拷贝构造函数
定义
如果一个构造函数的第一个参数是自身类类型的引用,且任何额外参数都有默认值,则此构造函数是拷贝构造函数。拷贝构造函数的第一个参数必须是一个引用类型,且几乎总是一个const的引用。
如果类没有显式地定义一个拷贝构造函数,那么编译器会为其合成一个拷贝构造函数
合成拷贝构造函数
合成的拷贝构造函数会将其参数的成员逐个拷贝到正在创建的对象中。编译器从给定对象中依次将每个非static成员拷贝到正在创建的对象中。
成员的类型决定了如何拷贝:对于类类型的成员,会使用拷贝构造函数来拷贝;内置类型的成员则直接拷贝;数组类型则会逐元素地拷贝。
拷贝初始化(拷贝构造函数使用的时候):
- 用 = 号定义变量
- 将一个对象作为实参传递给一个非引用类型的形参
- 从一个返回类型为非引用的函数返回一个对象
- 用花括号列表初始化一个数组中的元素或一个聚合类中的成员
拷贝构造函数被用来初始化非引用类类型参数,如果拷贝构造函数的参数不是引用类型,则调用永远也不会成功——为了调用拷贝构造函数,我们必须拷贝它的实参,但为了拷贝实参,我们又需要调用拷贝构造函数,如此无限循环
拷贝赋值运算符
定义
赋值运算符是一个名为operator= 的函数。类似于其他函数,运算符函数也有一个返回类型和一个参数列表。重载赋值运算符,必须定义为成员函数,如此才可以将this参数隐式地绑定到左侧运算对象上,而右侧运算对象作为显式参数传递。拷贝赋值运算符接受一个与其所在类相同类型的参数。且为了与内置类型的赋值保持一致,赋值运算符通常返回一个指向其左侧运算对象的引用。如果类没有定义赋值运算符重载函数,那么编译器会为其合成一个。
合成赋值运算符
与拷贝构造函数类似,会将右侧运算对象的每个非static成员赋予左侧运算对象的对应成员,通过成员类型的拷贝赋值运算符来完成的。同样,对于数组,逐个赋值数组元素。
编写赋值运算符需注意
- 如果将一个对象赋予它自身,赋值运算符必须能正确工作
- 大多数赋值运算符组合了析构函数和拷贝构造函数的工作(先析构左侧运算对象,再将右侧运算对象拷贝给左侧运算对象)
析构函数
定义及作用
析构函数执行与构造函数相反的操作:构造函数初始化对象的非static数据成员;析构函数释放对象使用的资源,并销毁对象的非static数据成员。
析构函数是类的一个成员函数,名字由波浪号接类名构成,没有返回值,也不接受参数,因此,不能被重载,一个给定的类只有一个析构函数。
在一个析构函数中,首先执行函数体,然后销毁成员,析构函数函数体并不销毁成员,成员是在析构函数体之后隐含的析构阶段中被销毁的。成员按照初始化顺序的逆序销毁。
通常,析构函数释放对象在生存期分配的所有资源。成员销毁时发生什么完全以来于成员的类型。类类型的成员需要执行成员自己的析构函数,内置类型则不需要进行任何操作。
隐式销毁一个内置指针类型的成员不会delete它所指向的对象,智能指针属于类类型,所以具有析构函数,在在析构阶段会被自动销毁,同时释放指向的内容调用时间
无论何时一个对象被销毁,就会自动调用其析构函数
- 变量在离开其作用域时被销毁
- 当一个对象被销毁时,其成员被销毁
- 容器被销毁时,其元素被销毁
- 对于动态分配的对象,当对指向它的指针应用delete运算符时被销毁
- 对于临时对象,当创建它的完整表达式结束时被销毁