假设我们要创建一个停车场 里面有各种类型的车辆 都继承自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];
}
因为这样做会使 p,q指向相同的对象(同一块类存地址) ;
我们也不能这样做 :
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){}//空参数构造函数 将VP置0
VehicleSurrogate:: VehicleSurrogate(const Vehicle &v): vp(v.copy()){}
//传入Vehicle对象的构造函数 调用对象类的Copy函数将VP置为对应类的对象
VehicleSurrogate:: ~VehicleSurrogate(){
Delete vp;//删除 Vehicle对象VP
}
VehicleSurrogate:: VehicleSurrogate(const VehicleSurrogate& v){
if(v.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数组时,该对象也销毁了。