上一回討論的句柄技術有一個明顯的缺點:為了將句柄捆綁到類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類可以在不了解其使用者任何信息的情況下與之合為一體。這樣一來,我們就可以把這個類當成句柄實現的一部分,與各種不同的數據結構協同工作。
作者 yucan1001