前言:不同类型的对象,放进同一个容器。(下文以数组表示容器)
代理类
问题:
现有不同种类的交通工具类派生层次,如下:
![986bd32e8078c1450a4da1edb6ece47a.png](https://i-blog.csdnimg.cn/blog_migrate/52f27b87ed7c8f1bc2d76e23be3f24d6.jpeg)
classVehicle{public:virtualdoubleweight()const=0;virtualvoidstart()=0;};classAircraft:publicVehicle {};classAutomobile:publicVehicle {};
我们想对一系列不同各类的Vehicle进行管理:
Vehicle parking_lot[1000];
不足:
抽象类不可实例化
若基类不是抽象类,类型转换会带来问题
![99c10866951389fd01ed70c2bd64a05e.png](https://i-blog.csdnimg.cn/blog_migrate/4118cc5f075571a014e6cd0b119293dc.jpeg)
经典解决方法:容器中存储基类指针
Vehicle* parking_lot[1000];Automobile x;parking_lot[0] = &x;
不足:
内存管理的负担
若容器中的指针在其它地方被释放,会造成大量野指针
经典解决方法的改进:容器中的指针指向原对象的副本。
Vehicle* parking_lot[1000];Automobile x;parking_lot[0] =newAutomobile(x);
不足:
动态内存管理的负担
需要知道对象x的静态类型
再次改进:虚复制函数
classVehicle{public:virtualdoubleweight()const=0;virtualvoidstart()=0;virtualVehicle*copy()const=0;virtual~Vehicle() {}};classAircraft:publicVehicle {public:Vehicle*copy()const{returnnewAircraft(*this); }};classAutomobile:publicVehicle {public:Vehicle*copy()const{returnnewAutomobile(*this); }};
直接调用copy(),不需要知道x的静态类型
Vehicle* parking_lot[1000];Automobile x;parking_lot[0] = x.copy();
引入代理类
我们引入代理类来避免显式的内存分配。
![ab7e6db46fbe2c4915703d05ce418561.png](https://i-blog.csdnimg.cn/blog_migrate/397cf44b1aba06d289325c426df35ed6.jpeg)
一个Vehicle代理代表着一个继承自Vehicle的对象,只要该代理关联着该对象,该对象就一定存在。因此,复制该代理就会复制该对象。给代理赋新值也会先删除旧对象,再复制新对象。
classVehicleSurrogate{public:VehicleSurrogate() : vp(0) {}// 注意这个缺省构造,我们需要定义一个“空代理”的概念,类似零指针VehicleSurrogate(constVehicle& v) : vp(v.copy()) {}VehicleSurrogate(constVehicleSurrogate& v) : vp(v.vp ? v.vp->copy() :0) {}VehicleSurrogate&operator=(constVehicleSurrogate& v) {if(this!= &v) {deletevp;vp = (v.vp ? v.vp->copy() :0); }return*this; } ~VehicleSurrogate() {deletevp; }doubleweight()const{if(vp ==0)throw"vp == 0"; vp->weight(); }voidstart(){if(vp ==0)throw"vp == 0"; vp->start(); }private: Vehicle* vp;};
需要注意的是,调用vp的成员函数前需要对vp进行判空。
![1a3d30f6409a58a285d4a5681ee74cb7.gif](https://i-blog.csdnimg.cn/blog_migrate/75d9db78bc656b78d486d51b168534be.gif)
现在我们管理一系列的Vehicle就方便多了:
VehicleSurrogate parking_lot[10];Automobile x;parking_lot[0] = x;
最后一行会调用VehicleSurrogate(const Vehicle& v)完成x从Automobile到VehicleSurrogate的类型转换,而且会创建x的副本。
我们不需要考虑数组中的副本释放问题,VehicleSurrogate的析构函数会帮我们做好。不同类型的对象,放进同一个容器。(下文以数组表示容器)
代理类
问题:
现有不同种类的交通工具类派生层次,如下:
classVehicle{public:virtualdoubleweight()const=0;virtualvoidstart()=0;};classAircraft:publicVehicle {};classAutomobile:publicVehicle {};
我们想对一系列不同各类的Vehicle进行管理:
Vehicle parking_lot[1000];
不足:
抽象类不可实例化
若基类不是抽象类,类型转换会带来问题
经典解决方法:容器中存储基类指针
Vehicle* parking_lot[1000];Automobile x;parking_lot[0] = &x;
不足:
内存管理的负担
若容器中的指针在其它地方被释放,会造成大量野指针
经典解决方法的改进:容器中的指针指向原对象的副本。
Vehicle* parking_lot[1000];Automobile x;parking_lot[0] =newAutomobile(x);
不足:
动态内存管理的负担
需要知道对象x的静态类型
再次改进:虚复制函数
classVehicle{public:virtualdoubleweight()const=0;virtualvoidstart()=0;virtualVehicle*copy()const=0;virtual~Vehicle() {}};classAircraft:publicVehicle {public:Vehicle*copy()const{returnnewAircraft(*this); }};classAutomobile:publicVehicle {public:Vehicle*copy()const{returnnewAutomobile(*this); }};
直接调用copy(),不需要知道x的静态类型
Vehicle* parking_lot[1000];Automobile x;parking_lot[0] = x.copy();
引入代理类
我们引入代理类来避免显式的内存分配。
一个Vehicle代理代表着一个继承自Vehicle的对象,只要该代理关联着该对象,该对象就一定存在。因此,复制该代理就会复制该对象。给代理赋新值也会先删除旧对象,再复制新对象。
classVehicleSurrogate{public:VehicleSurrogate() : vp(0) {}// 注意这个缺省构造,我们需要定义一个“空代理”的概念,类似零指针VehicleSurrogate(constVehicle& v) : vp(v.copy()) {}VehicleSurrogate(constVehicleSurrogate& v) : vp(v.vp ? v.vp->copy() :0) {}VehicleSurrogate&operator=(constVehicleSurrogate& v) {if(this!= &v) {deletevp;vp = (v.vp ? v.vp->copy() :0); }return*this; } ~VehicleSurrogate() {deletevp; }doubleweight()const{if(vp ==0)throw"vp == 0"; vp->weight(); }voidstart(){if(vp ==0)throw"vp == 0"; vp->start(); }private: Vehicle* vp;};
需要注意的是,调用vp的成员函数前需要对vp进行判空。
现在我们管理一系列的Vehicle就方便多了:
![2ec23b7cacbdc5b2e13fac45f8293b40.png](https://i-blog.csdnimg.cn/blog_migrate/2eea44bfce669929e90fa3818e879f23.jpeg)
VehicleSurrogate parking_lot[10];Automobile x;parking_lot[0] = x;
最后一行会调用VehicleSurrogate(const Vehicle& v)完成x从Automobile到VehicleSurrogate的类型转换,而且会创建x的副本。
我们不需要考虑数组中的副本释放问题,VehicleSurrogate的析构函数会帮我们做好。