Item 30 代理类:“用来代表其他对象”的对象。
(1)阻止只有一个参数的类执行隐式类型转换的方法。
template <typename T>
class Array
{
public:
class ArraySize
{
public:
ArraySize(int numElements):theSize(numElements) {}
int size() const {return theSize;}
private:
int theSize;
};
Array(ArraySize size);
};
其中ArraySize就是数组大小的一个代理类。
Array<int> a(10);
Array<int> b(10);在构造的过程中,编译器将int通过隐式类型转换转为ArraySize的一个临时对象,然后调用Array<int>的构造函数。
如果出现这样的代码:
if(a==b[i]) //a的类型为array<int>,而b[i]的类型为int,则若将int转为一个临时的ArraySize,然后根据ArraySize再构造一个临时的array<int>,这样的行为编译器不允许,不会连续执行两次以上的隐式类型转换。若不采用代理类,则直接根据int就可以构造一个Array<int>可以编译通过。
(2)区分operator[]的读写操作。
采用带引用计数、使用代理类的String做例子:
RCObject同上篇。
RCPtr如下:
template <typename T>
class RCPtr
{
public:
RCPtr(T* realPtr=0);
RCPtr(const RCPtr& rhs);
~RCPtr(void);
RCPtr& operator=(const RCPtr& rhs);
T* operator->() const;
T& operator*() const;
private:
T* pointee;
void init();
};
template <typename T>
void RCPtr<T>::init()
{
if(pointee==nullptr) return;
if(pointee->isShareable()==false)
{
pointee=new T(*pointee);
}
pointee->addReference();
}
template <typename T>
RCPtr<T>::RCPtr(T* realPtr):pointee(realPtr)
{
init();
}
template <typename T>
RCPtr<T>::RCPtr(const RCPtr& rhs):pointee(rhs.pointee)
{
init();
}
template <typename T>
RCPtr<T>::~RCPtr()
{
if(pointee)
pointee->removeReference();
}
template <typename T>
RCPtr<T>& RCPtr<T>::operator=(const RCPtr& rhs)
{
if(pointee!=rhs.pointee)
{
if(pointee)
pointee->removeReference();
pointee=rhs.pointee;
init();
}
return *this;
}
template <typename T>
T& RCPtr<T>::operator*() const
{
return *pointee;
}
template <typename T>
T* RCPtr<T>::operator->() const
{
return pointee;
}
String头文件:
#include <iostream>
using namespace std;
#include "RCObject.h"
#include "RCPtr.h"
class String
{
public:
class CharProxy
{
public:
CharProxy(String& str,int index):theString(&str),charIndex(index) {}
CharProxy& operator=(const CharProxy& rhs);
CharProxy& operator=(char c);
char* operator&();
const char* operator&() const;
operator char() const;
private:
void assignment(char c);
String* theString;
int charIndex;
};
friend class CharProxy;
String(const char* value="");
const CharProxy operator[](int index) const;
CharProxy operator[](int index);
private:
struct StringValue:public RCObject
{
char* data;
StringValue(const char* initValue);
StringValue(const StringValue& rhs);
void init(const char* initValue);
~StringValue();
};
RCPtr<StringValue> value;
friend ostream& operator<<(ostream& os,const String& str)
{
os<<str.value->data;
return os;
}
};
String实现文件:
#include "String.h"
String::CharProxy::operator char() const
{
return theString->value->data[charIndex];
}
void String::CharProxy::assignment(char c)
{
if(theString->value->isShared())
theString->value=new StringValue(theString->value->data);
theString->value->data[charIndex]=c;
}
String::CharProxy& String::CharProxy::operator=(const String::CharProxy& rhs)
{
assignment(rhs.theString->value->data[charIndex]);
return *this;
}
String::CharProxy& String::CharProxy::operator=(char c)
{
assignment(c);
return *this;
}
const char* String::CharProxy::operator&() const
{
return &(theString->value->data[charIndex]);
}
char* String::CharProxy::operator&()
{
if(theString->value->isShared())
theString->value=new StringValue(theString->value->data);
theString->value->markUnshareable();
return &(theString->value->data[charIndex]);
}
void String::StringValue::init(const char* initValue)
{
data=new char[strlen(initValue)+1];
strcpy_s(data,strlen(initValue)+1,initValue);
}
String::StringValue::StringValue(const char* initValue)
{
init(initValue);
}
String::StringValue::StringValue(const StringValue& rhs)
{
init(rhs.data);
}
String::StringValue::~StringValue()
{
delete[] data;
}
String::String(const char* initValue):value(new StringValue(initValue))
{
}
const String::CharProxy String::operator[](int index) const
{
return CharProxy(const_cast<String&>(*this),index);
}
String::CharProxy String::operator[](int index)
{
return CharProxy(*this,index);
}
例子分析:
int _tmain(int argc, _TCHAR* argv[])
{
String str1="Hello";
String str2="How many!!";
cout<<str1[2]<<endl;
str2[5]='y';
return 0;
}
在cout<<str1[2]<<endl;这句中,首先通过CharProxy operator[](int index);返回一个CharPorxy对象,然后调用operator char() const;转为char型,然后输出。
在str2[5]='y';这句中,首先通过CharProxy operator[](int index);返回一个CharProxy对象,然后调用CharProxy& operator=(char c);来完成操作。
因此这样就通过代理类的两个成员分清楚了是读操作,还是写操作。