上一回讨论的句柄技术有一个明显的缺点:为了将句柄捆绑到类T的对象上,必须要新定义一个具有类型为T的成员对象的新类。
这个毛病相当麻烦,如果想新设计一个类的句柄类,就需要新定义两个类。
C++之父提到过一种定义句柄类的技术可以弥补这一个缺点,主要思想就是将引用技术从数据中分离出来,把引用计数放到句柄类自己的对象之中。
示例代码如下所示:
#include <iostream>
using namespace std;
//-----------------------------------------
class Point
{
private:
int xval,yval;
public:
Point():xval(0),yval(0){}
Point(int x,int y):xval(x),yval(y){}
int x()const{return xval;}
int y()const{return yval;}
Point& x(int xv){xval=xv;return *this;}
Point& y(int yv){yval=yv;return *this;}
};
//------------------------------------------------------
class UseCount
{
private:
int* p;
public:
UseCount();
UseCount(const UseCount&);
UseCount& operator=(const UseCount&);
~UseCount();
bool only();
bool reattach(const UseCount&);
bool make_only();
};
UseCount::UseCount():p(new int(1)){}
UseCount::UseCount(const UseCount&u):p(u.p){++*p;}
UseCount::~UseCount()
{
if (--*p==0)
{
delete p;
}
}
bool UseCount::only()
{
return *p==1;
}
bool UseCount::reattach(const UseCount& u)
{
++*u.p;
if (--*p==0)
{
delete p;
p=u.p;
return true;
}
p=u.p;
return false;
}
bool UseCount::make_only()
{
if (*p==1)
return false;
--*p;
p=new int(1);
return true;
}
//-------------------------------------------
class Handle
{
private:
Point* p;
UseCount u;
public:
Handle();
Handle(int,int);
Handle(const Point&);
Handle(const Handle&);
Handle& operator =(const Handle&);
~Handle();
int x()const;
Handle&x(int);
int y()const;
Handle&y(int);
};
Handle::Handle():p(new Point){}
Handle::Handle(int x,int y):p(new Point(x,y)){}
Handle::Handle(const Point&p0):p(new Point(p0)){}
Handle::Handle(const Handle&h):u(h.u),p(h.p){}
Handle::~Handle()
{
if (u.only())
{
delete p;
}
}
Handle& Handle::operator=(const Handle &h)
{
if (u.reattach(h.u))
delete p;
p=h.p;
return *this;
/* //自定义版本不使用reattach辅助方法,自认为更容易理解,但很丑陋
(*(h.u.p))++;
if(*(u.p) == 1)
{
delete p;
delete u.p;
}
else
(*(u.p))--;
u.p = h.u.p;
p = h.p;
return *this;
*/
}
int Handle::x()const
{
return p->x();
}
int Handle::y()const
{
return p->y();
}
Handle& Handle::x(int x0)
{
if (u.make_only())
p=new Point(*p);
p->x(x0);
return *this;
/* //自定义版本,不使用辅助方法make_only,自认为更容易理解,但很丑陋
if(*(u.p) == 1)
p->x(x0);
else
{
(*(u.p))--;
u.p = new int(1);
p = new Point(*p);
p->x(x0);
}
retrun *this;
*/
}
Handle& Handle::y(int y0)
{
if (u.make_only())
p=new Point(*p);
p->y(y0);
return *this;
/* //自定义版本,不使用辅助方法make_only,自认为更容易理解,但很丑陋
if(*(u.p) == 1)
p->y(x0);
else
{
(*(u.p))--;
u.p = new int(1);
p = new Point(*p);
p->y(x0);
}
retrun *this;
*/
}
//---------------------------------------------------
int main()
{
Handle h(3,4);
Handle h2 = h;
h2.x(5);
int n = h.x();
cout<<n<<endl;
return 0;
}
这个策略的一个重要优势:UseCount类可以在不了解其使用者任何信息的情况下与之合为一体。这样一来,我们就可以把这个类当成句柄实现的一部分,与各种不同的数据结构协同工作。