c++类内存布局的一些理解(1)

多重继承与虚函数解析
本文通过一个C++代码示例详细介绍了多重继承下不同基类指针指向同一派生类对象时的行为差异,以及虚函数机制如何确保正确调用派生类的方法。解释了为何需要使用dynamic_cast进行类型安全的转换。

先看这段代码

//代码来自陈皓的博客http://blog.youkuaiyun.com/haoel/article/details/3081328
class Base1 {

public:
	int ibase1;
	Base1():ibase1(10) {}
	virtual void f() { cout << "Base1::f()" << endl; }
	virtual void g() { cout << "Base1::g()" << endl; }
	virtual void h() { cout << "Base1::h()" << endl; }
};

class Base2 {
public:
	int ibase2;
	Base2():ibase2(20) {}
	virtual void f() { cout << "Base2::f()" << endl; }
	virtual void g() { cout << "Base2::g()" << endl; }
	virtual void h() { cout << "Base2::h()" << endl; }
};

class Base3 {
public:
	int ibase3;
	Base3():ibase3(30) {}
	virtual void f() { cout << "Base3::f()" << endl; }
	virtual void g() { cout << "Base3::g()" << endl; }
	virtual void h() { cout << "Base3::h()" << endl; }
};

class Derive : public Base1, public Base2, public Base3 {
public:
	int iderive;
	Derive():iderive(100) {}
	virtual void f() { cout << "Derive::f()" << endl; }
	virtual void g1() { cout << "Derive::g1()" << endl; }
};

如果执行代码

	Derive d;

	Base1* b1_ptr = &d;
	Base2* b2_ptr = &d;
	Base3* b3_ptr = &d;

	cout << b1_ptr << endl << b2_ptr << endl << b3_ptr << endl;

会得到结果

0012FF48
0012FF50
0012FF58

也就是说,虽然三个指针指向同一个对象,但是它们的值确实不同的!!!

这是因为,Base2的指针,不管指向Base2的对象还是子类Derive的对象,任何对这个指针的操作,都是按照Base2类的定义的内存布局来处理的。很明显,在一个Derive对象中Base2的内存布局在保存在Base1内存布局之后,并且有8字节的偏移(虚函数表和变量ibase1)。所以,编译做了一个隐式的转换(我恨这些编译器偷偷干的事),将各个指针指向它自己实际的内存布局。

为了符合这个要求,编译器在背后做了许多事情。例如上面这个例子,还有为什么dynamic_cast是必需的。下面解释dynamic_cast的原因:

对转换 Derive* d_ptr = dynamic_cast<Derive*>(b2_ptr) 来说,首先我们想象一下d_ptr的和b2_ptr的值应该是什么,b2_ptr的值已经有了,是0012FF50,而d_ptr的值则应该是0012FF48(因为Base1类的内存布局在Derive类的内存布局的顶端)。很明显,d_ptr和b2_ptr是有偏移量的,至于偏移量有多少,依赖于编译器的实现,只有编译器知道。因此Derive* d_ptr = b2_ptr是个严重的错误(虽然直观的讲b2_ptr确实指向一个Derive类实例)。

同样为了符合这个要求,虚函数的设计十分复杂。

个人认为,虚函数之所以这么设计的原因(这个得看陈皓的博客),就是要满足任意一个指针,不管指向什么,都要按照由它类定义所定义的内存布局来解释内存,从这个角度理解虚函数问题应该有点新意,有空再写

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值