4

我知道菱形继承会导致歧义,可以通过使用继承来避免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

类似的是案例Derived1Derived2课程。

这是我与上述场景相关的问题:类对象
的大小如何Derived3,这是否意味着 Derived3 类有 2 个 vptr?
该类如何Derived3与这 2 个 vptr 一起工作,关于它使用的机制有什么想法吗?
类的大小保留为编译器的实现细节而不由标准定义(因为虚拟机制本身是编译器的实现细节)?

4

4 回答 4

4

是的,Derived3有两个 vtable 指针。如果您按值访问它,它会使用Derived3版本,或者从父级选择一个函数,或者表示如果它无法决定它是模棱两可的。

在孩子的情况下,它使用与正在多态使用的父 1/2 对应的 vtable。

请注意,您没有正确使用虚拟继承:我相信 Derived1 和 2 应该虚拟继承自Base. sizeof(Derived3)似乎仍然是 8,因为它仍然有两个可能的父母可以被视为Derived3. 当您投射到父母之一时,编译器实际上会调整对象指针以具有正确的 vtable。

另外我应该指出,任何与 vtable 相关的内容都是特定于实现的,因为标准中甚至没有提到 vtables。

于 2011-03-31T16:23:07.463 回答
3

对您的代码的一个小修复:虚拟应该在 derived2 和 derived 3 的定义中才能工作。

http://www.parashift.com/c++-faq-lite/multiple-inheritance.html#faq-25.9

于 2011-03-31T16:24:27.210 回答
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 在 L 的 vtable 中的位置与 R:h 在 R 的 vtable 中的位置相同(比如在索引 0 处)。现在考虑给定以下代码会发生什么:

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

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

于 2011-03-31T17:09:32.717 回答
1

我想你想知道一些完全特定于实现的东西。你不应该假设任何关于类的大小。

编辑:虽然好奇是一种经过验证的品质;-)

于 2011-03-31T16:23:54.997 回答