constructor
当编译器需要的时候,一个有用的(nontrivial)构造函数才会被声明出来,否则合成的是一个无用(trivial)的默认构造函数。
1.如果设计者设计的一个类的基类存在默认构造函数,该类的成员变量类带有默认的构造函数,但是没有提供构造函数,则编译器会为该类生成一个默认的构造函数,调用基类的默认构造函数(按照声明次序)和成员类默认的构造函数(按照声明次序),该成员函数时有用的。
2.在上述情况下,设计者提供了若干构造函数,但其中不包含基类和成员类的默认构造函数,则编译器不会在生成一个新的默认构造函数,但是会扩充每一个构造函数,调用基类和成员类的默认构造函数(先基类后成员类且按声明次序)。
3.class声明(或继承)一个虚函数。在前面一节中我们已经知道虚函数实现的机制,是生成一个虚函数表,存放指向虚函数的指针,然后生成一个指向该表的指针,该指针在构造函数中初始化,所以如果没有声明构造函数,编译器会生成默认的构造函数,实现虚指针的初始化,如果存在构造函数,编译器会为每一个构造函数安插初始化虚表指针的代码
4.class派生自一个继承串链,其中有一个或更多的virtual base classes。当利用指针访问成员时,由于在编译期不知道成员的实际偏移位置,因为指针所指向的类型是可以改变的,所以编译器会改变存取操作,使得这些操作在执行期才决定,也就是为每一个存在虚基类的派生类生成一个指针,该指针指向一个表,表中存放了虚基类与派生类指针的偏移地址。该指针也是在构造函数中完成初始化的,所以,如果有构造函数,编译器会添加代码初始化指针,如果没有,编译器会合成默认的构造函数初始化指针。
记住两点
1.任何class如果没有定义default constructor,编译器只在编译器需要的时候合成有用的默认构造函数,否则合成的是无用的(实际上并不会被合成出来)。
2.编译器合成出来的default constructor 不会明确设定class 内每一个data member的默认值。
copy constructor
当编译器需要的时候,一个有用的(nontrivial)copy constructor函数才会被声明出来
1.当class内含一个member object而后者的class声明有一个copy constructor时(不论是设计者声明出来的还是编译器合成的)。
2.当class继承自一个base class而后者存在一个copy constructor时(不论时设计者或是编译器合成的)。
3.当class声明了一个或多个virtual function时。在用派生类初始化基类对象时需要使虚表指针从指向派生类的虚表变为指向基类的虚表,所以此时简单的按位拷贝是不对的
4.当class派生自一个继承串链,其中有一个或多个virtual base classes时。如B虚继承自A,而C继承自B,若用C对象去初始化B对象,指向虚基类偏移位置的指针需要重新赋值。
关于构造函数中的初始化,必须用member initialization list的是
1.当初始化一个引用成员时
2.当初始化一个常量成员时
3.当调用一个base class的constructor,而它拥有一组参数时。(如过在构造函数体内赋值,会调用构造函数、赋值操作符,析构函数,过程就变的复杂了,而在member initialization list中只会调用构造函数)
4.当调用一个member class的constructor,而它拥有一组参数时。
注意初始化的顺序,按照声明次序初始化成员