C/C++编程日记:将不同类型的对象放进同一个容器

475 阅读4分钟

前言:不同类型的对象,放进同一个容器。(下文以数组表示容器)

代理类

问题:

现有不同种类的交通工具类派生层次,如下:

![](https://upload-images.jianshu.io/upload_images/24762785-d7a9356b71790e1b.jpg?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)

classVehicle{public:virtualdoubleweight()const=0;virtualvoidstart()=0;};classAircraft:publicVehicle {};classAutomobile:publicVehicle {};

我们想对一系列不同各类的Vehicle进行管理:

Vehicle parking_lot[1000];

不足:

抽象类不可实例化

若基类不是抽象类,类型转换会带来问题

![](https://upload-images.jianshu.io/upload_images/24762785-2a10fbc205e18407.jpg?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)

经典解决方法:容器中存储基类指针

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;virtualVehiclecopy()const=0;virtual~Vehicle() {}};classAircraft:publicVehicle {public:Vehiclecopy()const{returnnewAircraft(this); }};classAutomobile:publicVehicle {public:Vehiclecopy()const{returnnewAutomobile(*this); }};

直接调用copy(),不需要知道x的静态类型

Vehicle* parking_lot[1000];Automobile x;parking_lot[0] = x.copy();

引入代理类

我们引入代理类来避免显式的内存分配。

![](https://upload-images.jianshu.io/upload_images/24762785-dc0e9a6f19600d17.jpg?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)

一个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); }returnthis; } ~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进行判空。

如果你在学习C/C++的过程中遇到了问题,可以来加入小编的企鹅圈问小编哦~小编很热情的(●’◡’●)

现在我们管理一系列的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;virtualVehiclecopy()const=0;virtual~Vehicle() {}};classAircraft:publicVehicle {public:Vehiclecopy()const{returnnewAircraft(this); }};classAutomobile:publicVehicle {public:Vehiclecopy()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); }returnthis; } ~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就方便多了:

![](https://upload-images.jianshu.io/upload_images/24762785-ea5fa632aa563877.jpg?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)

VehicleSurrogate parking_lot[10];Automobile x;parking_lot[0] = x;

最后一行会调用VehicleSurrogate(const Vehicle& v)完成x从Automobile到VehicleSurrogate的类型转换,而且会创建x的副本。

我们不需要考虑数组中的副本释放问题,VehicleSurrogate的析构函数会帮我们做好。