C++中的句柄类

前奏

在刚开始学习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 1

class 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到底是哪个对象。实际使用句柄类时还需要重载句柄类的-〉操作符 或*操作符。

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

 

 


 

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值