設計模式之 原型模式(prototype)(C++實現 深拷貝 + 淺拷貝版本[bug])
阿新 • • 發佈:2018-12-30
本文介紹設計模式中的原型模式。
本質上其實就是克隆。
下面以個人簡歷為例進行舉例說明:
深拷貝版本:
#include <iostream> #include <string> #include <memory> using namespace std; template<class T> class ICloneable { public: virtual T* clone() = 0; }; class CWorkExperience { public: CWorkExperience(){} CWorkExperience(const string& company, const string& workTime) { m_strCompany = company; m_strWorkTime = workTime; } CWorkExperience(const CWorkExperience& right) { m_strCompany = right.m_strCompany; m_strWorkTime = right.m_strWorkTime; } ~CWorkExperience() { cout << "CWorkExperience析構" << endl; printInfo(); } void setCompany(const string& company) { m_strCompany = company; } const string& getCompany() const { return m_strCompany; } void setWorkTime(const string& workTime) { m_strWorkTime = workTime; } const string& getWorkTime() const { return m_strWorkTime; } void printInfo() { cout << "Company: " << m_strCompany << endl; cout << "WorkTime: " << m_strWorkTime << endl; } private: string m_strCompany; // company name string m_strWorkTime; // work time }; // 簡歷類 class CResume : public ICloneable<CResume> { public: CResume(){} ~CResume() { cout << "CResume析構 " << m_name << endl; } void setInfo(const string& name, const string& sex , int age) { m_name = name; m_sex = sex; m_age = age; } void setExperience(const string& company, const string& workTime) { m_experience.setCompany(company); m_experience.setWorkTime(workTime); } CResume* clone() { CResume* resume = new CResume; resume->setInfo(m_name, m_sex, m_age); resume->setExperience(m_experience.getCompany(), m_experience.getWorkTime()); return resume; } void printInfo() { cout << "Name: " << m_name << endl; cout << "Sex: " << m_sex << endl; cout << "Age: " << m_age << endl; cout << "Experience: " << endl; m_experience.printInfo(); cout << endl; } protected: string m_name; string m_sex; int m_age; CWorkExperience m_experience;// 物件 }; void testPrototype() { CResume re; re.setInfo("Jacky", "Male", 20); re.setExperience("MS", "2001.11 - 2005.11"); re.printInfo(); CResume* pClone = re.clone(); pClone->setInfo("Marry", "Female", 30); pClone->setExperience("Google", "2006.01 - 2010.01"); pClone->printInfo(); delete pClone; pClone = NULL; } int main(void) { testPrototype(); return 0; }
執行結果如下:
#include <iostream> #include <string> #include <memory> using namespace std; // 克隆介面 template<class T> class ICloneable { public: virtual T* clone() = 0; }; // 工作經歷類 class CWorkExperience { public: CWorkExperience(){} CWorkExperience(const string& company, const string& workTime) { m_strCompany = company; m_strWorkTime = workTime; } CWorkExperience(const CWorkExperience& right) { m_strCompany = right.m_strCompany; m_strWorkTime = right.m_strWorkTime; } ~CWorkExperience() { cout << "CWorkExperience析構" << endl; printInfo(); } void setCompany(const string& company) { m_strCompany = company; } const string& getCompany() const { return m_strCompany; } void setWorkTime(const string& workTime) { m_strWorkTime = workTime; } const string& getWorkTime() const { return m_strWorkTime; } void printInfo() { cout << "Company: " << m_strCompany << endl; cout << "WorkTime: " << m_strWorkTime << endl; } private: string m_strCompany; // company name string m_strWorkTime; // work time }; // 簡歷類 class CResume : public ICloneable<CResume> { private: // 只允許呼叫帶引數的建構函式和拷貝建構函式 CResume(){m_experience = NULL;} public: // 帶參建構函式 CResume(CWorkExperience* pWorkExperience) { // 不負責記憶體分配 只是共享 m_experience = pWorkExperience; } // 帶參拷貝建構函式 CResume(const CResume& right) { m_name = right.m_name; m_sex = right.m_sex; m_age = right.m_age; // 注意這裡是指標賦值 屬於淺拷貝 m_experience = right.m_experience; } ~CResume() { cout << "CResume析構 " << m_name << endl; } void setInfo(const string& name, const string& sex , int age) { m_name = name; m_sex = sex; m_age = age; } void setExperience(const string& company, const string& workTime) { m_experience->setCompany(company); m_experience->setWorkTime(workTime); } CResume* clone() { // 呼叫拷貝建構函式 淺拷貝 CResume* resume = new CResume(*this); return resume; } void printInfo() { cout << "Name: " << m_name << endl; cout << "Sex: " << m_sex << endl; cout << "Age: " << m_age << endl; cout << "Experience: " << endl; m_experience->printInfo(); cout << endl; } protected: string m_name; string m_sex; int m_age; CWorkExperience* m_experience;// 指標 聚合 }; void testPrototype() { CWorkExperience* pWorkExperience = new CWorkExperience("MS", "2001.11 - 2005.11"); CResume re(pWorkExperience); // 只能這樣構造 無參構造被遮蔽掉了 re.setInfo("Jacky", "Male", 20); re.printInfo(); CResume* pClone = re.clone(); // 指標賦值 淺拷貝 //delete pWorkExperience; // 這裡如果呼叫delete 程式會崩潰(因為是共享) pClone->setInfo("Marry", "Female", 30); pClone->setExperience("Google", "2006.01 - 2010.01"); pClone->printInfo(); re.printInfo(); // 我們發現原物件的workExperience屬性已經被修改 delete pClone; delete pWorkExperience; pClone = NULL; pWorkExperience = NULL; } int main(void) { testPrototype(); return 0; }
執行結果如下:
將146行取消註釋 程式崩潰。
執行圖如下:(圖片請在新視窗中檢視)
接下來一篇文章解決指標共享的深度拷貝版本。