C++对象的内存布局

简单对象

  • 非静态成员变量和虚函数是决定类大小的唯一两个因素
  • 非静态成员变量在类的内存里会有字节对齐
  • 如果对象中包含虚函数,会增加4个字节的空间,不论有多少个虚函数。
  • 静态成员变量,静态成员函数和非静态成员函数不会影响对象内存的大小。静态成员变量存储在内存的静态数据区。另外:非静态成员函数和程序普通函数的函数区别是,类的非静态成员函数函数有this指针,所以可以访问类的成员。静态成员函数不可以调用类的非静态成员,因为静态成员函数不含this指针。

class simpleClass
{
public:
    char c, d;
    double nValue;
    int i;
    static int nCount;

    simpleClass() {};
    virtual ~simpleClass() {};

    int getValue(void);
    virtual void foo(void) {};
    static void addCount() {};
};

int  main()
{
    std::cout << "sizeof(simpleClass):" << sizeof(simpleClass) << std::endl;
    std::cout << "offsetof(simpleClass, c):"  << offsetof(simpleClass, c) << std::endl;
    std::cout << "offsetof(simpleClass, d):" << offsetof(simpleClass, d) << std::endl;
    std::cout << "offsetof(simpleClass, nValue):" << offsetof(simpleClass, nValue) << std::endl;
    std::cout << "offsetof(simpleClass, i):" << offsetof(simpleClass, i) << std::endl;
    std::cin.get();
}

输出:
sizeof(simpleClass):32
offsetof(simpleClass, c):8
offsetof(simpleClass, d):9
offsetof(simpleClass, nValue):16
offsetof(simpleClass, i):24

因为double是8个字节,所以按照8字节对齐,虚函数表占8字节,两个char一起占8字节,int占8字节,总大小是32。

单继承

class simpleClass
{
public:
	static int nCount;
	int nValue;
	char c;
 
	simpleClass(){};
	virtual ~simpleClass(){};
 
	int getValue(void);
	virtual void foo(void){};
	static void addCount(){};
};
class derivedClass:public simpleClass
{
public:
	int nSubValue;
	derivedClass(){};
	~derivedClass(){};
	virtual void foo(void){};
};

在构造一个派生类的实例时首先够着一个基类的实例,而这个基类的实例在派生类的实例销毁之后销毁。derivedClass的大小是16字节,基类simpleClass的大小是12字节。派生类增加了一个整型变量nSubValue,在内存布局中放在基类的后面。而且派生类在构造时不会再创建一个新的虚函数表,而是在基类的虚函数表中增加或者修改。
在这里插入图片描述

多继承

class simpleClass1
{
public:
	int nValue1;
	char c;
 
	simpleClass1(){};
	virtual ~simpleClass1(){};
 
	int getValue(void);
	virtual void foo1(void){};
};
class simpleClass2
{
public:
	int nValue2;
 
	simpleClass2(){};
	virtual ~simpleClass2(){};
 
	int getValue(void);
	virtual void foo2(void){};
};
class derivedClass:public simpleClass1,public simpleClass2
{
public:
	int nSubValue;
	derivedClass(){};
	~derivedClass(){};
	virtual void foo2(void){};
};
  • 与单继承相同,创建派生类的对象时,要首先创建基类的对象。由于多继承中一个派生类有多个基类,因此创建基类的对象要遵循派生类声明的顺序。
  • simpleClass1对象的大小是12字节,simpleClass2对象的大小是8字节。而派生类增加了4个字节的整型成员数据,大小是24字节。
  • 在多继承中药注意避免二义性。如上面的例子两个基类都定义了getValue()函数。如果一个派生类的实例调用getValue函数会报二义性错误。
  • 若simpleClass1和simpleClass2的内存对齐不一样,那么派生类继承他们以后,会重新统一内存对齐。* 比如若simpleClass1是按4字节对齐,simpleClass2是按8字节对齐。当derivedClass继承他们以后,simpleClass1也会按照8字节对齐。

菱形继承

考虑如下的菱形继承
在这里插入图片描述
如果不适用虚拟继承,内存布局将会如上面右图所示:会有两个baseClass实例。
在这里插入图片描述
如果使用虚拟继承,则内存布局如下
在这里插入图片描述
使用虚拟继承以后, baseClass只创建了一个实例,并且放在derivedClass实例的内存空间中的最后,每个使用虚拟继承的类都会增加一个虚基类表的指针(virtual base table)。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值