我知道菱形继承会导致歧义,可以通过 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 类如何与这两个 vptr 一起工作,关于它使用的机制的任何想法?
类的大小作为编译器的实现细节而没有被标准定义(因为虚拟机制本身是编译器的实现细节)?

最佳答案

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

对于子项,它使用与多态使用的父项 1/2 对应的 vtable。

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

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

10-06 15:07