前言
C++通过在类中定义几个成员函数来控制的对象的拷贝,移动,赋值和销毁,分别如下:
- 拷贝构造函数和移动构造函数定义:当用同一类型的另一个对象初始化本对象时做什么(注意区分初始化和赋值)
- 拷贝和移动赋值函数定义:将一个对象赋予同类型的的另一个对象的时候做什么
- 析构函数定义当此类型对象销毁时做什么
拷贝,赋值,销毁。
1. 拷贝构造
C++拷贝构造函数是一种特殊的构造函数,用于同一类中之前创建的对象来初始化新创建的对象。拷贝构造函数的名称必须和类名称一致,它的第一个参数必须是一个本类型对象的引用
(原因是如果不是引用,则函数实参的初始化需要执行拷贝初始化,但拷贝初始化又需要调用拷贝构造,造成死循环),且任何额外的形参都有默认值。
有3种情况会调用拷贝构造函数:
- 通过使用一个已有的同类型对象来初始化新创建的对象
A a2 = a1
- 对象作为参数传递给函数
如下面a2.get(a1)
- 从函数返回这个对象时会调用拷贝构造
下面分别使用代码来说明几种调用情况:
#include <iostream>
using namespace std ;
class A{
private:
int _a ;
public:
A(int a){
_a = a ;
cout<< "this is a's constructor function"<< endl ;
}
A(const A &a){
cout << "this is a's copy constructor function" << endl ;
}
~A(){
cout << "this is a's destructor function" << endl ;
}
A getA(A a){
return a ;
}
void printA(){
cout<< _a <<endl ;
}
} ;
A constructor_aA(){
A a(12) ;
return a ;
}
int main(){
A a1(10) ;
a1.printA() ;
cout << "====1======" <<endl ;
//第一种情况,使用已初始化的对象初始化未初始化的对象的时候调用拷贝构造函数
A a2 = a1 ; //拷贝构造,区别以拷贝赋值的形式: a2 = a1
//第一种情况,使用已初始化的对象初始化未初始化的对象的时候调用拷贝构造函数,括号法
A a3(a1); //拷贝构造
cout << "=====2=====" <<endl ;
//第2种情况,复制对象把它作为参数传递给函数。
a2.getA(a1) ; //实际上发生的是 A a = a1 ; //拷贝构造,实际上还发生了一次 return的返回值会被拷贝构造给一个新的类对象,此处没有接收
cout << "=====3=====" <<endl ;
//第3种情况,函数返回一个对象
A a4 = constructor_aA();
cout << "==========" <<endl ;;
return 0 ;
}
- 注意区分拷贝构造和拷贝初始化,初始化是行为,需要调用拷贝构造函数。
2. 拷贝赋值
拷贝赋值发生在下面的这种情况:
A a ,b ;
b = a ;
- 重载运算符:本质是一种函数,函数名称由operator关键字后接表示要定义的运算符的符号组成。因此,赋值运算符就是一个名为operator=的函数,和其他函数类型,运算符函数也有返回值和参数列表。
Foo& operator=(const Foo&) ;
//赋值运算符 - 如果一个类没有定义拷贝赋值运算符,则编译器会自动合成一个
合成拷贝赋值运算符
- 默认的拷贝赋值运算符会将运算符=右侧的对象的非static成员赋予左侧运算符对象的相应成员,对于数组类型成员,会逐个赋值数组元素。
3.析构函数
- 析构函数释放对象使用的资源,并销毁对象的非static数据成员
-
在析构函数中,先执行函数体,然后销毁成员
,也就是说,析构函数自身并不销毁成员,成员时在析构函数之后隐含的析构阶段被销毁的。 - 调用时机:
- 变量离开作用域
- 当一个对象被销毁,其成员被销毁
- 容器被销毁,其元素被销毁
- 动态分配的对象,当指向它的指针应用delete运算符时销毁
- 对于临时对象,当创建它的完整表达式被销毁。
合成的析构函数不会delete一个指针成员
一般情况下,需要析构函数的类都需要拷贝和赋值操作。
需要拷贝操作的类也需要赋值操作,反之亦然
=default
显示要求编译器生成合成的控制函数。只能用于拷贝控制函数
=delete
将函数定义为删除的函数,表示虽然声明了该函数,但是不能使用。delete必须出现在函数第一次声明的时候。 可以将delete用于普通函数,表示该函数不能被调用。
-当不可能拷贝,赋值,销毁类的成员时,类的合成拷贝控制成员就被定义为删除的
(不能拷贝赋值销毁的成员指1.析构函数不能访问,2.某个拷贝构造函数是删除的或private的3. 类的某个常用拷贝赋值运算符是删除的或private的。如果类的某个成员的析构函数是删除的或不可访问的,或是类有一个引用成员,没有初始化器。)其本质是类的数据成员不能默认拷贝赋值删除或销毁。
- private拷贝控制
使用将函数声明为private并且不定义它,也可以阻止对象被拷贝或赋值。
拷贝控制和资源管理
对象拷贝时行为有两种情况,一种是对象的拷贝时类的行为像值拷贝,每个对象有自己独立的状态。一种是像指针,副本和原对象使用相同的底层数据。改变副本也会改变愿对象。
网友评论