C++中的句柄类

来源:互联网 发布:主题医院 mac版 编辑:程序博客网 时间:2024/04/29 09:13

前奏

在刚开始学习C++的时候,我师傅给了我一句话:好好看看《C++primer》中的句柄类。我一直记在心里,但是惭愧的是最近才真正实现这个东西,而且还不是很理解为什么要另外再定义一个句柄类来管理基类指针,所以发这篇博文的目的有两个:总结和解惑。总结自己的理解,解惑是希望牛人解答why。

实现句柄类的准备

   在实现句柄类之前,先要理解下智能指针,当我们定义的类有指针成员时,如果两个或多个类对象中的指针成员指向了同一个对象,这个时候如果其中一个对象生命结束了,那他的指针成员所指向的对象会被析构函数删除,而另外几个对象的指针并不知道他们所指对象已经被别人删除了,不知情况的对象在执行析构函数的时候也会删除已经不存在的对象,这对于C++来说是不允许的,编译器报错,为了解决这个问题就引出了智能指针,其中一种解决方案就是使用计数器,另外定义一个计数器类,将类成员指针相互关联的对象绑定到同一个计数器对象,每多绑定一个指针,计数器增一,对象析构的时候只有当计数器减为零时才删除对象,这样
一来就可以确保在删除指针对象之前对象还存在,这就是大致思路了,具体代码如下:

类头文件class.h

#ifndef CLASS_H#define CLASS_H 1/**假如我们要实现一个字符串类,那这个类中就需要一个指向*指向动态分配内存基地址的指针成员,这时候就需要使用智能指针*/class CCount; //声明一下class string_str{public:void get() const;string_str(char *data=0);//在这里string_str(const string_str &item);~string_str();string_str &operator=(const string_str &item);private:CCount *CData;//用计数器对象来管理这个指针};class CCount{friend class string_str;CCount(char *data);char *m_data;unsigned count;};#endif

类定义的实现class.cpp

#include "class.h"string_str::string_str(char *data):CData(new CCount(data)){}string_str::string_str(const string_str &item){CData=item.CData;//两个类对象绑定到同一个计数器CData->count=item.CData->count;++CData->count;//计数增一}string_str& string_str::operator =(const string_str &item){/**赋值操作符的操作有些不同,详细分析下,因为当执行赋值操作时,*说明两个类已经是分别绑了不同的计数器的,这个时候就要删除其中*一个,那是删除哪个呢?由于右操作数为const引用,无法修改他的成员,*所以我们只能删除左边对象绑定的计数器,将他绑定到右计数器上,同样在删除*之前要检测下计数器是否减为零*/if(--CData->count==0)delete CData;++item.CData->count;CData=item.CData;//将左对象计数器绑定到右对象计数器CData->count=item.CData->count;return *this;}string_str::~string_str(){if(--CData->count==0)//当计数器减为时删除计数对象delete CData;}CCount::CCount(char *data):m_data(data),count(1){}

测试代码test.cpp

#include "class.h"#include <iostream.h>void main(){string_str s1("hello");string_str s2;s2=s1;//调用赋值操作符string_str s3=s2;//调用复制构造函数 }

句柄类建立在智能指针的基础上

    以上就是智能指针的一种实现了,在句柄类中将用到另一种实现方式,但是思路是一样的,同样是使用计数,但是除了计数器,句柄类的目的是管理基类指针,C++的多态性发生在使用指向基类的指针或引用调用派生类成员函数时,所以在句柄类中就保存有一个指向基类的指针,这样一来就需要使用智能指针了,我们的目的是通过句柄类对象就可以获得多态性,比如:定义基类computer;派生类mobile,ipad,句柄类handle,通过handle(computer &c)->output();实现动态绑定。

类定义文件CLASS.H

#ifndef CLASS_H#define CLASS_H 1class computer{public:virtual void output();virtual computer* clone() const;//返回调用该函数的对象};class mobile:public computer{public:virtual void output();virtual mobile* clone() const;//返回调用该函数的对象};class ipad:public computer{public:virtual void output();virtual ipad* clone() const;//返回调用该函数的对象};class handle //句柄类{public:handle();handle(const handle &h);handle(computer &c);~handle();handle operator=(const handle &h);private:int *count;//保存句柄类实的使用次数的指针computer *base;};#endif

类定义实现CLASS.CPP

#include "CLASS.H"#include <iostream.h>void computer::output(){cout<<"computer"<<endl;}computer* computer::clone() const{return this;}void mobile::output(){cout<<"mobile"<<endl;}mobile* mobile::clone() const{return this;}void ipad::output(){cout<<"ipad"<<endl;}ipad* ipad::clone() const{return this;}handle::handle():count(new int(1)),base(NULL){}handle::handle(const handle &h):count(h.count),base(h.base){++*count;}handle::handle(computer &c):count(new int(1)),base(c.clone())//动态返回调用函数的对象{}handle::~handle(){if(0==--*count)delete count;}handle handle::operator =(const handle &h){if(0==--*count)delete count;++*h.count;count=h.count;base=h.base;return *this;}

测试代码text.cpp

#include <iostream.h>#include "CLASS.H"void main(){computer *c=NULL;mobile m;ipad i;handle h1(m);handle h2=h1;}

总结

   句柄类实现的关键就在那个clone()虚函数,在继承层次的每个类中增加一个clone()函数返回调用该函数的对象,这样句柄类就可以知道传递给handle(computer &c)中的c到底是哪个对象。实际使用句柄类时还需要重载句柄类的-〉操作符 或*操作符。

   句柄类代码未测试过,有错莫怪!