为了定义拷贝构造函数和拷贝赋值运算符,我们首先必须确认此类型对象的拷贝语义。通常可以定义拷贝操作,使类的行为看起来像一个值或者像一个指针(即所谓的深拷贝和浅拷贝)
类的行为像一个值,意味着它应该也有自己的状态。当我们拷贝一个像值的对象时,副本和原对象是完全独立的。改变副本不会对原对象有任何影响,反之亦然
行为像指针的类则共享状态。当我们拷贝一个这种类的对象时,副本和原对象使用相同的底层数据。改变副本也会改变原对象,反之亦然
在我们使用过的标准库类中,标准库容器和 string 类的行为像一个值。shared_ptr 提供类似指针的行为。IO 类型和 unique_ptr 不允许拷贝或赋值,因此它们的行为既不像值也不像指针
行为像值的类:
1 #include <iostream> 2 using namespace std; 3 4 class HasPtr{ 5 public: 6 HasPtr(const std::string &s = std::string()) : ps(new std::string(s)), i(0) {} 7 HasPtr(const HasPtr &p) : ps(new std::string(*p.ps)), i(p.i) {} 8 HasPtr& operator=(const HasPtr&); 9 ~HasPtr(){ 10 delete ps; 11 } 12 13 ostream& print(ostream &os){ 14 os << i << " " << *ps << " " << ps; 15 return os; 16 } 17 18 private: 19 std::string *ps; 20 int i; 21 }; 22 23 HasPtr& HasPtr::operator=(const HasPtr &rhs){ 24 auto newp = new string(*rhs.ps);//为了避免两个对象中ps指针相同时出错先将rhs.ps中的内容存放到一个新开辟的空间newp中 25 delete ps;//释放旧内存 26 ps = newp; 27 i = rhs.i; 28 return *this; 29 } 30 31 int main(void){ 32 HasPtr s1("hello"); 33 HasPtr s2 = s1; 34 HasPtr s3; 35 s3 = s1; 36 37 s1.print(cout) << endl; 38 s2.print(cout) << endl; 39 s3.print(cout) << endl; 40 41 // 输出: 42 // 0 hello 0x2a811d8 43 // 0 hello 0x2a811a8 44 // 0 hello 0x2a81198 45 46 return 0; 47 }