设计模式之 原型模式(prototype)(C++实现 深拷贝 + 浅拷贝版本[bug])

时间:2021-12-09 07:01:24

本文介绍设计模式中的原型模式。


本质上其实就是克隆。


下面以个人简历为例进行举例说明:


深拷贝版本:

#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;
}

运行结果如下:

设计模式之 原型模式(prototype)(C++实现 深拷贝 + 浅拷贝版本[bug])

浅拷贝版本:

#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;
}

运行结果如下:

设计模式之 原型模式(prototype)(C++实现 深拷贝 + 浅拷贝版本[bug])


将146行取消注释 程序崩溃。

运行图如下:(图片请在新窗口中查看)

设计模式之 原型模式(prototype)(C++实现 深拷贝 + 浅拷贝版本[bug])


接下来一篇文章解决指针共享的深度拷贝版本。