C++ 可以指定类类型对象在创建,复制,赋值以及销毁时的动作;
构造函数定义了该类型对象创建时刻的初始化动作,复制构造函数,赋值操作符,析构函数定义了类对象在复制,赋值和销毁时的动作;
复制构造函数,赋值操作符,析构函数统称为复制控制;
只有单个形参,且该参数对对本类类型对象的引用(常用const 修饰) ,这样的构造函数称为复制构造函数;
复制构造函数可用于:
1. 根据同一类型的对象显示或隐式初始化一个新的对象;
2. 复制一个对象,将它作为实参传递给函数
3. 从函数返回时复制一个对象
4. 初始化顺序容器中的元素
5. 根据元素初始化列表初始化数组元素
当我们没有定义复制构造函数时,编译器会我们合成一个,即合成的复制构造函数
(对比:没有定义构造函数时,编译器会合成默认构造函数) ,故在定义任何构造函数时,最好都要再定义默认构造函数
‘
合成默认构造函数的行为是,执行逐个成员初始化,将新对象初始化为原对象的副本;
逐个成员指的是现有对象的每个非static 成员 ,赋值构造函数可以直接访问对象的public,protected ,private 成员
合成复制构造函数直接复制内置类型成员的值,类类型成员使用该类的赋值构造函数进行复制;
数组一般不能复制,但如果一个类有数组成员,则合成的复制构造函数将复制数组。 复制数组时,将会复制数组的每一个元素;
赋值构造函数的形参必须为引用,若不是引用类型,则会导致自己调用自己的无限递归调用;
为了防止复制(如iostream 不允许复制),必须显示的声明复制构造函数为private; 若连类的友元和成员中的复制也禁止,可以声明一个private 的复制构造函数但不对其定义;
声明但不定义成员函数是合法的,但使用未定义的成员会导致链接失败; 用户代码中尝试复制时会标记错误,成员函数和友元复制时会导致链接错误;
如果定义了复制构造函数,则必须定义默认构造函数,否则该类类型就会没有默认构造函数;
重载操作符是一些函数,其名字是operator后跟着所定义的操作符的符号,因此可以通过定义名为operator= 的函数,对赋值进行定义;
操作符函数也必须有形参表和返回值, 形参表必须具有和该操作符操作数数目相同的形参(如果操作符是一个成员函数,则包括隐式的this 形参;
赋值是二元操作符,故需要两个形参:第一个形参数对应左操作数,第二个形参对应右操作数;
当赋值操作符为成员函数时,第一个操作数隐式的绑定到this 指针,故只需要一个代表有操作数的形参;
赋值操作符的返回类型为右操作数的引用;
合成赋值操作符会对每个成员进行逐个赋值;
复制和赋值应该看着一个单元,如果需要其中一个,几乎也会需要另一个;
析构函数是构造函数的对立, 完成资源的回收;
撤销类型对象时会自动调用析构函数,撤销一个容器(标准库容器和数组)时也会运行类类型元素的析构函数,容器中元素逆序撤销吗;
动态分配的对象只有在指向该对象的指针被删除时才会(new 和delete 几乎要成对使用)
析构函数通常用于释放构造函数或者在对象生命周期中获取的资源,或者是执行希望类对象使用完毕后需要进行的操作;
三法则(rule of three): 如果类需要析构函数,则它也需要复制构造函数和赋值操作符;
编译器总是会为我们合成一个析构函数,合成析构函数安卓对象创建时的逆序撤销每个非static 成员,即按照成员在类中声明的逆序撤销成员;
析构函数是个成员函数,名字是类名字前加一个~,析构函数没有返回值,也没有形参,也不能重载析构函数;
即使我们编写了自己的析构函数,合成析构函数仍然运行;