据我所知,Diamond形状的继承会导致歧义,可以通过virtual Base Classes
使用继承来避免这种情况,问题不在于此。当类是多态的时,问题是关于菱形层次结构中派生类最多的类的大小。以下是示例代码和示例输出:
#include<iostream>
using namespace std;
class Base
{
public:
virtual void doSomething(){}
};
class Derived1:public virtual Base
{
public:
virtual void doSomething(){}
};
class Derived2:public virtual Base
{
public:
virtual void doSomething(){}
};
class Derived3:public Derived1,public Derived2
{
public:
virtual void doSomething(){}
};
int main()
{
Base obj;
Derived1 objDerived1;
Derived2 objDerived2;
Derived3 objDerived3;
cout<<"\n Size of Base: "<<sizeof(obj);
cout<<"\n Size of Derived1: "<<sizeof(objDerived1);
cout<<"\n Size of Derived2: "<<sizeof(objDerived2);
cout<<"\n Size of Derived3: "<<sizeof(objDerived3);
return 0;
}
我得到的输出是:
Size of Base: 4
Size of Derived1: 4
Size of Derived2: 4
Size of Derived3: 8
据我所知,Base
包含一个虚拟成员函数,因此,
sizeof Base =此环境中vptr = 4的大小
情况类似Derived1
&amp; Derived2
课程。
以下是与上述情况有关的问题:
Derived3
类对象的大小如何,这是否意味着Derived3类有2个vptr?
Derived3
类如何使用这两个vptr,有关它使用的机制的任何想法?
sizeof类保留为编译器和实现的实现细节。标准没有定义(因为虚拟机制本身就是编译器的实现细节)?
答案 0 :(得分:4)
是的,Derived3
有两个vtable指针。如果您按值访问它,它会使用Derived3
版本,或从父项中选择一个函数,或者表示如果它无法决定它是不明确的。
对于孩子,它使用对应于多态地使用的父1/2的vtable。
请注意,您没有正确使用虚拟继承:我相信Derived1和2应该从Base
虚拟继承。 sizeof(Derived3)
似乎仍然是8,因为它仍然有两个可能被视为Derived3
的父母。当你转换为其中一个父项时,编译器实际上会调整对象指针以获得正确的vtable。
另外我应该指出,与vtable相关的任何内容都是特定于实现的,因为标准中甚至没有提到vtable。
答案 1 :(得分:3)
对您的代码的一个小修复:虚拟应该在derived2和derived3的定义中,以便工作。
http://www.parashift.com/c++-faq-lite/multiple-inheritance.html#faq-25.9
答案 2 :(得分:1)
我认为你想知道完全特定于实现的东西。 你不应该假设任何关于类的大小。
编辑:虽然好奇是一种经过验证的品质; - )
答案 3 :(得分:1)
考虑一个稍微不同的情况:
struct B { virtual void f(); };
struct L : virtual B { virtual void g(); };
struct R : virtual B { virtual void h(); };
struct D : L, R {};
在一个典型的实现中,L :: g将处于相同的位置(比如说 索引0)在L's vtable中作为R:h在R的vtable中。现在考虑会发生什么 给出以下代码:
D* pd = new D;
L* pl = pd;
R* pr = pd;
pl->g();
pr->h();
在最后两行中,编译器将生成代码以查找 vtable中相同位置的函数地址。所以 通过pl访问的vtable不能与一个(或前缀)相同 一个)通过公关访问。因此,至少需要完整的对象 两个vptr,指向两个不同的vtable。