30 Proxy class(替身类,代理类):
1. 所谓代理类(proxy class),指的是"它的每一个对象都是为了其他对象而存在的,就像是其他对象的代理人一般".某些情况下用代理类取代某些内置类型可以实现独特的功能,因为可以为代理类定义成员函数而但却无法对内置类型定义操作.条款5就展示了一个使用代理类阻止隐式类型转换的例子.
2. 实现二维数组.
C++没有提供分配动态二维数组的语法,因此常常需要定义一些类(模板实现这些功能),像这样:
template<class T>
class Array2D
{
public:
Array2D(int dim1, int dim2);
...
};
既然是二维数组,那么有必要提供使用"[][]"访问元素的操作,然而[][]并不是一个操作符,C++也就不允许重载一个operator[][],解决办法就是采用代理类,像这样:
template<class T>
class Array2D
{
public:
//代理类
class Array1D
{
public:
T& operator[](int index);
const T& operator[](int index) const;
...
};
Array1D operator[](int index);
const Array1D operator[](int index) const;
...
};
那么以下操作:
Array2D<float> data(10, 20);
...
cout << data[3][6];
data[3][6]实际上进行了两次函数调用:第一次调用Array2D的operator[],返回Array1D对象,第二次调用Array1D的operator[],返回指定元素.
(本例对proxy class作用的体现其实并不显著,因为可以对指针施加operator[],因此只要使Array2D的oeprator[]返回一个指针可达到同样效果,没有必要使用代理类)
3. 区分operator[]的读写动作
条款29用String类的例子讨论了引用计数,由于当时无法判断non-const版本oeprator[]返回的字符将被用于读操作还是写操作,因此保险起见,一旦调用non-const版本operator[],便开辟一块新内存并复制数据结构到新内存.在这种策略下,因此如果operator[]返回的字符被用于读操作,那么分配新内存并复制数据结构的行为其实是不必要的,由此会带来效率损失,使用proxy class便可以做到区分non-const operator[]用于读还是写操作,像这样:
class String
{
public:
//代理类用于区分operator[]的读写操作
class CharProxy
{ // proxies for string chars
public:
CharProxy(String& str, int index); // creation
CharProxy& operator=(const CharProxy& rhs); // lvalue
CharProxy& operator=(char c); // uses
operator char() const;
private:
String& theString; //用于操作String,并在适当时机开辟新内存并复制
int charIndex;
};
const CharProxy operator[](int index) const; // for const Strings
CharProxy operator[](int index); // for non-const Strings
...
friend class CharProxy;
private:
RCPtr<StringValue> value;//见条款29
};
对String调用operator[]将返回CharProxy对象,CharProxy通过重载oeprator char模拟char类型的行为,但它比char类型更有优势——可以为CharProxy定义新的操作,这样当对CharProxy使用operator=时,便可以得知对CharProxy进行写操作,由于CHarProxy保存了父对象String的一个引用,便可以在现在执行开辟内存并复制数据结构的行为,像这样:
Comments NOTHING