为什么虚拟继承2类会增加对象大小?

时间:2019-05-25 11:39:12

标签: c++ object inheritance model virtual

我有一个简单的对象,可以使用g ++在64位ubuntu1804下编译并运行:

struct Base1{ int mi,mj,mk,mh;};
struct Base2{ int ni,nj,nk,nh;};

struct Child1:virtual Base1{virtual void f(){}};
struct Child2:virtual Base1{virtual void f(){}};
struct Derive1:Child1,Child2{};

struct Child3:virtual Base2{virtual void f(){}};
struct Child4:virtual Base2{virtual void f(){}};
struct Derive2:Child3,Child4{};

struct Final:Derive1,Derive2{};
int main(){
        cout<<"C1="<<sizeof(Child1)<<endl;
        cout<<"C2="<<sizeof(Child2)<<endl;
        cout<<"C3="<<sizeof(Child3)<<endl;
        cout<<"C4="<<sizeof(Child4)<<endl;
        cout<<"D1="<<sizeof(Derive1)<<endl;
        cout<<"D2="<<sizeof(Derive2)<<endl;
        cout<<"F ="<<sizeof(Final)<<endl;
        return 0;
}

程序输出:

$ g++ om.cpp -O2 && ./a.out
C1=24
C2=24
C3=24
C4=24
D1=32
D2=32
F =64

我知道sizeof(B1)是16,Child1-Child4作为添加虚拟函数(指向vtable的vptr)将增加一个额外的指针大小,因此它们的大小为24,没问题。但是为什么Derive1 / Derive2的size为32? C ++对象模型向它添加了一个额外的指针,对吗?但是,这个额外的指针实际上是做什么的?为什么有必要添加这个额外的8byte指针?我觉得这里没有必要。

非常感谢。

1 个答案:

答案 0 :(得分:1)

合理的布局:

Final
----------------------
| Derive1
| --------------------
| | Child1
| | ------------------
| | | Pointer to Base1 (8 bytes)
| | ------------------
| | Child2
| | ------------------
| | | Pointer to Base1 (8 bytes)
| | ------------------
| --------------------
| Derive2
| --------------------
| | Child3
| | ------------------
| | | Pointer to Base2 (8 bytes)
| | ------------------
| | Child4
| | ------------------
| | | Pointer to Base2 (8 bytes)
| | ------------------
| --------------------
| Base1
| --------------------
| | mi                 (4 bytes)
| | mj                 (4 bytes)
| | mk                 (4 bytes)
| | mh                 (4 bytes)
| --------------------
| Base2
| --------------------
| | ni                 (4 bytes)
| | nj                 (4 bytes)
| | nk                 (4 bytes)
| | nh                 (4 bytes)
| --------------------
----------------------

总大小:8 + 8 + 8 + 8 + 4 + 4 + 4 + 4 + 4 + 4 + 4 + 4 = 64
请注意,如果您的虚函数不那么琐碎和/或实际上覆盖了某些东西,则此大小可能会增加以容纳vtable指针。 (就目前而言,可以完全优化虚拟功能。)

要了解为什么所有这些指针都是必需的,请考虑以下几点:

Final foo;
Child3 * c3 = &foo;
Child4 * c4 = &foo;
Base2 * b23 = c3;
Base2 * b24 = c4;

如果给您c4,您将如何将其转换为指向Base2的指针?请记住,不允许您假设c4指向Final的一部分;您的解决方案还必须适用于以下情况,并且必须同样适用于c3

Child4 c4;
Base2 * b24 = &c4;