构造
- 无继承
Plain Old Data(纯data)
1
2
3
4typedef struct Point{
double x;
double y;
}Point;直接逐bit拷贝,编译器甚至没有生成默认构造和析构函数。
抽象数据
1 | class Point{ |
默认的bitwise copy已经足够。
- 带有虚函数
在执行构造函数的时候扩充代码,主要是对虚表进行初始化。
包括拷贝构造和拷贝赋值的时候,都会对虚表进行初始化。
- 继承
继承情况下会增加大量的隐藏代码:
- 记录初始化列表初始化操作并按照变量声明顺序进行初始化,这些初始化操作代码会放到构造函数内(但对于member object会少一次拷贝构造)。
- 对于没有在初始化列表中的成员变量,执行默认构造。
- 再此之前,先初始化虚表指针。
- 在此之前,调用基类的构造函数,以声明顺序为准。
- 如果基类在初始化列表中,把参数固定为初始化列表中的参数。
- 若没有在初始化列表,调用默认构造。
- 若为多重继承第二个之后的class,调整this指针。
- 在此之前,调用虚基类的构造函数,从左到右,从浅到深。
- 若在初始化列表,传入参数然后构造,若没有在列表,调用默认构造。
- virtual base class object偏移量在执行器必须可存取。
具体例子见《深度探索c++对象模型》P207
- 虚拟继承
- 共同父类怎么初始化?
在虚继承的时候,由于有共同父类的原因,对于子类的构造函数中的代码扩充,需要引入判断当前类是否为most_derived,即最后一个继承的子类。
在最后继承子类的构造函数中,对于父类的构造函数传递most_derived = false;从而来抑制父类对于共同父类的构造。
- 构造函数调用共同虚函数怎么初始化?
如果父类和子类的虚函数存在同名函数,那应该怎么初始化?是调用本体的虚函数还是全部调用继承类的虚函数?
C++规则是在类内调用的话全都应该是本体的虚函数。调用虚函数就需要虚函数表,那么应该怎么初始化?
- 在base class constructors调用之后,在初始化列表和user code之前。
因此可以这么理解,在虚继承机制下,一个子类首先变成共同父类,然后依次变成父类,最后构造本体,因此它的构造过程是:
- 在子类的构造函数中,调用共同父类和父类的构造函数。
- 初始化对象的虚表指针,指向相关的虚表。
- 在构造函数体内展开初始化列表。
- 执行user code。
- 对象复制
拷贝赋值什么时候会展现不会展现bitwise语义?
- class内部的某个成员对象有拷贝赋值。
- 基类有拷贝赋值。
- 存在虚函数。
- 存在虚父类。
一旦展现出bitwise语义,编译器就不为我们合成相关的函数。
- 析构
析构函数什么时候会被合成?
class内部的member object含有析构函数。
析构函数调用顺序和构造函数相反。