4

据我所知,菱形继承产生歧义,它可以通过virtual Base Classes使用继承回避的是,问题不是它。当类是多态时,问题是关于菱形层次结构中派生最多的类的大小。下面是一个示例代码和输出样本:菱形多态继承:大多数的sizeof派生类

#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; 
} 

输出I得到的是:

Size of Base: 4 
Size of Derived1: 4 
Size of Derived2: 4 
Size of Derived3: 8 

据我所知Base包含虚拟成员函数,因此,
的sizeof基地= vptr的的尺寸= 4在这种环境下

类似的情况Derived1 & Derived2类。

这里是我的问题涉及到上述方案:
怎么样Derived3类对象的大小,这是否意味着Derived3类有2 vptr的?
Derived3类如何与这2个vptr一起工作,有关它使用的机制的任何想法?
Sizeof类的大小保留为未由标准定义的编译器&的实现细节(因为虚拟机制本身是编译器的实现细节)?

+1

关于标准问题。是的,如何实现虚拟方法的机制是实现细节,而不是指定的。是的,sizeof'的实际结果也是一个实现细节,它主要取决于指针大小,如果你在64位平台上,你会看到'8/8/8/16'。 – 2011-03-31 18:12:38

回答

4

是,Derived3有两个虚表指针。如果您按价值访问它,它会使用Derived3版本,或者从父项中选取一个函数,或者表示如果它无法确定,则它是不明确的。

在儿童的情况下,它使用对应于该被真实多态中使用的父1/2 V表。你没有使用虚拟继承

注意正确:我相信Derived1和2应从Base几乎继承。 sizeof(Derived3)仍然似乎是8,因为它仍然有两个可能的父母,可以被视为Derived3。当你转换到其中一个父代时,编译器会实际调整对象指针以获得正确的vtable。

此外,我应该指出,任何虚函数表相关的具体实施,因为竟然没有标准虚函数表的任何提及。

+0

谢谢,我纠正了Derived1&Derived2几乎从Base继承的错误。 O/P仍然是一样的。 – 2011-03-31 16:32:42

1

我想你想知道的东西完全是实现特定的。 你不应该假设类的大小。

编辑:虽是好奇的是一个公认的质量;-)

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 ::克将在相同的位置中(在 索引0表示)L的虚函数表为R: h在R的vtable中。现在考虑 给出下面的代码会发生什么:

D* pd = new D; 
L* pl = pd; 
R* pr = pd; 
pl->g(); 
pr->h(); 

在最后两行,编译器将生成的代码在虚函数表的相同位置找到该功能的 地址。因此,通过pl访问的 vtable不能与通过pr访问的那个(或其中的前缀 )相同。因此,完整的对象至少需要两个vptr,以指向两个不同的vtable。

+0

实际上在典型的实现中'f'可能会在虚拟表中的'g'或'h'之前,所以当使用'L'或'R'多态作为'B时不需要调整'(即'L'表格的布局将是'B'表格布局的超集,所以它的'B'视图符合'B'尝试)。 – 2011-03-31 18:11:12

+0

@Matthieu M.是的。在很多实现中,vtable将以一个或多个特殊指针开始,例如type_info信息,接着是基类中的虚函数,然后是该类的虚函数,这些函数不是覆盖一个基地。但是,事实仍然是,L的vtable与g的vtable有相同的地方,所以同样的vtable不能用于D. – 2011-04-01 07:51:04

+0

中的L和R。在很多实现中都是这样。构建更智能的vtables需要全面的程序分析/链接时间优化。 – 2011-04-01 12:23:30