猿问

虚拟继承如何解决“钻石”(多重继承)歧义?

虚拟继承如何解决“钻石”(多重继承)歧义?

class A                     { public: void eat(){ cout<<"A";} }; 

class B: virtual public A   { public: void eat(){ cout<<"B";} }; 

class C: virtual public A   { public: void eat(){ cout<<"C";} }; 

class D: public         B,C { public: void eat(){ cout<<"D";} }; 


int main(){ 

    A *a = new D(); 

    a->eat(); 

我理解钻石问题,上面的代码没有那个问题。


虚拟继承究竟是如何解决问题的?


我的理解: 当我说A *a = new D();,编译器想要知道类型的对象是否D可以分配给类型的指针A,但它有两个可以遵循的路径,但不能自己决定。


那么,虚拟继承如何解决问题(帮助编译器做出决定)?


慕姐8265434
浏览 489回答 3
3回答

互换的青春

派生类的实例“包含”基类的实例,因此它们在内存中看起来像这样:class&nbsp;A:&nbsp;[A&nbsp;fields]class&nbsp;B:&nbsp;[A&nbsp;fields&nbsp;|&nbsp;B&nbsp;fields]class&nbsp;C:&nbsp;[A&nbsp;fields&nbsp;|&nbsp;C&nbsp;fields]因此,如果没有虚拟继承,D类的实例将如下所示:class&nbsp;D:&nbsp;[A&nbsp;fields&nbsp;|&nbsp;B&nbsp;fields&nbsp;|&nbsp;A&nbsp;fields&nbsp;|&nbsp;C&nbsp;fields&nbsp;|&nbsp;D&nbsp;fields] &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;'-&nbsp;derived&nbsp;from&nbsp;B&nbsp;-'&nbsp;'-&nbsp;derived&nbsp;from&nbsp;C&nbsp;-'因此,请注意A数据的两个“副本”。虚拟继承意味着内部派生类在运行时设置了一个vtable指针,指向基类的数据,因此B,C和D类的实例如下所示:class&nbsp;B:&nbsp;[A&nbsp;fields&nbsp;|&nbsp;B&nbsp;fields] &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;^----------&nbsp;pointer&nbsp;to&nbsp;Aclass&nbsp;C:&nbsp;[A&nbsp;fields&nbsp;|&nbsp;C&nbsp;fields] &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;^----------&nbsp;pointer&nbsp;to&nbsp;Aclass&nbsp;D:&nbsp;[A&nbsp;fields&nbsp;|&nbsp;B&nbsp;fields&nbsp;|&nbsp;C&nbsp;fields&nbsp;|&nbsp;D&nbsp;fields] &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;^----------&nbsp;pointer&nbsp;to&nbsp;B::A&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;^---------------------&nbsp;pointer&nbsp;to&nbsp;C::A
随时随地看视频慕课网APP
我要回答