20180206修订:将具体例子改为Ch09_Point类(作为指针变量使用),Ch09_CopyConstructor类(作为父类,包含Ch09_Point指针变量),Ch09_DeprivedClass类(作为子类)。通过这三个类的相互关系,介绍c++的拷贝构造函数和赋值操作符的使用。
拷贝构造函数(copy constructor)又称为复制构造函数,此函数经常用在函数调用时用户自定义类型的值传递及返回。如果没有定义拷贝构造函数,编译器会自动为我们创建一个,拷贝构造函数会逐个执行成员的初始化(按照类成员在类中声明的顺序)。对于基本类型数据默认拷贝构造函数可以正常创建一个副本并由被赋值对象持有;对于类类型数据直接调用数据的拷贝构造函数创建新的副本并由被赋值对象持有(有可能两个对象共同持有一个数据);对于指针类数据,默认拷贝函数会让两个对象共同持有一个数据,导致修改A对象,B对象的值跟着变化,在程序中造成异常。
拷贝构造函数调用条件:
1)一个对象最为函数参数,以“值传递”的方式传入函数体。
2)一个对象作为函数返回值,以“值传递”的方式从函数返回。
3)一个对象对另一个对象进行初始化。
拷贝构造函数及赋值操作符(C++建议类的赋值操作符作为类方法出现,同样建议的还有“.”, "[]", "()")格式:
1 Ch09_Point.h: 2 3 class Ch09_Point 4 { 5 public: 6 explicit Ch09_Point(); 7 explicit Ch09_Point(int x, int y); 8 9 /** 10 *@author qioawei 11 *@date 2018-02-05 12 *@version 1.0 13 *@brief 拷贝构造函数 14 *@called by 15 *@param p 16 **/ 17 Ch09_Point(const Ch09_Point& p); 18 19 void print() const; 20 21 void SetPoint(int x, int y); 22 23 int GetX() const; 24 25 int GetY() const; 26 27 /** 28 *@author qioawei 29 *@date 2018-02-05 30 *@version 1.0 31 *@brief = 赋值操作符 32 *@called by 33 *@param rvalue 赋值变量 34 *@return 赋值后 35 **/ 36 Ch09_Point& operator = (const Ch09_Point& rvale); 37 38 friend Ch09_Point operator + (const Ch09_Point& a, const Ch09_Point& b); 39 40 private: 41 int x_; 42 int y_; 43 }; 44
45 Ch09_Point.cpp: 46 47 #include "ch09_point.h" 48 49 Ch09_Point::Ch09_Point() : 50 x_(0), 51 y_(0) 52 { 53 54 } 55 56 Ch09_Point::Ch09_Point(int x, int y) : 57 x_(x), 58 y_(y) 59 { 60 61 } 62 63 Ch09_Point::Ch09_Point(const Ch09_Point &p) 64 { 65 x_ = p.x_; 66 y_ = p.y_; 67 } 68 69 void Ch09_Point::print() const 70 { 71 qDebug() << "x = " << x_ << ", y = " << y_ << endl; 72 } 73 74 void Ch09_Point::SetPoint(int x, int y) 75 { 76 x_ = x; 77 y_ = y; 78 } 79 80 int Ch09_Point::GetX() const 81 { 82 return x_; 83 } 84 85 int Ch09_Point::GetY() const 86 { 87 return y_; 88 } 89 90 Ch09_Point& Ch09_Point::operator = (const Ch09_Point &rvale) 91 { 92 if (this != &rvale) { 93 x_ = rvale.x_; 94 y_ = rvale.y_; 95 } 96 97 return *this; 98 } 99 100 Ch09_Point operator + (const Ch09_Point &a, const Ch09_Point &b) 101 { 102 return Ch09_Point(a.x_ + b.x_, a.y_ + b.y_); 103 }
使用情况:
1 Ch09_Point a1; //调用无参构造函数 2 Ch09_Point a2(a1); //调用拷贝构造函数 3 Ch09_Point a3 = a1; //调用拷贝构造函数 4 Ch09_Point a4; 5 a4 = a2 //赋值操作符 6 7 //特殊情况 8 Ch09_Point* a5(new A()); 9 Ch09_Point a6(*a5) //调用拷贝构造函数 10 Ch09_Point* p3 = new Ch09_Point(10, 20); //构造函数 11 a6 = *p3; //赋值操作符 12 Ch09_Point p4(*p3); //拷贝构造函数
“=”在对象声明语句中表示初始化,调用拷贝构造函数;在非声明语句中表示赋值,调用赋值构造函数。
Ch09_CopyConstructor类作为容器类,保存Ch09_Point类型指针,具体如下:
1 ch09_copyconstructor.h 2 3 class Ch09_Point; 4 5 class Ch09_CopyConstructor 6 { 7 public: 8 explicit Ch09_CopyConstructor(); 9 explicit Ch09_CopyConstructor(int x, int y); 10 11 /** 12 *@author qioawei 13 *@date 2018-02-05 14 *@version 1.0 15 *@brief 拷贝构造函数 16 *@called by 17 *@param cc 18 **/ 19 Ch09_CopyConstructor(const Ch09_CopyConstructor& cc); 20 21 ~Ch09_CopyConstructor(); 22 23 Ch09_CopyConstructor& operator = (const Ch09_CopyConstructor& rvalue); 24 25 void Print() const; 26 27 private: 28 Ch09_Point* p_; 29 }; 30 31 ch09_copyconstructor.cpp 32 33 #include "ch09_copyconstructor.h" 34 35 #include "ch09_point.h" 36 37 Ch09_CopyConstructor::Ch09_CopyConstructor() : 38 p_(new Ch09_Point(0, 0)) 39 { 40 41 } 42 43 Ch09_CopyConstructor::Ch09_CopyConstructor(int x, int y) : 44 p_(new Ch09_Point(x, y)) 45 { 46 } 47 48 Ch09_CopyConstructor::Ch09_CopyConstructor(const Ch09_CopyConstructor &cc) 49 { 50 if (this != &cc) { 51 delete p_; 52 53 //调用Ch09_Point的拷贝构造函数 54 p_ = new Ch09_Point(*(cc.p_)); 55 } 56 } 57 58 Ch09_CopyConstructor::~Ch09_CopyConstructor() 59 { 60 delete p_; 61 62 //qDebug() << "from base class" << endl; 63 } 64 65 Ch09_CopyConstructor& Ch09_CopyConstructor::operator =(const Ch09_CopyConstructor& rvalue) 66 { 67 if (this != &rvalue) { 68 delete p_; 69 //调用Ch09_Point拷贝构造函数? 70 p_ = new Ch09_Point(*(rvalue.p_)); 71 } 72 73 return *this; 74 } 75 76 void Ch09_CopyConstructor::Print() const 77 { 78 p_->print(); 79 }
因为p_变量在构造函数中进行初始化,在进行拷贝构造或者赋值操作时需要先判断,如与所赋对象不一致,则需要先delete p_的实例,随后创建新实例保存所赋对象中数据。
Ch09_DeprivedClass类作为Ch09_CopyConstructor的子类,同时在Ch09_DeprivedClass类中保存一个Ch09_Point类作为变量保存。
1 Ch09_DeprivedClass.h 2 3 class Ch09_Point; 4 5 class Ch09_DeprivedClass : public Ch09_CopyConstructor 6 { 7 public: 8 explicit Ch09_DeprivedClass(); 9 explicit Ch09_DeprivedClass(int x, int y); 10 11 Ch09_DeprivedClass(const Ch09_DeprivedClass& dc); 12 13 virtual ~Ch09_DeprivedClass(); 14 15 Ch09_DeprivedClass& operator =(const Ch09_DeprivedClass& dc); 16 17 void PrintDeprivedClass(); 18 19 public: 20 Ch09_Point* deprived_p_; 21 }; 22 23 Ch09_DeprivedClass.cpp 24 25 #include "ch09_deprivedclass.h" 26 27 #include "ch09_point.h" 28 29 Ch09_DeprivedClass::Ch09_DeprivedClass() : 30 Ch09_CopyConstructor(), 31 deprived_p_(new Ch09_Point(0, 0)) 32 { 33 qDebug() << deprived_p_ << endl; 34 } 35 36 Ch09_DeprivedClass::Ch09_DeprivedClass(int x, int y) : 37 Ch09_CopyConstructor(x, y), 38 deprived_p_(new Ch09_Point(x + 11, y + 22)) 39 { 40 qDebug() << deprived_p_ << endl; 41 } 42 43 Ch09_DeprivedClass::Ch09_DeprivedClass(const Ch09_DeprivedClass &dc) : 44 Ch09_CopyConstructor(dc) //调用基类拷贝构造函数 45 { 46 if (this != &dc) { 47 delete deprived_p_; 48 49 deprived_p_ = new Ch09_Point(*(dc.deprived_p_)); 50 //deprived_p_ = new Ch09_Point(dc.deprived_p_->GetX(), dc.deprived_p_->GetY()); 51 } 52 } 53 54 Ch09_DeprivedClass::~Ch09_DeprivedClass() 55 { 56 delete deprived_p_; 57 58 //qDebug() << "from deprived class" << endl; 59 } 60 61 Ch09_DeprivedClass &Ch09_DeprivedClass::operator =(const Ch09_DeprivedClass &dc) 62 { 63 if (this != &dc) { 64 delete this; 65 66 //调用基类赋值操作符,完成基类private变量的赋值 67 Ch09_CopyConstructor::operator =(dc); 68 deprived_p_ = new Ch09_Point(*(dc.deprived_p_)); 69 } 70 71 return *this; 72 } 73 74 void Ch09_DeprivedClass::PrintDeprivedClass() 75 { 76 Print(); 77 78 qDebug() << " deprived x = " << deprived_p_->GetX() 79 << ", deprived y = " << deprived_p_->GetY() << endl; 80 }
在拷贝构造函数中需要调用基类的拷贝构造函数;在赋值操作符中调用基类赋值操作符,给基类中保存的private变量赋值。