2

样本代码内部机构:的在C++虚拟继承

class A { 
    public: 
    A(int) {} 
}; 

class B : public virtual A { 
    public: 
    B(int b) : A(b) {} 
}; 

class C : virtual public A { 
    public: 
    C(int c) : A(c) {} 
}; 

class D : public B, public C { 
    public: 
    D() : B(1), C(2){}; 
}; 

这是金刚石问题典型代码(溶液)。我知道为什么使用virtual关键字。但编译器处理这个问题的内部机制并不为我所知。现在我已经遇到了关于所述机制的两种不同理论,如下所述。

  1. 当一个类用virtual关键字继承时,编译器会在派生类中添加一个虚拟基指针。我已经检查过派生类的大小,并且它包含了一个额外指针的大小。但是我不知道它指向的是什么,当上面例子中的类D中的成员被引用时它是如何工作的。

  2. 对于每个构造函数,编译器会为程序员提供的每个定义创建两个版本。必须从this link 在上面的代码中。 编译器将产生2个版本C的构造的

    C(int){}   // Version1 
    
    C(int):A(int){} // Version2 
    

    和两个不同版本的构造B的

    B(int){}   // Version1 
    
    B(int):A(int){} // Version2 
    

    因此,当d被构造然后编译器将生成任一下面的代码的

    D() : B(), C(2) {} // Version1 
    
    D() : B(1), C() {} // Version2 
    

    为了确保只创建了A的一个实例,因此避免了A的副本。

请帮我理解内部机制。

+1

@Ron标记之前请先阅读实际文章 – George

+0

@ paper.plane这个问题可能对SO有点理论......虚拟继承的实际实现依赖于编译器......看看实际的标准是什么说:看看:http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2013/n3690.pdf在231页 – George

+1

@ Ron再次,我想你可能没有读过这个问题,只是Google搜索标题...op似乎并不想知道虚拟是做什么的(或虚拟基类是做什么的),而是产生所述类和继承类的内部对象模型的方式和原因 – George

回答

0

通常的用法(没有任何标准指定!)是先创建虚拟继承对象的实例并在vtables中放入一个指针。因此,这里是发生了什么:

  • 创作的答:没有什么特别的
  • 创建一个B的:甲A构造和它的链接B中虚函数表添加
  • 创建d组成: A是先构造的,然后是B和C,每个包含一个到他们vtable中的A的链接。这可以让你得到一个指向D对象的指针,将它转换为指向B和C的指针,并且每个指针仍然知道它的A成员在哪里。

但是,这只不过是什么可能的实施的理论答案。我并不是说实际的实现(比如说gcc,clang或者microsoft vc)就是这样的。但是,如果您必须以纯C语言模拟虚拟继承,则可以使用它。

+0

它是否创建虚拟继承?正如我的问题所述,我同意它会添加一个虚拟基指针。但是这与虚拟指针不同吗? 因为在上面的例子中B类的大小是N(指针的大小)。但是如果在类B中添加了一个虚函数,那么它的大小将变成2N(我已经检查过了)因为编译器会另外添加v-pointer和v-table。我的问题是单独虚拟继承,编译器会添加v-table吗? –

+0

@ paper.plane:可能。正如我所说,这只是一个可能的实现。如果你想知道具体的实现,你应该确切地说明你的目标是什么编译器(以及版本和构建选项)。 –

+1

一个虚拟表是静态的。它永远不会改变,并且不能包含指向动态对象的指针! – curiousguy