《深度探索C++对象模型》--5构造、析构、拷贝语意学
1、纯虚函数:
(1)C++可以定义和调用一个纯虚函数,不过只可以静态调用,不可以由虚拟机制调用。
注意:pure virtual destructor一定得定义,因为每一个derivedclass destructor会被编译器加以扩张,以静态方式调用其每一个virtual base class及上一个base class的destructor,如果缺乏任何一个base class destructor的定义就会导致链接失败。
综上,不要把virtual destructor声明为pure。
(2)如果一个函数定义内容并不与类型有关,几乎不会被后续的derived class改写,则没有必要声明为virtual。
(3)virtual函数最好不要加const。
2、“无继承”情况下的对象构造
(1)Plain OL' Data具有trivialcopy等操作,编译器实际上不会产生。
(2)explicit initialization list的缺点:
只有当class members都是public,才有效;只能指定常量,因为在编译期间就可以被评估求值;由于编译器没有自动实施,初始化行为的失败率要高一些。
(3)如果许多函数需要以传值方式传回一个local class object,则提供一个copy constructor合理,触发NRV优化。
3、继承体系下的对象构造
constructor的执行算法:
在derived class constructor中,所有virtual baseclasses以及上层base class的constructors都会被调用;
上述完成后,对象的vptr被初始化,指向相关的virtual table;
如果有member initialization list的话,将在constructor体内扩展开来。这必须在vptr被设定之后才做,以免有一个virtual member function被调用;
最后执行体内所提供的代码。
4、对象复制语意学
(1)只有在默认行为不安全或者不正确时,才设计一个copy assignmentoperator。可能自己提供一个,来打开NRV优化。
(2)尽可能地不要允许一个virtualbase class的拷贝操作。建议不要在任何virtual base class中声明数据。
5、析构语意学
析构过程与constructor顺序相反。
《深度探索C++对象模型》--6执行期语意学
C++的困难之一,就是不容易从代码看出来表达式的复杂,一个类似if(yy == xx.getValue())的简单式子,有可能经历操作符重载,转换运算符-》if(yy.operator == ( xx.getValue.operator Y() ));这些都由编译器暗中进行。
1、对象的构造和析构
(1)把object尽可能放置在使用它的那个程序区段附近,以节省不必要的产生对象和销毁操作。
(2)C++程序中所有的globalobject都被放置在程序的datasegment中(其它的应该是在heap或stack中)。如果明确的给一个值,object将以该值为初值。否则object所配置的内存内容为0。
2、new和delete运算符
(1)语言要求每一次对new的调用都必须传回一个独一无二的指针,传统方法就是传回一个指针,指向一个默认为1-Byte的内存区块。
(2)注意,如果用的当一个baseclass指针指向一个derivedclass objects所组成的数组时,delete时只会调用base class的destructor,虚拟机制不起作用,如下:
Point * pointer = new Point3d[10];
delete [ ] pointer;//此时调用的是Point::~Point()
如果必须这样做的话必须迭代走过整个数组,把delete实施于每一个元素上,如此才会调用virtual,如下:
for ( int ix=0; ix < elem_count; ++ix ){
Point3d *p = &( (Point3d*) ptr ) [ ix ];
delete p;
}
(3)placementoperator new的语意
Point2w*pt2 = new(arena)Point2w;
其中arena指向内存中的一个区块,用以放置新产生出来的Point2w object。
placementoperator new的价值在于它所扩充的另一半是将Point2wconstructor自动调用于arena所指的地址上。注意placement operator new并不支持多态,如Point2s*ptw = new (arena)Point3w;将会导致严重的破坏。
3、临时性对象
(1)临时性对象的被摧毁,应该是对完整表达式求值过程中最后的一步。该完整表达式造成临时对象的产生。
(2)凡持有表达式执行结果的临时性对象,应该存留到object的初始化操作完成为止。
(3)如果一个临时对象被绑定于一个reference,对象将残留,知道初始化之reference的声明结束,或者直到临时对象的声明范畴结束。