构造函数可能被编译器当成是一个转换函数,因此引入explicit,禁止隐式转换(c++11中没有被声明explicit的构造函数都有可能被当成是转换函数)
一、默认构造函数:
如果用户自己没有是声明构造函数,编译器就会自己生成一个默认构造函数,该默认构造函数在以下几种情况是nontrivial的,只有在以下四种情况下,编译器才会合成默认构造函数,且内置数据类型都不会被初始化,只有base class subobject和member class才会被初始化:
1)一个类中没有ctor,内含一个member object,后者有一个default ctor(因为需要调用后者的构造函数因此是nontrivial的),为了避免生成多个default ctor,将合成的default ctor作为inline函数。如果有多个member object,则编译器会按照声明顺序来调用member的ctor,并且程序自己定义了ctor,没有包括所有的member,编译器则会自动插入对应的ctor。
2)一个类由一个有构造函数的基类派生而来, 生成的default ctor会先调用base object的ctor
3)包含虚函数的类 ,default ctor会为每一个class object 初始化vptr
4)虚继承而来的类
三四两点都需要default来初始化vptr和vtbl
二、拷贝构造函数:
三种情况会调用copy ctor
1)用一个对象来初始化一个新对象
2)调用函数的时候,对象的作为参数传入
3)函数返回一个对象
若没有定义copy ctor,编译器会采用两种方法来拷贝对象,member wise copy(default copy ctor)和bit wise copy(位逐次拷贝,复制的东西完全一样)。
以下四种情况会生成default copy ctor:
1)class中包含了一个member object,而这个object有copy ctor(不管是程序设计还是编译器合成的)
2)class继承了一个base class,后者有copy ctor
3)声明了一个虚函数
4)虚继承
一二两点,要复制基类和派生类中的数据,基类中提供了copy ctor,因此存在bitwise copy无法完成的情况,因此需要合成copy ctor。三四两点需要重新初始化vptr和vtbl,因为可以使用派生类给基类初始化(只需要slice即可),如果使用bitwise copy的话,vptr也会被复制。
对象作为传入参数:
首先声明一个临时变量,用copy ctor初始化,传入函数中,使用引用节省时间
对象作为返回参数:
在传入参数中添加一个相应的object的引用,用于存放返回值,在return前加上copy ctor,返回值为空。编译器优化,直接对_result进行处理,不需要调用copy ctor函数(NRV优化)
三、成员初始化列表:
以下四种情况必须使用初始化列表:
1)初始化一个reference member
2)初始化一个const member
3)调用基类的ctor
4)调用member data 的ctor
在一个类中使用了member object,并且在ctor中进行赋值,则会首先创建一个临时对象,初始化并copy给member data,最后dtor。如果使用成员初始化列表,只会调用构造函数。编译器会根据member data声明的顺序,进行初始化,并且初始化在显示调用构造函数或者赋值的前面。