句柄类
——《C++沉思录》第六章 句柄:第一部分
三个类:
Point:主体类,表示实际的数据
Handle:句柄类,用来引用代理主体类
UPoint:对Point的封装,增加了一个use count成员,用来记录主体类对象被引用代理的次数。该类完全可以省略,但是添加此类的好处是更便于管理。
对Handle的拷贝构造函数和赋值运算符的实现是通过对UPoint对象的use count修改来完成的。Handle中有两个写函数,有两种实现方式:指针语义和值语义,这里涉及了一项技术称作写时赋值(copy on write)。
具体代码如下:
// 句柄类 #include <iostream> using namespace std; class Point { private: int xval; int 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; } }; // use count class class UPoint { private: friend class Handle; Point p; int u; UPoint() : u(1) {} UPoint(int x, int y) : p(x, y), u(1) {} UPoint(const Point& p0) : p(p0), u(1) {} }; // 句柄类 class Handle { private: UPoint* up; public: Handle(); Handle(int, int); Handle(const Point&); Handle(const Handle&); Handle& operator = (const Handle&); ~Handle(); int x() const; int y() const; Handle& x(int); Handle& y(int); void test() const; }; void Handle::test() const { cout << up->u << endl; } Handle::Handle() : up(new UPoint) {} Handle::Handle(int x, int y) : up(new UPoint(x, y)) {} Handle::Handle(const Point& p) : up(new UPoint(p)) {} Handle::~Handle() { if (--up->u == 0) { delete up; } } Handle::Handle(const Handle& h) : up(h.up) { ++up->u; } Handle& Handle::operator = (const Handle& h) { // 为了避免当只存在一个引用的时候,自赋值操作而引起的错误, // 这里采用先递增右侧句柄的引用计数,然后再对左侧句柄引用计数进行递减 ++h.up->u; if (--up->u == 0) { delete up; } up = h.up; return *this; // 对于operator=的操作也可以采用另外一种方法: // 先检测是否是自赋值,如果是,则不进行操作,直接返回*this // 如果不是,则--up->u,然后++h.up->u } int Handle::x() const { return up->p.x(); } int Handle::y() const { return up->p.y(); } // 对Handle& Handle::x(int)和Handle& Handle::y(int)的实现有两种方式: // 指针语义和值语义 // 其中值语义的实现方式称作为写时赋值(copy on write) // 指针语义 Handle& Handle::x(int x0) { up->p.x(x0); return *this; } Handle& Handle::y(int y0) { up->p.y(y0); return *this; } //// 值语义 //Handle& Handle::x(int x0) //{ // if (up->u > 1) // { // --up->u; // up = new UPoint(up->p); // } // up->p.x(x0); // // return *this; //} // //Handle& Handle::y(int y0) //{ // if (up->u > 1) // { // --up->u; // up = new UPoint(up->p); // } // up->p.y(y0); // // return *this; //} int main() { Point p1; Handle* ph1 = new Handle(p1); ph1->test(); Handle* ph2 = new Handle(*ph1); ph1->test(); ph2->test(); delete ph1; ph2->test(); return 0; }