C++进阶--拥有资源句柄的类(浅拷贝,深拷贝,虚构造函数)

// Person通过指针拥有string
class Person {
public:
   Person(string name) { pName_ = new string(name); }
   ~Person() { delete pName_; }

   void printName() { cout << *pName_; }

private:
   string* pName_;
};

int main() {
   
   vector<Person> persons;
   persons.push_back(Person("George")); 

   persons.front().printName(); //这里会崩

   cout << "Goodbye" << endl;
}

   //persons.push_back(Person("George")); 事实上该行代码可以分解成以下步骤
   // 1. "George" 被构造
   // 2. "George"的一个副本保存到(浅拷贝)
   // 3. "George"被销毁

// Solution 1: 定义拷贝构造和拷贝赋值实现深拷贝
    Person(const Person& rhs) {   
      pName_ = new string(*(rhs.pName()));
   }
    Person& operator=(const Person& rhs);  
   string* pName() const { return pName_; }

// Solution 2: 禁用拷贝构造和拷贝赋值
// 对C++ 11,使用=delete
// for C++ 03, 声明但不定义
    Person(const Person& rhs); 
    Person& operator=(const Person& rhs);  

// 如果禁用之后仍然需要拷贝,使用clone()
// 显式的拷贝
    Person* clone() {  
      return (new Person(*(pName_)));
   }

// 更推荐方法2:
// 1. 因为拷贝构造和拷贝赋值经常并不需要
// 2. 使拷贝显式,隐式拷贝容易出现bug
// 3. clone可以利用多态实现虚构造函数,自动根据指针所指对象的类型拷贝基类或者派生类对象

class Dog { 
public:
   virtual Dog* clone() { return (new Dog(*this)); }   //co-variant return type 允许覆写函数具有不同的返回类型,只要返回类型由基类的返回类型派生得到
};

class Yellowdog : public Dog { 
   virtual Yellowdog* clone() { return (new Yellowdog(*this)); }
};

void foo(Dog* d) {      // d 是Yellowdog
   //Dog* c = new Dog(*d); // c 是Dog,不是我们想要的
   Dog* c = d->clone();    // c是Yellowdog
   //... 
   //
}

int main() {
   Yellowdog d;
   foo(&d);
}

// C++ 11 的方法:
//    shared_ptr<string> pName_;
//    大多数情况下用unique_ptr也可以, 但是跟STL container一起使用时必须使用shared_ptr, 
//    因为STL容易要求元素时可拷贝的

猜你喜欢

转载自www.cnblogs.com/logchen/p/10166653.html
今日推荐