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关键字继承类时,编译器会在派生类中添加虚拟基指针。我检查了派生类的大小,是的,它包括一个额外指针的大小。但我不知道它指向何处以及如何在上面的例子中在D类中引用A类成员时它是如何工作的。
对于每个构造函数,编译器都会为程序员提供每个定义的两个版本。从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的副本。
请帮助我理解内部机制。
答案 0 :(得分:0)
常见用法(未由任何标准指定!)是首先创建虚拟继承对象的实例,并在vtable中放置指向该实例的指针。所以这是发生的事情:
但这只不过是一个可能是一个实现的理论答案。我不是说实际的实现(比如gcc,clang或microsoft vc)就是这样的。但是你可以使用它,例如,如果你必须用普通的C语言模仿虚拟继承。