1、作用
原型模式可以用指向基类的子类指针指针或者引用,拷贝出子类对象。拷贝构造函数只能用子类的对象拷贝构造子类对象。使用原型模式的目的是实现多态,根据指针指向的类型实现动态拷贝。
2、实现方式
原型模式的重点是在基类中定义了一个clone的虚函数,在子类中重写clone函数,且每个clone函数调用当前类的拷贝构造函数,这样就能实现动态拷贝,即指向基类的子类指针通过调用clone函数,能够拷贝子类的数据域。
3、C++代码
Animal.h
#include <string> #include <iostream> #ifndef ANIMAL__H #define ANIMAL__H class Animal { public: Animal() = default; Animal(const std::string &n):name(n) {std::cout<<"Animal()"<<std::endl; } Animal(const Animal &a) :name(a.name) {std::cout<<"Animal(Animal &a)"<<std::endl;} virtual Animal *clone(); virtual ~Animal() { std::cout<<"~Animal()"<<std::endl; } virtual std::string &getName() {return name;} protected: std::string name; }; #endif
Animal.cc
#include "Animal.h" Animal *Animal::clone() { std::cout<<"Animal::clone()"<<std::endl; return new Animal(*this); }
Rabbit.h
#include "Animal.h" #include <iostream> #include <vector> #include <string> #ifndef RABBIT__H #define RABBIT__H class Rabbit:public Animal { public: Rabbit(const std::string &n); Rabbit(Rabbit &r); ~Rabbit(); void addFood(const std::string &f) { food->push_back(f); } std::vector<std::string> *getFood() { return food; } virtual Animal *clone() override; private: std::vector<std::string> *food = nullptr; }; #endif
Rabbit.cc
#include "Rabbit.h" Rabbit::Rabbit(const std::string &n): Animal(n) , food(new std::vector<std::string>){ std::cout<<"Rabbit()"<<std::endl; } Rabbit::Rabbit(Rabbit &r):Animal(r), food(new std::vector<std::string>){ for(const auto &v : *(r.food)) food->push_back(v); std::cout<<"Rabbit(&Rabbit)"<<std::endl; } Animal *Rabbit::clone() { std::cout<<"clone()"<<std::endl; return new Rabbit(*this); } Rabbit::~Rabbit() { std::cout<<"~Rabbit()"<<std::endl; delete food; }
test.cc
#include <iostream> #include "Rabbit.h" #include <iomanip> using namespace std; int main() { Rabbit r("hehe"); r.addFood("cabbage"); Rabbit r1(r); r1.addFood("radish"); Animal *a = &r1; Animal *b = a->clone(); std::cout<<"---------------------"<<endl; std::cout<<"name:"<<b->getName()<<endl; std::cout<<"foods:"<<endl; for(const auto &v : *(static_cast<Rabbit*>(b)->getFood())) { std::cout<<right<<setw(12)<<v<<endl; } std::cout<<"---------------------"<<endl
}
输出:
Animal() Rabbit() Animal(Animal &a) Rabbit(&Rabbit) clone() Animal(Animal &a) Rabbit(&Rabbit) --------------------- name:hehe foods: cabbage radish --------------------- ~Rabbit() ~Animal() ~Rabbit() ~Animal()