c++对象模型

使用c++有些年头了 , 有一本深度搜索c++对象模型的书写的很赞 , 很经典 。本文是本书的读书笔记 。
关于对象
加上封装后的布局成本
C语言中如下声明一个结构体
typedef struct point3d{ float x; float y; float z;}Point3d;struct point3d 转化为class Point3d之后
class Point3d{ public: Point3d(float x = 0.0f, float y = 0.0f; float z = 0.0f) :_x(x),_y(y),_z(z){} private: float _x,_y,_y;}封装带来的布局成本增加了多少?实际是没有增加布局成本的 。3个数据成员直接在class object内 , member function在classs声明却不出现在class object中 , 所谓布局的成本主要由virtual引起的 。
virtual function 机制用以支持运行时绑定(运行时多态)
virtual base class 机制支持多次出现在集成体系中的base class有一个单一的被共享的实例 。
基本c++对象模型
nostatic data members 被配置在class object之内 , static data member存放在class object之外.
static 和nostatic function memners放在class object之外
virtual function的处理步骤:

  1. 每个class产生出一堆指向virtual functions的指针 , 放在表格中 , 这个表格称为虚表virtual table
  2. 每个class object 安插一个虚表指针vptr指向虚表(virtual table).
  3. vptr的设定和重置都由每个class的构造函数、拷贝赋值运算符、析构函数自动完成 , 每个class所关联的type_info object (用以支持runtime type identification, RTTI)也经由virtual table被指出 , 通常放在virtual table的第一个slot.
声明一个class Point然后查看其对象模型
class Point{ public: Point(float x); virtual ~Point(); float x() const; static int PointCount(); protected: virtual ostream& print(ostream& os) const; float _x; static int _point_count;}
c++对象模型

文章插图
 
加上继承
c++支持单一继承和多重继承.base class subobject的data members直接被放置在derived class object,也就是说子类对象中包含基类子对象.基类成员的改变都会导致继承类重新编译.对于虚基类则是扩展子类自己的vittual table维护virtual base class的位置 。
class istream : virtual public IOS{...};class ostream : virtual public ios{...};class iostream : public istream, public ostream{...};在虚拟继承的情况下base class 不管在继承链中被派生多少次 , 永远只有一个实例存在即一个subobject.iostream之中只有virtual ios base class的一个实例.
NRV优化
函数返回基本是数据类型或者指针类型是通过eax寄存器进行传递的 , 返回对象对象则会进行命名返回值优化.以外部引用传参的形式去掉函数内部的局部对象构造 。
X foo(){ X xx X* px = new X(); xx.foo(); //func是一个虚函数 px->foo() delete px; rerurn xx}如上函数有可能内部转化为如下代码:
void foo(X &result){ _result.X::X(); px = _new(sizeof(X)); if(px != 0){ px->X::X(); } func(&_result);//这里涉及到成员函数的语义 (*px->vtbl[2])(px) //使用virtual机制扩展px->func() if(px != 0) { (*px->[1])(px); //扩展delete px _delete(p) } return; }
c++对象模型

文章插图
 
指针类型
  • 指针类型会指导编译器如何解释某个特定地址中内容及其大小
  • void*的指针只能够持有一个地址 , 而不能够通过他操作他所指向的object
  • cast是一种编译指令它不改变一个指针的内容 , 只影响被指出的大小和其内容的解释方式
  • c++通过引用或者指针的方式支持多态 , 是因为他们不会引发任何与类型有关的内存委托 , 
  • 当一个基类对象直接被初始化为一个子类对象是 , 子类对象会被切割以放入base type的内存中
构造函数语义学
默认构造函数被合成出来执行编译器的所需操作
如果类class A含有一个以上的类成员对象 , 编译器会扩张构造函数 , 在构造函数中安插代码 , 以成员类的声明顺序调用每个成员类的默认构造函数 , 这些代码被安插在用户代码之前.
有四种情况会造成编译器为未声明构造函数的类合成一个默认的构造函数 , 接着调用member object或者base class的默认构造函数 , 完成虚函数和虚基类机制 。
  1. 带有默认构造函数的成员类对象
  2. 带有默认构造函数的基类
  3. 带有virtual function的类 , 用来初始化vptr


    推荐阅读