“用来代表其他对象”的对象被称为proxy objects,用来表现proxy objects者,称为proxy classes(代理类)。
一、实现二维数组
//Array2D.h #ifndef ARRAY2D_H #define ARRAY2D_H //代理类 template<typename T> class Array1D{ public: Array1D(int d) :dim(d),data1d(new T[dim]){}//构造函数,T必须有默认构造函数 Array1D(const Array1D& rhs):dim(rhs.dim),data1d(new T[dim]){//深拷贝构造函数 for (int i = 0; i < dim; ++i) data1d[i] = rhs.data1d[i]; } ~Array1D(){ delete[] data1d; }//析构函数 T& operator[](int index){ return data1d[index]; }//重载[]运算符,非const版本 const T& operator[](int index) const { return data1d[index]; }//重载[]运算符,const版本 int getLength(){ return dim; }//返回一维数组长度 private: int dim; T* data1d; }; template<typename T> class Array2D{ public: Array2D(int d1, int d2):dim1(d1),dim2(d2){ //构造函数,T必须有默认构造函数 void* raw = ::operator new[](dim2*sizeof(Array1D<T>(dim1)));//分配原始内存 data2d = static_cast<Array1D<T>*>(raw);//data2d指向原始内存,并使这块内存被当做Array1D<T>数组 for (int i = 0; i < dim2; ++i)//利用placement new构造内存中的Array1D<T>对象 new (data2d + i) Array1D<T>(dim1); } Array2D(const Array2D& rhs):dim1(rhs.dim1),dim2(rhs.dim2){//深拷贝构造函数 void* raw = ::operator new[](dim2*sizeof(Array1D<T>(dim1))); data2d = static_cast<Array1D<T>*>(raw); for (int i = 0; i < dim2; ++i)//利用placement new拷贝构造内存中的Array1D<T>对象 new (data2d + i) Array1D<T>(rhs.data2d[i]); } ~Array2D(){//析构函数,没有用new来创建data2d数组,就不能直接用delete[]来删除data2d for (int i = 0; i<dim2; ++i) data2d[i].~Array1D<T>(); //显式调用析构函数销毁各个对象 ::operator delete[](static_cast<void*>(data2d)); //释放内存 } Array1D<T>& operator[](int index){ return data2d[index]; }//重载[]运算符,非const版本 const Array1D<T>& operator[](int index) const { return data2d[index]; }//重载[]运算符,const版本 int getLength1(){ return dim1; }//返回数组第一维长度 int getLength2(){ return dim2; }//返回数组第二维长度 private: int dim1; int dim2; Array1D<T>* data2d; }; #endif //main.cpp #include"Array2D.h" #include<iostream> using namespace std; int main(){ Array2D<int> data(10, 20); int count = 0; for (int i = 0; i < 10; ++i){ for (int j = 0; j < 20; ++j){ data[i][j] = count++; } } for (int i = 0; i < 10; ++i){ for (int j = 0; j < 20; ++j){ cout << data[i][j] << ' '; } } system("pause"); return 0; }
二、区分operator[]的读写动作
operator[]可以在两种不同情境下被调用:用来读取一个字符,或是用来写一个字符。读取动作是右值运用,写动作是左值运用。写一个引用计数对象,可能需要复制一份完整的数据结构,而读取则只是简单返回一个值。
//RCObject.h #ifndef RCOBJECT_H #define RCOBJECT //引用计数基类 class RCObject{ public: void addReference();//增加引用计数 void removeReference();//减少引用计数,如果变为0,销毁对象 void markUnshareable();//将追踪其值是否可共享的成员设为false bool isShareable() const;//判断其值是否可共享 bool isShared() const;//判断其值是否正在被共享 int getRefCount();//返回引用计数 protected: RCObject();//构造函数 RCObject(const RCObject& rhs);//拷贝构造函数 RCObject& operator=(const RCObject& rhs);//拷贝赋值运算符 virtual ~RCObject() = 0;//析构函数 private: int refCount;//保存引用计数 bool shareable;//保存其值是否可共享的状态 }; //构造函数,这里refCount设为0,让对象创建者自行或将refCoun设为1 RCObject::RCObject(void) :refCount(0), shareable(true){} //拷贝构造函数,总是将refCount设为0,因为正在产生一个新对象,只被创建者引用 RCObject::RCObject(const RCObject&) : refCount(0), shareable(true){} //拷贝赋值运算符,这里只返回*this,因为左右两方RCObject对象的外围对象个数不受影响 RCObject& RCObject::operator=(const RCObject& rhs){ return *this; } //析构函数 RCObject::~RCObject(){} //增加引用计数 void RCObject::addReference(){ ++refCount; } //减少引用计数,如果变为0,销毁对象 void RCObject::removeReference(){ if (--refCount == 0) delete this; } //将追踪其值是否可共享的成员设为false void RCObject::markUnshareable(){ shareable = false; } //判断其值是否可共享 bool RCObject::isShareable() const{ return shareable; } //判断其值是否正在被共享 bool RCObject::isShared() const{ return refCount>1; } //返回引用计数 int RCObject::getRefCount(){ return refCount; } #endif //RCPtr.h #ifndef RCPTR_H #define RCPTR_H //智能指针模板类,用来自动执行引用计数类成员的操控动作 template<typename T> class RCPtr{ public: RCPtr(T* realPtr = 0);//构造函数 RCPtr(const RCPtr& rhs);//拷贝构造函数 ~RCPtr();//析构函数 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 == 0) 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; } #endif //String.h #ifndef STRING_H #define STRING_H #define _CRT_SECURE_NO_WARNINGS #include"RCObject.h" #include"RCPtr.h" #include<iostream> class String { public: //代理类,为了区分左值和右值 class CharProxy{ public: CharProxy(String& str, int index);//构造函数 CharProxy& operator=(const CharProxy& rhs);//左值运用 CharProxy& operator=(char c); operator char() const;//右值运用 char* operator&();//重载&运算符,非const版本 const char* operator&() const;//重载&运算符,const版本 private: String& theString;//这个proxy所附属的字符串 int charIndex;//这个proxy所代表的字符串字符 }; String(const char *value = "");//构造函数 const CharProxy operator[](int index) const;//重载[]运算符,针对const Strings,注意返回CharProxy对象 CharProxy operator[](int index);//重载[]运算符,针对non-const Strings,注意返回CharProxy对象 int getRefCount();//返回引用计数 friend std::istream& operator>>(std::istream& is, const String& str);//重载>>运算符 friend std::ostream& operator<<(std::ostream& os, const String& str);//重载<<运算符 private: struct StringValue : public RCObject {//继承自引用计数基类 char *data; StringValue(const char *initValue);//构造函数 StringValue(const StringValue& rhs);//拷贝赋值运算符 void init(const char *initValue); ~StringValue();//析构函数 }; RCPtr<StringValue> value;//智能指针对象 }; //String::CharProxy实现代码 //构造函数 String::CharProxy::CharProxy(String& str, int index) :theString(str), charIndex(index){} //左值运用 String::CharProxy& String::CharProxy::operator=(const CharProxy& rhs){ //如果本字符串与其他String对象共享一个实值,将实值复制一份,供本字符串单独使用 if (theString.value->isShared()) theString.value = new StringValue(theString.value->data); //赋值动作 theString.value->data[charIndex] = rhs.theString.value->data[rhs.charIndex]; return *this; } String::CharProxy& String::CharProxy::operator=(char c){ //如果本字符串与其他String对象共享一个实值,将实值复制一份,供本字符串单独使用 if (theString.value->isShared()) theString.value = new StringValue(theString.value->data); //赋值动作 theString.value->data[charIndex] = c; return *this; } //右值运用 String::CharProxy::operator char() const{ return theString.value->data[charIndex]; } //重载&运算符,非const版本 char* String::CharProxy::operator&(){ if (theString.value->isShared()) theString.value = new StringValue(theString.value->data); theString.value->markUnshareable(); return &(theString.value->data[charIndex]); } //重载&运算符,const版本 const char* String::CharProxy::operator&() const{ return &(theString.value->data[charIndex]); } //String::StringValue实现代码 void String::StringValue::init(const char *initValue){ data = new char[strlen(initValue) + 1]; strcpy(data, initValue); } //StringValue类的构造函数 String::StringValue::StringValue(const char *initValue){ init(initValue); } //StringValue类的拷贝赋值运算符 String::StringValue::StringValue(const StringValue& rhs){ init(rhs.data); } //StringValue类的析构函数 String::StringValue::~StringValue(){ delete[] data; } //String实现代码 //String类的构造函数 String::String(const char *initValue) : value(new StringValue(initValue)) {} //重载[]运算符,针对const Strings,注意返回CharProxy对象 const String::CharProxy String::operator[](int index) const{ return CharProxy(const_cast<String&>(*this), index); } //重载[]运算符,针对non-const Strings,注意返回CharProxy对象 String::CharProxy String::operator[](int index){ return CharProxy(*this, index); } //返回引用计数 int String::getRefCount(){ return value->getRefCount(); } //重载>>运算符 std::istream& operator>>(std::istream& is, const String& str){ is >> str.value->data; return is; } //重载<<运算符 std::ostream& operator<<(std::ostream& os, const String& str){ os << str.value->data; return os; } #endif //main.cpp #include"String.h" #include<iostream> using namespace std; int main(){ String str1("hello world"); String str2 = str1;//调用拷贝构造函数 String str3;//调用默认构造函数 str3 = str2;//调用拷贝赋值运算符 cout << str1[4] << endl; // 'o' 右值运用 str2[0] = 'H';//左值运用 cout << str1 << endl; //"hello world" cout << str2 << endl;//"Hello world" cout << str3 << endl;//"hello world" cout << "str1的引用计数是:" << str1.getRefCount() << endl; // 2 cout << "str2的引用计数是:" << str2.getRefCount() << endl; // 1 cout << "str3的引用计数是:" << str3.getRefCount() << endl; // 2 str1[3] = str2[8];//左值运用 cout << str1 << endl; //"helro world" cout << str2 << endl;//"Hello world" cout << str3 << endl;//"hello world" cout << "str1的引用计数是:" << str1.getRefCount() << endl; // 1 cout << "str2的引用计数是:" << str2.getRefCount() << endl; // 1 cout << "str3的引用计数是:" << str3.getRefCount() << endl; // 1 char* p = &str1[0];//如果CharProxy类不重载&运算符,出现错误, //对proxy取址获得的指针类型和对真实对象取址所获得的指针类型不同 system("pause"); return 0; }
代理类的限制:
a、对proxy取址获得的指针类型和对真实对象取址所获得的指针类型不同;
b、通过proxies调用真实对象的成员函数会失败;
c、用户不能将它们传递给接受非常量引用对象的函数,否则会出错;
d、proxies难以完全取代真正对象的最后一个原因在于隐式转换。
总结:
代理类可以完成某些十分困难或几乎不可能完成的行为。多维数组是其中之一,左值/右值的区分是其中之二,压抑隐式类型转换是其中之三。
proxy类也有缺点。作为函数返回值,代理对象是临时对象,必须被构造和析构。代理对象的存在也增加了软件的复杂度。最后,当类的身份从与真实对象合作转移到与替身对象合作,往往会造成类语义的改变,因为代理对象所展现的行为常常和真正对象的行为有些隐微差异。
版权声明:本文为博主原创文章,未经博主允许不得转载。