我使用钻石继承在C ++中编写了一个代码,而没有使用关键字'virtual'作为最顶层的A类,同时定义继承A的B和C类。然后我定义了继承自B和C的类D.类D不使用类A成员x,编译不会抛出任何错误。但如果确实如此(通过取消注释函数foo()),编译器会抛出提及歧义的错误。
#include<iostream>
#include<cstdlib>
using namespace std;
class A
{
protected:
int x;
public:
void set(int y){x=y;}
};
class B:public A
{
};
class C:public A
{
};
class D:public B,public C
{
public:
// void foo(){x*=2;} // error!
};
int main()
{
cout<<sizeof(D)<<endl;
return(0);
}
在定义C和D类时,使用'virtual'限定符允许使用foo()函数,如下面C类所示。
class C:virtual public A
{
};
现在foo()中使用的x没有任何歧义,因为它只有一个副本。我的问题是这样的:
a)在第一种情况下,编译器实际上是否允许2份x副本,因为它没有解决任何歧义?
b)如果对(a)的答案是肯定的,那么为什么第一个代码输出8代表D类的大小而第二个代码输出24呢?由于第一种情况有x的两个副本,它的大小不应该至少与第二种情况一样多(即使我们忽略填充)?
答案 0 :(得分:3)
a)是的。它实际上是重复的。为了明确,D包含成员B :: x和C :: x。
如果你修改foo()是显式的,它可以工作。例如:
void foo() { B::x *= 2; }
b)在虚拟继承的情况下占用额外内存的原因是需要虚拟表或vtable。
您可以在此处找到一个很好的解释:http://www.cprogramming.com/tutorial/virtual_inheritance.html