原型模式:使用原型实例来指定创建对象的种类,并通过拷贝这个对象的值来创建新的对象。
Specify the kind of objects to create using a prototypical instance, and create new objects by copying this prototype.
UML图:
主要包括
其它语言针对上面的克隆有专门的函数,但是C++好像没有。针对上面的克隆函数,C++中可以通过拷贝构造函数来实现。而拷贝构造函数又涉及到了浅拷贝和深拷贝的问题。
先看看浅拷贝的克隆模式的C++代码实现:
#include <iostream>
#include <string>
using namespace std;
class Prototype
{
public:
Prototype(string str=""):id(str)
{
}
//对C++而言需要返回指针
virtual Prototype * clone()=0;
string getId() const
{
return id;
}
private:
string id;
};
class ConcretePrototype1:public Prototype
{
public:
ConcretePrototype1(string str=""):Prototype(str)
{
}
Prototype * clone()
{
std::cout<<"ConcretePrototype1::clone()"<<std::endl;
return new ConcretePrototype1(*this);
}
};
class ConcretePrototype2:public Prototype
{
public:
ConcretePrototype2(string str=""):Prototype(str)
{
}
Prototype * clone()
{
std::cout<<"ConcretePrototype2::clone()"<<std::endl;
return new ConcretePrototype2(*this);
}
};
int main()
{
std::cout<<"原型模式测试"<<std::endl;
ConcretePrototype1* cp1=new ConcretePrototype1("001");
ConcretePrototype1* cp11=dynamic_cast<ConcretePrototype1 *>(cp1->clone());
ConcretePrototype2* cp2=new ConcretePrototype2("002");
ConcretePrototype2* cp22=dynamic_cast<ConcretePrototype2 *>(cp2->clone());
delete cp1;
delete cp11;
delete cp2;
delete cp22;
return 0;
}
执行代码如下:
但是当代码中有自定义类型的指针成员变量时需要注意一个浅拷贝和深拷贝的问题,这个问题的实质是C++中的拷贝构造函数只是执行简单的按位复制操作(即浅拷贝),当成员变量中含有指针类型的数据时,它也只是简单的复制一下指针的值,不会复制一份指针所指向的内存(深拷贝)。
考虑下面的代码:
这对代码最后输出对象cp1和cp11更改前后的三项信息:
可以发现更改cp11中成员变量data的name字段后cp1中的成员变量data的name字段也发生了变化,这是由于data指向的是同一块内存区域,根据它们的地址信息可以很直观的看出这一点。
#include <iostream>
#include <string>
#include <stdlib.h>
#include <stdio.h>
using namespace std;
class Data
{
public:
Data(string n,string i):name(n),info(i)
{
}
string name;
string info;
};
class Prototype
{
public:
Prototype()
{
}
Prototype(char *point):pChar(point)
{
}
//对C++而言需要返回指针
virtual Prototype * clone()=0;
char * getPchar() const
{
return pChar;
}
void setPchar(char * ch)
{
pChar=ch;
}
Data * getData() const
{
return data;
}
void setData(Data *d)
{
data=d;
}
private:
char * pChar;
Data * data;
};
class ConcretePrototype1:public Prototype
{
public:
ConcretePrototype1()
{
}
ConcretePrototype1(char * point):Prototype(point)
{
}
Prototype * clone()
{
std::cout<<"ConcretePrototype1::clone()"<<std::endl;
return new ConcretePrototype1(*this);
}
};
int main()
{
std::cout<<"原型模式测试"<<std::endl;
char p1[]="hello";
char p2[]="world";
Data data1("Bill","Microsofe");
ConcretePrototype1* cp1=new ConcretePrototype1(p1);
cp1->setData(&data1);
ConcretePrototype1* cp11=dynamic_cast<ConcretePrototype1 *>(cp1->clone());
std::cout<<"cp1 information:------------------"<<std::endl;
printf("cp1->pChar address:%p\n",cp1->getPchar());
printf("cp1->data address:%p\n",cp1->getData());
std::cout<<"cp1->data->name:"<<cp1->getData()->name<<" cp1->data->info "<<cp1->getData()->info<<std::endl;
std::cout<<"cp11 information:------------------"<<std::endl;
printf("cp11->pChar address:%p\n",cp11->getPchar());
printf("cp11->data address:%p\n",cp11->getData());
std::cout<<"cp11->data->name:"<<cp11->getData()->name<<" cp11->data->info "<<cp11->getData()->info<<std::endl;
cp11->setPchar(p2);
cp11->getData()->name="change to John";
std::cout<<"cp11 change:----------------"<<std::endl;
std::cout<<"cp1 information:------------------"<<std::endl;
printf("cp1->pChar address:%p\n",cp1->getPchar());
printf("cp1->data address:%p\n",cp1->getData());
std::cout<<"cp1->data->name:"<<cp1->getData()->name<<" cp1->data->info "<<cp1->getData()->info<<std::endl;
std::cout<<"cp11 information:------------------"<<std::endl;
printf("cp11->pChar address:%p\n",cp11->getPchar());
printf("cp11->data address:%p\n",cp11->getData());
std::cout<<"cp11->data->name:"<<cp11->getData()->name<<" cp11->data->info "<<cp11->getData()->info<<std::endl;
delete cp1;
delete cp11;
return 0;
}
输出信息:
针对上面的问题需要使用C++中的深拷贝,即自己重新定义拷贝构造函数:
#include <iostream>
#include <string>
#include <stdlib.h>
#include <stdio.h>
using namespace std;
class Data
{
public:
Data()
{
}
Data(string n,string i):name(n),info(i)
{
}
string name;
string info;
};
class Prototype
{
public:
Prototype()
{
}
Prototype(char *point):pChar(point)
{
}
Prototype(const Prototype& rhs)
{
//下面这条代码是关键,又重新分配了一块内存区域
data=new Data(*rhs.getData());
pChar=rhs.getPchar();
}
//对C++而言需要返回指针
virtual Prototype * clone()=0;
char * getPchar() const
{
return pChar;
}
void setPchar(char * ch)
{
pChar=ch;
}
Data * getData() const
{
return data;
}
void setData(Data *d)
{
data=d;
}
private:
char * pChar;
Data * data;
};
class ConcretePrototype1:public Prototype
{
public:
ConcretePrototype1()
{
}
ConcretePrototype1(char * point):Prototype(point)
{
}
ConcretePrototype1(const ConcretePrototype1 & rhs):Prototype(rhs)
{
}
Prototype * clone()
{
std::cout<<"ConcretePrototype1::clone()"<<std::endl;
return new ConcretePrototype1(*this);
}
};
int main()
{
std::cout<<"原型模式测试"<<std::endl;
char p1[]="hello";
char p2[]="world";
Data data1("Bill","Microsofe");
ConcretePrototype1* cp1=new ConcretePrototype1(p1);
cp1->setData(&data1);
ConcretePrototype1* cp11=dynamic_cast<ConcretePrototype1 *>(cp1->clone());
std::cout<<"cp1 information:------------------"<<std::endl;
printf("cp1->pChar address:%p\n",cp1->getPchar());
printf("cp1->data address:%p\n",cp1->getData());
std::cout<<"cp1->data->name:"<<cp1->getData()->name<<" cp1->data->info "<<cp1->getData()->info<<std::endl;
std::cout<<"cp11 information:------------------"<<std::endl;
printf("cp11->pChar address:%p\n",cp11->getPchar());
printf("cp11->data address:%p\n",cp11->getData());
std::cout<<"cp11->data->name:"<<cp11->getData()->name<<" cp11->data->info "<<cp11->getData()->info<<std::endl;
cp11->setPchar(p2);
cp11->getData()->name="change to John";
std::cout<<"cp11 change:----------------"<<std::endl;
std::cout<<"cp1 information:------------------"<<std::endl;
printf("cp1->pChar address:%p\n",cp1->getPchar());
printf("cp1->data address:%p\n",cp1->getData());
std::cout<<"cp1->data->name:"<<cp1->getData()->name<<" cp1->data->info "<<cp1->getData()->info<<std::endl;
std::cout<<"cp11 information:------------------"<<std::endl;
printf("cp11->pChar address:%p\n",cp11->getPchar());
printf("cp11->data address:%p\n",cp11->getData());
std::cout<<"cp11->data->name:"<<cp11->getData()->name<<" cp11->data->info "<<cp11->getData()->info<<std::endl;
delete cp1;
delete cp11;
return 0;
}
执行代码如下,可以发现在克隆时cp1和cp11中data成员变量的地址就不一样了,这样更改cp11中的data成员后cp1中的data成员没有发生变化,这就是深拷贝了。
原文地址:http://blog.csdn.net/u012501459/article/details/46383025