c++探险--多态类的内存分布

多态类在编译期间会生成虚函数表存放在只读存储区,虚函数表类似于虚函数的数组,函数的代码存储在代码区。在运行时,多态类的对象在内存开始位置存放着虚表指针,对象访问虚函数时,通过虚表指针找到虚表进而找到虚函数地址。
多态类在继承时,子类对象会将父类的徐标志镇和所有变量都保存到自己的内存里(即使父类private变量的内存也会继承下来,只会无法访问到),也就是子类对象内存中存储着一个父类对象。如果使菱形继承,那么"菱形"底部的类就会存储两份"菱形"顶端的类对象内存,通过虚继承可优化成一份,暂且不表。
接下来,我们通过代码验证多态类的内存分布,以及分析多态类对象的大小。

#include <iostream>
class Base {
public:
	virtual void f() { std::cout << "Base::f\n"; }
private:
	int v;
};

class Derive : public Base {
public:
	virtual void f() { std::cout << "Derive::f\n"; }
	virtual void foo() { std::cout << "Derive::foo\n"; }
	char ch;
	int v1;
};

typedef void(*Fn)();
// 64 bit system
int main() {
	std::cout << sizeof(Base) << ", " << sizeof(Derive) << std::endl;	// 16, 24
	
	Base* b = new Derive;
	// 为了对对象成员赋值
	Derive* real = dynamic_cast<Derive>(ch);
	real->ch= 1;
	real->v1 = 13;
	// 虚函数地址访问
	Fn f = (Fn)(*(int64_t*)(*(int64_t*)b));		// 第一次*(int64_t*)b 取得虚表指针的值,也就是虚函数数组的首地址,第二次是取得第一个虚函数地址
	Fn f1 = (Fn)(*((int64_t*)(*(int64_t*)b) + 1));		// 第一次*(int64_t*)b 取得虚表指针的值,也就是虚函数数组的首地址,第二次是取得第2个虚函数地址
	f();
	f1();
	std::cout << "b->ch:" << *(char*)((int8_t*)b + 12) << "\n";
	std::cout << "b->v1:" << *(int*)((int8_t*)b + 16) << "\n";
/**
	Derive::f
	Derive::foo
	b->ch:			//美打出来是因为类型是字符,按照字符转玛了
	b->v1:13
**/
	return 0;
}

子类对象内存中一次存放了:虚表指针-父类成员变量-子类成员变量
首先计算下大小:64为系统中指针占8B,于是按字节对其 sizeof(Base) =8 + 4 = 12, 最后对最大的成员类型取整,16;
sizoef(Dervice)=8(子类指针) + 4 + 1 + (3+4) (int v1需要对齐)=20, 最后对指针类型取整,24;

上面按地址打印验证的多态类对象内存分布。

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值