C++沉思录读书笔记(一)代理类
代理类的每一个对象都代表另一个对象,该对象可以是位于一个完整继承层次中的任何类的对象。通过在容器中用代理类而不是对象本身可以解决控制内存分配和把不同类型的对象放在同一个容器中这两个问题
********
问题
********
抽象基类Vehicle包含成员
double weight() const
void start()
以下4个类从Vehicle派生,每个类另有自己的独特的成员,比如Aircraft包含成员 void fly()
RoadVehicle
AutoVehicle
Aircraft
Helicopter
设计一个C++容器,它有能力包含类型不同而彼此相关的对象
将整个派生层次压缩在一个对象类型中
********
解决方案
********
@方案1:数组存储基类对象
Vehicle parking_lot[1000];
@潜在问题:
1. 抽象基类无法实例化
2. 即使基类不是抽象类,存储派生类对象也会造成对象被剪裁
@方案2:数组存储基类指针
Vehicle* parking_lot[1000];
@潜在问题:
1. 存储的对象都有各自的生存期
@方案3:数组存储指向对象副本的指针
对象副本的生存期由数组决定,释放数组时也释放其中指向的全部对象
@潜在问题:
带来动态内存管理的负担
放入数组的对象只能是静态类型,如果想让parking_lot[p]指向一个新建的对象,这个对象的实际类型和parking_lot[q]指向的对象相同,则无法创建出这个对象(不使用RTTI)
@方案4:数组存储指向对象副本的指针,为派生层次添加虚复制函数
Virtual Vehicle* copy() const = 0; //基类
Vehicle* Aircraft::copy() const //派生类
{
return new Aircraft(*this);
}
还必须为派生层次添加虚析构函数
@潜在问题:
显式处理内存分配
@方案5:代理类
定义一个行为和Vehicle对象相似,又潜在的表示所有继承自Vehicle类的对象
class VehicleSurrogate {
public:
VehicleSurrogate(); //可以创建VehicleSurrogate对象的数组
VehicleSurrogate(const Vehicle&); //由任意继承自Vehicle的对象创建代理
~Vehiclesurrogate();
VehicleSurrogate(const VehicleSurrogate&);
VehicleSurrogate& operator= (const VehicleSurrogate&);
private:
Vehicle* vp;
public: //来自Vehicle的操作
double weight() const;
void start();
}
VehicleSurrogate::VehicleSurrogate():vp(0) {} //可以生成空代理(empty surrogate)
VehicleSurrogate::VehicleSurrogate(const Vehicle& v):vp(v.copy()) {}
VehicleSurrogate::~VehicleSurrogate() { delete vp; }
VehicleSurrogate::VehicleSurrogate(const VehicleSurrogate&v):vp( v.vp?v.vp->copy():0 ) {}
VehicleSurrogate&
VehicleSurrogate::operator=(const VehicleSurrogate& v)
{
if (this != &v) { //防止将代理复制给自身
delete vp;
vp = (v.vp?v.vp->copy():0);
}
return *this;
}
//来自Vehicle的操作
double VehicleSurrogate::weight() const
{
if(0 == vp)
throw "empty VehicleSurrogate.weight()";
return vp->weight();
}
void VehicleSurrogate::start()
{
if(0 == vp)
throw "empty VehicleSurrogate.start()";
vp->start();
}
*空代理:行为类似于零指针,可以创建、销毁和复制这样的代理,但是其他操作被视为出错
使用代理类
VehicleSurrogate parking_lot[1000];
Aircraft x;
parking_lot[0] = x;