C++進階--擁有資源控制代碼的類(淺拷貝,深拷貝,虛建構函式)
阿新 • • 發佈:2018-12-24
// 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容易要求元素時可拷貝的