C++沉思录读书笔记(二)句柄类.上

原创 2004年07月06日 15:24:00

C++沉思录读书笔记(二)句柄类.上


延续 “C++沉思录读书笔记(一)代理类”
********
问题
********
创建代理将会复制所需要的对象,对某些类来说,复制的代价太大或者包含不能轻易被复制的资源。
如何在保持代理的多态行为的同时,避免复制对象的代价

class Point { //一个简单的类,没有指针成员的函数常常无需重写赋值操作符和复制构造函数
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; }
private:
 int xval, yval;
};

********
解决方案
********
@Handle类的轮廓
定义一个适当的Handle类,将Handle类绑定到它们所控制的对象上
要求:
1. Handle类应该创建和销毁对象
  创建自己的Point对象并把它赋给一个handle
  把创建Point的参数传给Handle
2. 通过Handle类访问Point对象
  重载Handle类的operator->操作符,暴露内部的Point对象(本文未采用这种方式)
  明确选择让Handle类支持那些Point操作

class Handle {
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);
private:
 //...
};

@引用计数
因为允许多个句柄绑定到单个对象上,所以要使用引用计数确定多少个句柄绑定到同一个对象上,以便确定何时删除对象
引用计数不能是句柄的一部分,否则每个句柄必须知道跟它一起被绑定到同一个对象的其他所有句柄的位置(更不能使用static成员)
引用计数不能是对象的一部分,要求不重写已存在的Point对象

class UPoint { //用来存储引用计数和Point对象
private: //纯粹为了实现而设计,所有成员私有
 friend class Handle;
 Point p;
 int u;

 UPoint(): u(1) { } //UPoint对象总是随Handle类产生,因此缺省引用计数为1
 UPoint(int x, int y): p(x, y), u(1) { }
 UPoint(const Point& p0): p(p0), u(1) { }
};

class Handle {
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);
private:
 UPoint* up; //新添加
};

@Handle类的实现
//构造函数
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; }

//赋值操作符可能造成原左侧对象计数器为0
//先调用++可以保证左右两侧句柄引用同一个UPoint对象时也能工作
Handle& Handle::operator=(const Handle& h)
{
 ++h.up->u;
 if (--up->u == 0)
  delete up;
 return *this;
}

//简单的读函数
int Handle::x() const { return up->p.x(); }
int Handle::y() const { return up->p.y(); }

//复杂的写函数
/*
 句柄类在用户面前的行为
 Handle h(3,4) //原对象
 Handle h2 = h; //复制
 h2.x(5); //修改复制对象
 int n = h.x(); // 3 or 5?
*/

//指针语义:复制句柄类后,复制对象和原对象使用同一个UPoint对象

Handle& Handle::x(int x0)
{
 up->p.x(x0);
 return *this;
}

Handle& Handle::y(int y0)
{
 up->p.y(y0);
 return *this;
}

//值语义:复制句柄类后,复制对象和原对象不使用同一个UPoint对象
//在绝对必要的时候才进行对象复制,称为写时复制(copy on write),写时复制只是针对可变对象的一种优化技术

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;
}

@图示
+--------+       +--------+       +--------+
| Handle |------>| UPoint |<>---->| Point  |
+--------+       +--------+       +--------+

C++ 沉思录》阅读笔记——类的反思

类这个概念无非是数据和方法的集合,为什么我一直困惑呢?为什么不弄清楚呢? C++中的类这个概念里有4个函数比较特殊,像我这种以前有C经验的人可能一时难以适应,它们是构造函数、析构函数、复制构造函...
  • flora_yao
  • flora_yao
  • 2015-07-02 18:02:15
  • 720

《软件管理沉思录》第三章读书笔记

一、共同目标        1、团队:超过两名成员,同一目标,角色扮演,相互依赖。        2、没有共同目标,那样只能剩下时间付出。        3、凝胶型团队。 二、团队合作比独立工...
  • sun2003shy
  • sun2003shy
  • 2012-09-09 12:04:44
  • 483

概率论沉思录 前言

    1998年4月30日Jaynes去世。此前,他曾经要我完成并出版他的这本关于概率论的书。为此,我曾纠结了一段时间。因为我认为Jaynes毫无疑问想完成这本书;但不幸的是,这本书后面的许多章节(...
  • shoreman
  • shoreman
  • 2011-04-17 22:22:00
  • 2124

读书笔记∣概率论沉思录 01

读书笔记:概率论沉思录
  • zhaozhn5
  • zhaozhn5
  • 2017-09-09 21:09:49
  • 609

C++沉思录源代码

  • 2008年03月12日 11:44
  • 46KB
  • 下载

C++沉思录_英文版_清晰 带书签目录.pdf

  • 2018年03月16日 14:51
  • 13.69MB
  • 下载

《C++沉思录》-第八章- 一个面向对象程序范例

node.h #ifndef NODE_H #define NODE_H #include "expr.h" #include #include using namespace std; c...
  • shuideyidi
  • shuideyidi
  • 2013-12-10 13:56:31
  • 752

C++沉思录C++沉思录

  • 2010年02月21日 18:38
  • 7.46MB
  • 下载

c++沉思录(中文版)

  • 2009年06月02日 11:56
  • 8.13MB
  • 下载
收藏助手
不良信息举报
您举报文章:C++沉思录读书笔记(二)句柄类.上
举报原因:
原因补充:

(最多只允许输入30个字)