学习拷贝构造函数和赋值运算符
拷贝构造函数在下面三种情况下被调用:
- 拷贝初始化,如:A b(a);
- 赋值初始化:如:A b = a;
- 函数传形参:如:foo(A a)
赋值运算只有一种情况会被调用:
- 非初始化的赋值:如:A b; b = a;
代码:
1 #include <stdlib.h> 2 #include <string> 3 4 /*** 5 * @author:zanzan101 6 */ 7 8 inline void P(const char* str) 9 { 10 printf("%s\n", str); 11 } 12 13 class A 14 { 15 private: 16 int _data; 17 char* _name; 18 public: 19 A(): _name(0) 20 { 21 P("调用构造函数"); 22 } 23 24 // 拷贝构造函数 25 // 无论构造函数还是拷贝构造函数,都要处理好对于指针的初始化,一般,应该一开始就对指针赋值为0,后面再进一步赋值 26 // 对象的产生,究其根源只有两个途径:构造和拷贝构造,赋值运算的右值也是来自这两种途径 27 A(A& a) 28 { 29 P("调用拷贝构造函数"); 30 _name = 0; 31 _data = a._data; 32 if(a._name) 33 { 34 _name = new char[strlen(a._name)+1]; 35 strcpy(_name, a._name); 36 } 37 } 38 39 // 赋值运算符 40 // 注意:返回值类型设为A&是为了实现a=b=c、(a=b)=c等操作 41 A& operator= (A& a) 42 { 43 P("调用赋值运算符"); 44 45 if(this == &a) 46 return *this; 47 48 // 调用赋值运算的对象,必然已经经历过了构造或者拷贝构造 49 // 因此,合理的设计构造和拷贝构造函数,会使_name为0或者其他有效值,不会出现0xCCCCCCCC的非法情况 50 if(_name) 51 delete _name; 52 53 _data = a._data; 54 55 if(!a._name) 56 _name = 0; 57 else 58 { 59 _name = new char[strlen(a._name)+1]; 60 strcpy(_name, a._name); 61 } 62 return *this; 63 } 64 }; 65 66 void foo(A a) 67 { 68 return; 69 } 70 int _tmain(int argc, _TCHAR* argv[]) 71 { 72 P(">> 声明对象,但不初始化时:"); 73 A a; 74 75 P(">> 声明对象同时用对象进行初始化时:"); 76 A b = a; 77 78 P(">> 先声明对象:"); 79 A c; 80 P(">> 再对对象进行赋值时:"); 81 c = a; 82 83 P(">> 使用拷贝构造函数初始化时:"); 84 A d(a); 85 86 P(">> 在函数调用传入形式参数时:"); 87 foo(a); 88 89 90 system("pause"); 91 return 0; 92 }
输出:
>> 声明对象,但不初始化时: 调用构造函数 >> 声明对象同时用对象进行初始化时: 调用拷贝构造函数 >> 先声明对象: 调用构造函数 >> 再对对象进行赋值时: 调用赋值运算符 >> 使用拷贝构造函数初始化时: 调用拷贝构造函数 >> 在函数调用传入形式参数时: 调用拷贝构造函数 请按任意键继续. . .