我遇到了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
的结果,即:
Func2()
,它只属于Derived类 - 4个字节
(据我所知,没有非虚拟基类并获得其独特虚函数的派生类应该有自己的虚拟表) 总计最多20个字节;
然而Xcode 4.6产生了sizeof(Derived)==16
的不同结果,我弄错了吗?
答案 0 :(得分:1)
啊,我现在看到了问题。这不是完全虚函数表的工作原理。定义指针表示基类的虚函数表 - 4个字节
指针表示仅属于的虚函数Func2() class Derived - 4个字节(据我所知,派生类是哪个 没有非虚拟基类并获得其独特的虚函数 应该有自己的虚拟表)
Base
时,编译器会注意到它需要一个虚拟表,并为Base
生成一个虚拟表,其中一个指针(Func
)指向Base::Func
实现。定义Derived
时,编译器会通知它继承自Base
,并为Base
生成一个具有两个指针的函数表,Func
个点至Derived::Func
,Func2
指向Derived::Func2
。
然后,如果创建了Base
的实例,那么你在Base
表中提到点的函数表指针,对Func
的任何调用都将被重定向到{{1 }}。
如果创建了Base::Func
的实例,则它的内部Derived
对象的虚函数表指针将指向Base
表。 Derived
只知道如何访问Base
指针,但Func
指针现在指向Func
,这就是所谓的调用。它没有意识到它指向一个不同的表。在代码中,它可能看起来更像这样:
Derived::Func
所以XCode是对的。 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
是“劫持”Derived
的虚拟功能表,事实上,正好虚拟功能如何发挥其魔力。
(各地的假设,这些都没有明确定义,虚拟遗骸使事情变得复杂等等)