句柄类
今天闲来无事,看了篇关于句柄类的博客,详细的可以参考 http://rangercyh.blog.51cto.com/1444712/1293679
主要是利用了代理的思想,可以实现两个功能,一个是完全可以将实现文件(.cpp)与头文件完全隔离出来,类的结构或者是函数的实现部分都在实现文件中,我们通过编译器编译后形成静态文件或者是动态文件,只给出在头文件(只提供接口信息)这样防止客户程序员不能够轻易访问到他的实现部分。
class handle {
public:
//在这里提供些访问或者是设置Point对象的接口
private:
struct Point;
Point *p;
}
在实现文件中,给出Point的结构和其他函数
struct Handle::Point
{
}
另外一个是也就是智能指针,也就是涉及到什么引用计数啦、什么自动释放啦,
能够让我们不必去复制对象,同时能够达到运行时绑定对象的方法
要完成这个功能和类与类之间的关系和上面差不多,但当我们需要有多个句柄指向同一个 Point 对象,而又不会产生代理类中复制代理类就会多产生一个 Point 副本的内存开销,我们引入了引用计数,这样,我们需要把句柄类第一次绑定到 Point 对象的时候复制一个 Point 对象的副本,然后使用引用计数来统计同时有多少个句柄指向了这个相同的对象,然后我们需要在引用计数减为 0 ,也就是这个副本没有被引用的时候删除掉这个副本。
class handle {
public:
Handle();
Handle(int, int);
Handle(const Point &);
Handle(const Handle &);
Handle &operator=(const Handle &);
Handle &x(int);
~Handle();
private:
Point *p;
int *u;//引用计数
}
但是如果某个时候我们要修改某个句柄中的Point值时候,如果直接修改,那么指向同一块内存的句柄都会被修改,这就给我们带来不便。这就要涉及到句柄到底是值语义还是指针语义。
如果是指针语义,就是直接修改内存,不另外再申请空间并拷贝,任何对指向对象的句柄的操作,都会实质性的影响到真正的对象本身。
Handle &Handle::x(int x0)
{
p->x(x0);
return *this;
}
如果是值语义,那么我们就需要在值发生修改时,重新拷贝一份副本保存下来,而不是去修改原对象里的值。我们称之为“写时复制( copy on write )”也就是只有当必要的时候才会进行复制
Handle &Handle::x(int x0)
{
/*
这里比较的目的是如果引用计数大于1,代表有多个句柄指向该对象,
所以我们需要减少引用计数,如果引用计数为1,
代表只有这一个句柄指向这个对象,
既然,我要修改这个对象的值,那么直接改原对象就可以了。
*/
if (*u != 1)
{
--*u;
p = new Point(*p);
}
p->x(x0);
return *this;
}
这个设计的这个句柄类能够在运行时绑定未知类型的 Point 类及其继承,同时能够自己处理内存分配的问题,而且我们避免了代理类每次复制都拷贝对象的操作