代理类和虚复制函数

来源:互联网 发布:淘宝手游代充的秘密 编辑:程序博客网 时间:2024/05/29 11:05

假设我们要创建一个停车场 里面有各种类型的车辆 都继承自Vehicle

1.       虚复制函数:

1)为什么我们需要虚复制函数?

假设我们有一个表示不同种类的交通工具的类派生层次:

class Vehicle{

public:

       visual double Weight() const=0;

       visual void start() =0;

}

 

class RoadVehicle:public Vehicle{/*….*/};

class AutoVehicle:public RoadVehicle{/*…*/};

class Aircraft:public Vehicle{/*….*/};

class Helicopter:public Aircraft{/*….*/};

 

所有这些类当中都有Vehicle类所共有的属性与方法 但其子类有Vehicle所没有的

属性,方法 比如Aircraft能飞等。

假设我们要处理一些列不同种类的Vehicle 比如我们定义一个对象数组:

Vehicle parking_lot[100];

这里显然是错误的 应为Vehicle是抽象类(含有纯虚函数) 不能实例化对象

即便Vehicle能实例化 这如下操作:

Vehicle parking_lot[100];

Automobile x=/*….*/;

Parking_lot[[num_Vehicle]=x;

也会出现问题 X中含有Vehicle所没有的属性时  会造成数据丢失

 

或许我们可以这样解决:

Vehicle *parking_lot[100];

然后输入类似:

Automobile x=/*….*/;

Parking_lot[num_Vehicle]=&x;

但也会有如下问题:

X是局部变量 一旦X没有了 parking_lot 就不知道指向了什么东西了;

我们可以这样做:

放入parking_lot中的值  不是只想原对象的指针 而是指向他们副本的指针。

然后 才用一个约定 就是当 释放parking_lot 也释放其中所指向的全部对象

上面的语句可以改为:

Automobile X=/*…*/

Parking_lot[num_vehicles]=new Atuomobile(x);//拷贝构造函数

这样也存在问题 增加了 1.动态内存管理的负担  2.只有我们知道要放到parking_lot中的对象是静态对象后 这种方法才起作用 :

我们想让parking_lot[p]指向一个已存在的parking_lot[q]的对象

我们不能这么做

If(p!=q){

    Delete parking_lot[p];

    Parking_lot[p]=parking_lot[q];

}

因为这样做会使 pq指向相同的对象(同一块类存地址) ;

我们也不能这样做 :

If(p!=q){

    Delete parking_lot[p];

    Parking_lot[p]=new Vehicle(parking_lot[q]);

}

因为Vehicle不能实例化,即便能,可能也不是我们想要的(可能 parking_lot[q]是一个Aircraft类的对象等…)

 

2)虚复制函数的实现

虚复制函数可以再编译时复制(显然是动态的)类型未知的对象,我们知道,C++中处理类型未知的对象的方法是使用虚函数,由于我们想复制任何类型的Vehicle的对象,所以我们在Vehicle中增加一个纯虚函数Copy()

假设我们有一个表示不同种类的交通工具的类派生层次:

class Vehicle{

public:

       visual double Weight() const=0;

       visual void start() =0;

       visual Vehicle * Copy() const=0;

};

接下来 在每个继承自Vehicle类的类中 添加Copy函数的,指导思想是,如果Vp指向某个继承自Vehicle类的对象,则Vp->copy会获得一个指针,指向该对象的一个新建的副本,例如,如果Truck继承自(直接或间接继承)Vehicle,则他的Copy函数形如:

Vehicle * Truck::Copy() const{

       return new Truck(*this);

}

这里 处理完一个对象后,需要清楚该对象,要做到这一点,Vehicle类应该有一个虚析构函数:

class Vehicle{

public:

       visual double Weight() const=0;

       visual void start() =0;

       visual Vehicle * Copy() const=0;

       visual ~Vehicle(){ }

//……

};

 

 

2.代理类

代理类:定义一个行为和Vehicle对象相似,而又潜在的表示了所有继承自Vehicle类的对象的东西。我们把这个类的对象叫做代理(surrogate)。

每个Vehicle代理都代表某个继承自Vehicle的对象,只要该代理关联着该对象,该对象就一定存在。因此,复制代理就会复制相应的对象,而给代理赋新值也会先删除旧对象,再复制新对象:

Class VehicleSurrogate{

Public:

       VehicleSurrogate();

       VehicleSurrogate(const Vehicle&);

       ~ VehicleSurrogate();

       VehicleSurrogate(const VehicleSurrogate&);

       VehicleSurrogate &operator=(const VehicleSurrogate&);

       //来自Vehicle类的操作

       double Weight() const;

       void start() //这里不是虚函数 我们要创建代理类的对象

//;

 

Provate:

       Vehicle *vp;

}

 

下面是个函数实现:

VehicleSurrogate:: VehicleSurrogate() :vp(0){}//空参数构造函数 VP0

 

VehicleSurrogate:: VehicleSurrogate(const Vehicle &v): vp(v.copy()){}

//传入Vehicle对象的构造函数 调用对象类的Copy函数将VP置为对应类的对象

 

VehicleSurrogate:: ~VehicleSurrogate(){

Delete vp;//删除 Vehicle对象VP

}

VehicleSurrogate:: VehicleSurrogate(const VehicleSurrogate& v){

ifv.vp=0{

       this.vp=v.vp->Copy();

}//传入VehicleSurrogate对象的构造函数 如果该对象的VP不为0,则给VP赋值,

//调用对象类的Copy函数将VP置为对应类的对象

}

 

VehicleSurrogate &  VehicleSurrogate ::operator=(const VehicleSurrogate& v){

       if(this!=&v){

delete vp

vp=v.vp?v.vp->copy():0);//这里和上面一样

}

return  *this;

}

//重载操作符 =

 

这样 我们 就可以很容易的实现停车场了 :

VehicleSurrogate parking_lot[100];

Automoblie x

VehicleSurrogate parking_lot[num_Vehicle]=x;

由于重载了运算符 =’这里相当于VehicleSurrogate parking_lot[num_Vehicle]= VehicleSurrogate(x);这条语句创建了X的副本,并将VehicleSurrogate对象绑定到该副本,然后赋值给parking_lot的一个元素。当最后销毁parking_lot数组时,该对象也销毁了。

 

原创粉丝点击