2.1 Default Constructor的构建操作
带有“Default Constructor”的Member Class Object
如果一个类没有定义 default construction,就会有一个nontrivial(有用的) constructor被合成,依次调用作为成员的类的default constructor。如果定义了,则扩张该default constructor,调用作为成员的类的default constructor。
带有“Default Constructor”的Base Class
如果派生类没有定义default constructor,就会有一个nontrivial constructor被合成,依次调用基类的default constructor,然后再调用作为成员的类的构造函数。如果设计者提供了多个constructor,但是没有default constructor,它会将必要的构造函数加进去,不会生成default constructor。
带有“Virtual Function”的Class
生成虚表,设定虚表指针的初值。编译器为了让virtual机制发挥功效,必须为每一个vptr设定初值。无论是已声明构造函数还是编译器生成default constructor,都会初始化class object的vptr。
- 当类中含有其他类的对象作为成员对象的时候,注意构造顺序:基类的构造函数 → 对象成员的构造函数 → 派生类的构造函数;copy构造函数也类似。
- 编译器生成的default constructor不会将成员初始化(eg:int类型变量、指针...)为0。
- 一个类的 基类或者作为成员的类 没有默认构造函数,编译器不会为该类生成默认构造函数,编译报错。
- 错误的观点:任何class如果没有定义default constructor,就会被合成出一个来。
- 错误的观点:编译器合成出来的default constructor会明确设定class内每一个data member的默认值。
2.2 Copy Constructor的构建操作
满足bitwise copy semantics(位逐次拷贝)的类,编译器生成的拷贝构造函数直接将X2的成员逐一拷贝给X1。
不满足bitwise copy semantics的类:
- class内含member object,而后者的类声明了copy constructor时;
- class继承base class,而后者的类声明了copy constructor时;
- class声明了虚函数;
- class派生一个或多个虚基类。
对于1、2,编译器生成的copy constructor调用members或base class的copy constructors。
对于3,编译器生成的copy constructor会拷贝X2的vptr值给自身的vptr。相同类的赋值,使用bitwise copy.
2.3 程序转换语义学
程序员自定义的copy constructor如果使用memset、memset函数操作类,必须没有编译器自动生成的members。
2.4 成员们的初始化队伍
class A
{
public:
A(){}
~A(){}
A(int _m):m(_m){}
A& operator=(const A& a){m = a.m; return *this;}
private:
int m;
}
class B
{
public:
#if 0
B(int m):a(m){} //使用初始化列表
#endif
B(int m){a = A(m);}
private:
A a;
}
对于类B的constructor,初始化链表,对成员类初始化时,只调用了A的constructor。
而不使用初始化列表,先调用A的默认constructor构造a,再调用A的带参constructor构造临时对象,再调用copy assignment操作符重载函数,再调用析构函数释放临时对象。
初始化列表对成员变量初始化是按照成员变量的声明顺序的,而和列表的顺序无关。初始化列表的执行在explicit user code之前。