深度探索c++对象模型1
- C++的主要额外负担:
- virtual function 机制
- virtual base class 用以实现“多次出现在继承体系中的base class,又一个单一而被共享的实例”
- 多重继承下的额外负担
1.1 C++对象模式
C++对象模型
- 非静态成员变量存放在每一个class object里面,静态成员变量存放在个别的class object 之外;静态函数,非静态函数成员放在个别的class object之外,虚函数特殊对待:
- 每一个class 产生出一堆指向virtual function 的指针,放在表格中,这个表格称之为虚函数表(virtual table)
- 每一个class object被安插一个指针,指向相关的virtual table。通常这个指针称为$vtpr$.$vtpr$的设定由每一个class的constructor,destructor和copy assignment运算符自动完成。每一个class所关联的$tyle_info$ object(用来支持runtime type identification)也经由虚函数表纸出来,通常放在表格的第一个slot里面。
例子如下
- 非静态成员变量存放在每一个class object里面,静态成员变量存放在个别的class object 之外;静态函数,非静态函数成员放在个别的class object之外,虚函数特殊对待:
C++继承
- 使用所谓的base table 模型。每一个class object内涵一个bptr,被初始化,指向它的base class table,然后这个表就如同虚函数表一样指向继承的类的对象,如下图
什么时候一个人应该使用struct 取代class?当它让一个人感觉比较好的时候(狗头)
聚合(composition)而非继承才是把C++和C结合起来的好方法。
struct在C++中的一个合理用途,是当你要传递一个“复杂的class object的全部或者部分”到某一个C函数去的时候,struct声明可以将数据封装起来,并且保证拥有与C兼容的空间布局,然而这种保证只在聚合(composition)的情况下存在。如果是继承的话,可能会因为内存布局原因无法实现想要的结果。C++以下列方法支持多态:
- 经过一组隐式的转化操作,比如把一个派生类的指针转化为一个指向它的public base type的指针:
shape *ps=new circle (); - 经由virtual function机制:
ps->rotate() - 经由$dynamic_cast$和typeid运算符:
$if(circle pc=dynami_cast < circle>(ps))$
- 经过一组隐式的转化操作,比如把一个派生类的指针转化为一个指向它的public base type的指针:
需要多少内存才能够表现一个class object:
- 非静态成员变量的总和大小
- 加上任何由于alignment(对齐)的需求而填补(padding)上去的空间
- 加上为了支持virtual而内部产生的任何额外负担
关于指针:
不同类型的指针从内存需求的观点来看没有什么不同,“指向不同类型之各指针‘间的差异,既不在其指针表示法的不同,也不再其内容的不同,而是在其所寻址出来的object类型不同。也就是说,“指针类型”会教导编译器如何解释某一个特定地址的内存内容及其大小。最后一部分内容讨论了多态发生的条件,我认为总结下来就是引用和指针可能触发多态,通过虚函数来实现。然后将子对象赋值给父类对象一般会导致切割,来放置数据溢出。
具体问题:
一个Bear指针和一个ZooAnimal指针有什么不同:
1
2
3Bear b;
ZooAnimal *pz=&b;
Bear *pb=&;它们每一个都指向Bear object 的第一个type,它们的区别是:pb所涵盖的地址包含整个 Bear object但是pz所涵盖的地址之包含Bear object中的ZooAnimal subobject.
内存布局如下图: