深度探索C++对象模型--之对象的差异加上多态之后

class zooAnimal{
public:
	zooAnimal();
	virtual ~zoonAnimal();
	virtual void rotate(); 
protected:
	int loc;
	string name;
};
class Bear :public zooAnimal{
public :
	Bear();
	~Bear();
	void rotate(); 
	void dance();
protected:
	enum Dances{};
	Dances dance_know;
};

zooAnimal za("zoey");
zooAnimal *pza = &za;
Bear  b("yogi");
Bear *pb = &b;
Bear &rb = *pb;

基类zooAnimal的对象布局如下,假设指针pza的地址为1000;

                                基类对象za的内存布局

加上多态之后派生类Bear的内存布局如下(假设指针地址为1000):

                                  子类Bear的内存分配
一个Bear指针和一个zooAnimal指针有何不同之处?

Bear b;
zooAnimal *pz = &b;
Bear *pb =&b;

以上两指针pz pb都指向Bear的对象的第一个byte,期间的差异是,pb所覆盖的地址包含整个Bear object, 而pz所覆盖的地址只包含Bear object 中的zooAnimal subobject.
除了zooAnimal subobject中出现的member你不能够用pz来直接处理Bear的任何member,唯一是通过vritual机制。
当我们写pz->rotate();时,pz的类型将在编译时期决定以下几点:
1、固定的可用接口,pz只能调用zooAnimal 的public接口。
2、该接口是zooAnimal的公共接口。
在每一个执行点,pz所指的object类可以决定rotate()所调用的实体。类型信息的封装不是维护于pz中,而是维护于link之中,此link存在于object的vptr和vptr所指的virtual table之间。

如下这种

Bear b;
zooAnimal za = b;//这会引起切割(sliced)
//调用zooAnimal::rotate()
za.rotate();

1、为什么za调用的是zooAnimal实体而不是Bear实体呢?
za并不是(而且也绝不会是)一个Bear,它是一个zooAnimal,多态所造成的 “一个以上的类型” 的潜在力量,并不能够实际发挥在 “直接存取 objects” 这件事上。有一个似是而非观念:OO程序设计并不支持对object的直接处理。一个point 或一个reference之所以支持多态是因为它们并不引发内存中的任何委托操作,会受到改变的只是它们所指向的内存的”大小和内容解释方式“而已。
然而任何试图改变object za的大小,便会违反其定义中受契约保护的”资源需求量“。如果把整个Bear object指给za,则会溢出它所配置得到的内存。
当一个base class object 被直接初始化为一个derived class object时,derived object就会被切割(sliced),多态于是不再呈现。总而言之,多态是一种威力强大的设计机制,允许你继承一个抽象的public接口之后,封装相关的类型。C++通过class 的pointer和reference来支持多态,这种程序风格叫做 ”面向对象“。

2、如果初始化函数将一个object内容拷贝到另一个object中去,为什么za的vptr不指向Bear的vritual table?
编译器在初始化及指定操作之间做了仲裁,编译器必须确保某个object含有一个或一个以上的vptrs的内容不会被base class object初始化所改变。

猜你喜欢

转载自blog.csdn.net/cindywry/article/details/84673978