C++代理类

前言

本次读书笔记为C++沉思录第五章, 介绍的是代理类, 代理类是句柄类的一种, 较为简单

代理类并不局限于C++语言, 是一种广泛的编程思想

面临的问题

C++通过虚函数来实现的运行时多态, 但是我们在构建一个容器存储时(不管是内建类型还是自定义类型容器)只能获得编译时类型一致的元素值.

例如:std::vector<T>, 我们声明一个存储 T 类型的 vector, 但是有时实际中我们拥有很多继承于同一基类的派生类对象, 若是容器中只能包含相同类型的元素, 我们就无法在该容器中包含同一个基类不同派生类对象了

而我们能想到的一个经典办法就是: 存储指针; 不过存储指针必然伴随着内存管理的问题, 即如何得知指针指向的对象是否还存在

那么我们现在面临的问题就是: 当我们将继承和容器共用时, 要管理内存分配和把不同类型对象放入同一容器

解决办法

所谓计算机领域的任何问题, 都能通过增加一个中间层来解决

代理类

代理类(surrogate)就是做这样的工作: 让我们忽略正在处理的对象的准确类型.

代理类是句柄(handle)类中最简单的一种

现有如下例子:

1
2
3
4
5
6
7
8
9
10
11
12
class Vehicle 	//基类
{
public:
virtual double weight() const = 0;
virtual void start() = 0;
// ...
};
//派生类
class RoadVehicle : public Vehicle{ / * ... */ };
class AutoVehicle : public RoadVehicle{ /* ... */};
class Aircraft : public Vehicle { / * ... */};
class Helicopter : public Aircraft { / * ... */};

首先, 我们给基类和所有派生类增加copy接口, 返回对应的确切类型

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
class Vehicle
{
public:
virtual Vehicle * copy() const = 0;
/**/
}; //Vehicle的派生类都自实现copy函数

class Truck : public Vehicle
{
public:
Vehicle* copy() const
{
return new Truck(*this);
}
/**/
};

//同时也该增加一个虚析构函数:
class Vehicle
{
public:
virtual double weight() const = 0;
virtual void start() = 0;
virtual Vehicle * copy() const = 0;
virtual ~Vehicle() {}
// ...
};

代理类:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
class VehicleSurrogate
{
public:
VehicleSurrogate() //缺省构造函数空代理
: vp(NULL) {};
VehicleSurrogate(const Vehicle& v) //针对所有继承自Vehicle的派生类
: 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();
};
double weight() const
{
if(vp == 0)
throw "empty VehcileSurrogate.weight()";
return vp->weight();
}

private:
  Vehicle* vp;
};

总结

代理类很好理解, 就是一种管理句柄的句柄类, 提供了一个中间层, 让所有子类自定义了一个 copy 函数, 返回自身的复制, 代理类中有一个基类指针保存子类

返回自身的复制? 这听起来在某些时候行不通, 可能是因为复制代价太大或者根本就无法复制, 解决办法就是本书下一章节介绍的句柄类(也就是shared_ptr, 智能指针不仅仅是 shared_ptr, 其他的智能指针和句柄类并不相同)


该章介绍的代理类很好理解, 需要掌握的是这种编程思想

0%