問題描述:如何設計一個容器,能使得它能包含類型不同但是彼此相關的對象?
問題描述:如何復制編譯時類型未知的對象?
解決方案一:使用容器存儲指向對象的指針,通過繼承來處理類型不同的對象。
這個方案有嚴重的問題:
問題一:無法讓容器中的指針指向一個局部變量,例如:
Vehicle * parking_lot[1000];
Automobile x = /*..*/
Parking_lot[num_vehicles++] = &x;
一旦x不存在了,Parking_lot就不知道指向哪裡了。
我們可以變通一下,讓放入Parking_lot的值,指向原來對象的副本,而不直接存放原來對象的地址,例如:
Parking_lot[num_vehicles++]= new Automobile(x);
這個改進方案又帶來一個問題,那就是我們必須知道x的靜態類型。假如我們想讓parking_lot[p]指向的Vehicle的類型和值與parking_lot[q]指向的對象相同,那在我們無法得知parking_lot[q]的靜態類型的情況下,我們無法做到這點。
解決方案二(方案一的改進):增加虛擬復制函數來復制編譯時類型未知的對象,代碼描述如下
class Vehicle
{
public:
virtual Vehicle * copy() const = 0;
/**/
};//Vehicle的派生類都自實現copy函數
class Truck : public RoadVehicle
{
public:
Vehicle* copy() const { return new Truck(*this); }
/**/
};
假如我們想讓parking_lot[p]指向的Vehicle的類型和值與parking_lot[q]指向的對象相同,可以簡單是使用如下代碼:parking_lot[p] =parking_lot[q].copy();
解決方案三(與方案二作用類似,但實現手段有不同):使用代理類
代理類:行為與原類相似,又潛在的表示了所有繼承自原類的類
Vehicle類的代理類VehicleSurrogate的描述如下:
class VehicleSurrogate
{
public:
VehicleSurrogate() : vp(NULL) {};
VehicleSurrogate(const Vehicle& v) : vp(v.copy()) {};
~VehicleSurrogate() {};
VehicleSurrogate(const VehicleSurrogate& v) : vp(v.vp ? v.vp->copy() : NULL) {}; //v.vp非零檢測
VehicleSurrogate& operator=(const VehicleSurrogate& v)
{
if (this != &v) // 確保沒有將代理賦值給它自身
{
delete vp;
vp = (v.vp ? v.vp->copy() : NULL);
}
return *this;
};
//來自類Vehicle的操作
void start()
{
if (vp == 0)
throw "empty VehicleSurrogate.start()";
vp->start();
};
private:
Vehicle* vp;
};
完成了這些工作後,就很容易定義我們所需要的操作了,如下:
VehicleSurrogate parking_lot[1000];
Automobile x = /*..*/
Parking_lot[num_vehicles++] = x;
//Parking_lot[num_vehicles++] = VehicleSurrogate(x);//此語句與上條語句作用一致
/*...*/
Parking_lot[p] = Parking_lot[q];
作者 yucan1001