拷贝构造函数
• 拷贝控制函数:如果一个构造函数的第一个参数是自身类的引用,且额外的参数都有默认值,则此构造函数是拷贝控制函数。
• 拷贝构造函数不应该是explicit的。
1 #include<iostream> 2 #include<string> 3 using namespace std; 4 5 class Sales_data { 6 public: 7 Sales_data(const Sales_data&); 8 private: 9 string bookNo; 10 int units_sold = 0; 11 double revenue = 0.0; 12 }; 13 14 Sales_data::Sales_data(const Sales_data &rhs): 15 bookNo(rhs.bookNo), 16 units_sold(rhs.units_sold), 17 revenue(rhs.revenue) 18 { }
拷贝初始化
string dots(10, ' '); //直接初始化 string s(dots); //直接初始化 string s2 = dots; //拷贝初始化 string null_book = "9-99-999-9999-9"; //拷贝初始化 string nines = string(100, '9'); //拷贝初始化
• 当使用直接初始化时,我们实际上是要编译器使用普通的函数匹配来选择与我们提供的参数最匹配的构造函数。
• 当我们使用拷贝初始化时,我们要求编译器将右侧运算拷贝到正在创建的对象中,如果需要的话要进行类型转换。
13.1.1练习
• 13.4
1. local = arg将arg拷贝给local
2. *heap = local; 将local拷贝到heap指定的地址中
3. Point pa[4] = {local, *heap}; 将local和heap拷贝给数组的前两个元素
4. return *heap;
• 13.5
1 class HasPtr { 2 public: 3 HasPtr(const string &s = string()): ps(new string(s)), i(0) {} 4 HasPtr(const HasPtr &rhs): ps( new string(*rhs.ps)), i(rhs.i) {} 5 private: 6 string *ps; 7 int i; 8 }
扫描二维码关注公众号,回复:
106912 查看本文章
拷贝赋值运算符
• 与处理拷贝构造函数一样,如果一个类未定义自己的拷贝赋值运算符,编译器会为它生成一个合成拷贝赋值运算符。
1 Sales_data &Sales_data::operator=(const Sales_data &rhs) 2 { 3 bookNo = rhs.bookNo; 4 units_sold = rhs.units_sold; 5 revenue = rhs.revenue; 6 return *this; 7 }
13.1.2节练习
1 class HasPtr { 2 public: 3 HasPtr(const string &s = string()): ps(new string(s)), i(0) {} 4 HasPtr(const HasPtr &rhs): ps( new string(*rhs.ps)), i(rhs.i) {} 5 6 HasPtr operator=(const HasPtr &rhs); 7 private: 8 string *ps; 9 int i; 10 } 11 12 HasPtr HasPtr::operator=(const HasPtr &rhs) 13 { 14 ps = new string(*rhs.ps); 15 i = rhs.i; 16 return *this; 17 }
析构函数
合成析构函数:当一个类定义自己的析构函数时,编译器会为它定义一个合成析构函数。
• 析构函数自身不直接销毁成员,成员是在析构函数体之后隐含的析构函数阶段中被销毁的。
1 class Sales_data { 2 public: 3 //成员会自动销毁,除此之外不需要做其他事情 4 ~Sales_data() {} 5 //其他成员的定义,如前 6 };
13.1.3练习
• 13.13
1 #include<iostream> 2 #include<string> 3 #include<vector> 4 using namespace std; 5 6 struct X { 7 X() { cout << "X()" << endl; } 8 X(const X&) { cout << "拷贝构造函数 X(const X&)" << endl; } 9 X& operator=(const X &rhs) { cout << "拷贝赋值运算符=(const X&)" << endl; return *this; } 10 ~X() { cout << "析构函数 ~()" << endl; } 11 }; 12 13 void f1(X x) 14 { 15 16 } 17 18 void f2(X &x) 19 { 20 21 } 22 23 int main() 24 { 25 cout << "局部变量" << endl; 26 X x; 27 cout << endl; 28 29 cout << "非引用参数传递:" << endl; 30 f1(x); 31 cout << endl; 32 33 cout << "引用参数传递" << endl; 34 f2(x); 35 cout << endl; 36 37 cout << "动态内存:" << endl; 38 X *px = new X(x); 39 cout << endl; 40 41 cout << "添加到容器中:" << endl; 42 vector<X> vx; 43 vx.push_back(x); 44 cout << endl; 45 46 cout << "释放动态内存" << endl; 47 delete px; 48 cout << endl; 49 50 cout << "间接初始化和赋值:" << endl; 51 X y = x; 52 y = x; 53 cout << endl; 54 55 cout << "程序结束" << endl; 56 return 0; 57 }
运行结果:
三五法则
• 如果一个类需要自定义析构函数,几乎可以肯定它也需要自定义拷贝赋值运算符和拷贝构造函数。
• 如果一个人类需要一个拷贝构造函数,几乎可以肯定它也需要一个拷贝赋值运算符。
• 如果一个类需要一个拷贝赋值运算符,几乎可以肯定它也需要一个拷贝构造函数。
13.1.4练习
• 13.13
/* 输出三个相同的序列号 */
• 13.15
/* 输出3、4、5 */
使用=default
• 我们可以通过将拷贝控制成员定义为=default来显式地要求编译器生成合成的版本。
1 class Sales_data { 2 public: 3 //拷贝控制成员; 使用default 4 Sales_data() = default; 5 Sales_data(const Sales_data &) = default; 6 Sales_data& operator=(const Sales_data &); 7 ~Sales_data() {} = default; 8 //其他成员的定义,如前 9 } 10 Sales_data& Sales_data::operator=(const Sales_data &) = default;