1

我遇到了 C++ 虚拟继承的问题。

我有一个类层次结构如下:

class Base
{
public:
    virtual void Func(){};
    int BaseValue;
};

class Derived : virtual public Base
{
public:
    void Func(){};
    virtual void Func2(){};
    int DerivedValue;
};

编译得很好,但是,我对内存结构有点困惑。

我希望得到 的结果sizeof(Derived)==20,即:

  1. BaseValue 和 DerivedValue--8 字节
  2. Pointer 表示 Base 类的成员偏移量 (虚拟继承的特性)- 4字节
  3. 指针表示Base类的虚函数表--4字节
  4. 指针表示Func2()只属于派生类的虚函数--4字节 (就我而言,没有非虚基类并获得其唯一虚函数的派生类应该有自己的虚表)

其中总计 20 个字节;

然而 Xcode 4.6 产生了不同的结果sizeof(Derived)==16,我弄错了吗?

4

1 回答 1

1

指针表示基类的虚函数表--4字节
指针表示仅属于派生类的虚函数Func2()--4字节(就我而言,派生类没有非虚基类并得到其独有的虚函数应该有自己的虚表)

啊,我现在看到了问题。这不是虚拟函数表的工作方式。Base定义时,编译器注意到它需要一个虚拟表,并为 生成一个虚拟表,Base其中有一个指向实现的指针 ( Func) Base::FuncDerived定义时,编译器会注意到它继承自,Base并为其生成一个函数表,Base该函数表有两个指针,Func指向Derived::FuncFunc2指向Derived::Func2

然后,如果Base创建了 的实例,则您提到的函数表指针指向Base表,并且对的任何调用Func都将重定向到Base::Func.

如果创建了 的实例,Derived则其内部Base对象的虚函数表指针将指向该Derived表。 Base只知道如何访问Func指针,但Func指针现在指向Derived::Func,所以这就是 get 的调用。它没有意识到它指向的是另一张桌子。在代码中,它可能看起来更像这样:

using voidFunctionType = void(*)();

struct BaseVTable {
    voidFunctionType Func;
}BaseVTableGlobal; 

struct Base {
    Base() :vTable(&BaseVTableGlobal) {}
    void Func() {vTable->Func();}

    BaseVTable* vTable; //4 bytes
    int BaseValue; //4 bytes
}; //total is 8 bytes

struct DerivedVTable : public BaseVTable  {
    voidFunctionType Func;
    voidFunctionType Func2;
}DerivedVTableGlobal; 

//inherits 8 bytes, +4 for virtual inheritance = 12
struct Derived : virtual public Base { 
    Derived() :Base() {vTable = &DerivedVTableGlobal;} //the shared vTable points at DerivedVTableGlobal
    void Func() {vTable->Func();} //base knows about Func, so this is easy
    void Func2() {((DerivedVTable*)vTable)->Func2();} //base doesn't know about Func2

    int DerivedValue; //4 bytes
}; //16 bytes total

所以 XCode 是对的。 Derived是“劫持”Base的虚函数表,事实上,这正是虚函数发挥作用的方式。

(到处都是假设,这些都没有明确定义,虚拟继承使事情复杂化,等等等等)

于 2013-08-22T19:51:18.037 回答