“用来代表其他对象”的对象被称为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类也有缺点。作为函数返回值,代理对象是临时对象,必须被构造和析构。代理对象的存在也增加了软件的复杂度。最后,当类的身份从与真实对象合作转移到与替身对象合作,往往会造成类语义的改变,因为代理对象所展现的行为常常和真正对象的行为有些隐微差异。