C++ sizeof之虚继承

本文探讨了C++中的数据对齐原则及其对内存布局的影响,并详细解析了包含虚函数的类如何影响类的大小,包括非虚继承与虚继承的不同表现。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

C++数据对齐有着重大意义,一般以机器字长为对齐准则,如32位机中的4,如果结构(如类或者结构体)中有超出字长长度的成员,则已此成员长度(一般为字长整数倍)为对齐长度。

此外,也有显式指定的对齐方式,指定方法为#pragma pack(n),此处指定对齐长度为n

#include<iostream>
using namespace std;
  
class A1
{
public:
int a;
char c;
};
  
class A2
{
public:
char a;
private:
double b;
int c;
float d;
};
  
int main()
{
cout<<"size A1: "<<sizeof(A1)<<endl;
cout<<"size A2: "<<sizeof(A2)<<endl;
}


输出结果为

size A1:8

size A2:24

第一个类的对齐字长为4,第二个类的对齐字长为最长原子类型长度(double,8)


关于有着虚函数的类的长度,就比较复杂,一般虚函数会需要一个虚指针,用以指向此类中所有虚函数组成的虚函数表的起始地址,具体可以参考http://blog.youkuaiyun.com/haoel/article/details/1948051/,源代码及运行结果如下:

#include<iostream>
#include<memory.h>
#include<assert.h>
  
using namespace std;
  
class A
{
char k[3];
public:
virtual void aa(){};
};
  
class B:public A
{
char j[3];
public:
virtual void bb(){};
};
  
class C
{
char f[3];
public:
virtual void cc(){};
};
  
class D:public B,public C
{
char g[3];
public:
virtual void dd(){};
};
  
int main()
{
cout<<"A size:"<<sizeof(A)<<endl;
cout<<"B size:"<<sizeof(B)<<endl;
cout<<"D size:"<<sizeof(D)<<endl;
}


A size:8 
B size:12 
D size:24

类A有一个虚指针用于指向虚函数表,所以长度为8,类B非虚拟继承了类A,所以其虚指针指向的虚函数表的第一个函数为类A的函数,第二个函数才是类B自身的虚函数,共用一张虚函数表;类D同时非虚继承了类B和类C,那么,类D的第一个虚指针指向类B的虚函数表,并将自身的虚函数地址附加到此表末尾,此外,类D还继承了类C,需要另开一张表,新添一个虚指针,故此长度为24.


刚才说的是非虚继承,如果是虚继承,情况又有所不同,此时派生类虚函数与第一基类的虚函数不再共用一张虚函数表,长度需要增加一个字长的长度:

#include<iostream>
#include<memory.h>
#include<assert.h>
  
using namespace std;
  
class A
{
char k[3];
public:
virtual void aa(){};
};
  
class B:public virtual A
{
char j[3];
public:
virtual void bb(){};
};
  
class C
{
char f[3];
public:
virtual void cc(){};
};
  
class D:public virtual B,public virtual C
{
char g[3];
public:
virtual void dd(){};
};
  
class E:public virtual C,public A
{
char t[3];
public:
virtual void ee(){};
};
  
int main()
{
cout<<"A size:"<<sizeof(A)<<endl;
cout<<"B size:"<<sizeof(B)<<endl;
cout<<"D size:"<<sizeof(D)<<endl;
cout<<"E size:"<<sizeof(E)<<endl;
}

​A size:8 
B size:16 
D size:32 
E size:20

我们看到,只要是虚继承,其派生类的虚函数就不会与基类的虚函数共用一张表(自身需要一个虚指针指向本身虚函数表),故此长度会有所增加(class D),而只要有非虚继承,派生类虚函数总会与第一个非虚继承基类虚函数共用一张虚函数表(class E)。


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值