C++中句柄

一、句柄的概念


1.windows方面理解:

  • 句柄,是整个windows编程的基础。
  • 一个句柄是指使用的一个唯一的整数值,即一个四字节长的数值,来标志应用程序中的不同对象和同类对象中的不同的实例,诸如,一个窗口,按钮,图标,滚动条,输出设备,控件或者文件等。
  • 应用程序能够通过句柄访问相应的对象的信息,但是句柄不是一个指针,程序不能利用句柄来直接阅读文件中的信息。如果句柄不用在I/O文件中,它是毫无用处的。 
  • 句柄是windows用来标志应用程序中建立的或是使用的唯一整数,windows使用了大量的句柄来标志很多对象。

2.本人理解:

  • C++句柄是一种指向指针的指针。
  • C++句柄类的主要目的是在对象层面上实现多态。

二、实例详细说明


1.在visual studio 2010 创建控件器平台:

C++中句柄_第1张图片


2.添加两个类,helloA,helloB
helloA.h
#pragma once
class helloA
{
public:
	helloA(void);
	~helloA(void);
	virtual void func()const{printf("A");}
};
helloB.h
#pragma once
#include "helloa.h"
class helloB :
	public helloA
{
public:
	helloB(void);
	~helloB(void);
	 void func()const{printf("B");}
};
handel.cpp
#include "stdafx.h"
#include "helloA.h"
#include "helloB.h"
#include <vector>
using namespace std;

int _tmain(int argc, _TCHAR* argv[])
{
	vector<helloA> vec;
	helloA a;
	helloB b;
	vec.push_back(a);
	vec.push_back(b);
	
	for ( vector<helloA>::iterator iter=vec.begin();iter!=vec.end();iter++)
	{
		(*iter).func();
	}

	return 0;
}
运行的结果:



原因:vec.push_back(b);  ,其实把截断了,将b转化为了它的基类helloA.

如何解决这个问题,可以用指针代替对象方法:如:vector<helloA*>vec;这样做可以达到多态的目的,但程序员必须接管内存管理,例如,更改下handel.cpp代码:

vector<helloA*> vec;
	helloA *a = new helloA;
	helloB *b = new helloB;
	vec.push_back(a);
	vec.push_back(b);

	for ( vector<helloA*>::iterator iter=vec.begin();iter!=vec.end();iter++)
	{
		(*iter)->func();
	}

运行结果:




效果达到,但问题来了,这里假如vec的生命周期结束了,vec不会主动释放b所占用的内存,如果不手动delete b,就会产生内存泄漏。

接下来,就实现下句柄类,来解决如上问题。

更改下helloA,helloB的代码:
helloA.h
#pragma once
class helloA
{
public:
	helloA(void);
	~helloA(void);
	virtual void func()const{printf("A");}
	virtual helloA* clone() const {return new helloA(*this);}
};
helloB.h
#pragma once
#include "helloa.h"
class helloB :
	public helloA
{
public:
	helloB(void);
	~helloB(void);
	 void func()const{printf("B");}
	 virtual helloB* clone() const{return new helloB(*this);}
};
同时,添加sample类,记得把sample.cpp的代码注释掉,我们只在sample头文件更改代码即可。
sample.h
#pragma once
#include "helloA.h"
#include "helloB.h"
#include <stddef.h>
class sample
{
public:

	sample():p(0),use(1){};
	sample(const helloA& a):p(a.clone()),use(1){};
	sample(const sample&i):p(i.p),use(i.use){use++;}
	~sample(){decr_use();};
	sample& operator = (const sample& i)
	{
		use++;
		decr_use();
		p = i.p;
		use = i.use;
		return *this;
	}
	const helloA *operator->() const {if (p)return p;}

	const helloA &operator*() const{if(p)return *p;}
private:
	helloA* p;
	size_t use;
	void decr_use(){if (-use == 0)delete p;}
};
回到main函数,更改代码
handle.cpp
// handle.cpp : 定义控制台应用程序的入口点。
//

#include "stdafx.h"
#include "helloA.h"
#include "helloB.h"
#include "sample.h"
#include <vector>
#include <list>
using namespace std;


int _tmain(int argc, _TCHAR* argv[])
{

	vector<sample> vec;
	helloA a;
	helloB b;

	sample sample1(a);
	sample sample2(b);

	vec.push_back(sample1);
	vec.push_back(sample2);

	
	for ( vector<sample>::iterator iter=vec.begin();iter!=vec.end();iter++)
	{
		(*iter)->func();
	}

	return 0;
}
运行结果:




我们得到了正确的输出,如同shared_ptr,我们引入了计数,在vec生命周期结束时,我们不需要自己释放内存。

对上面代码需要注意,为什么克隆函数,要用virtual helloA* clone() const {return new A(*this);}而不是直接virtual A*clone() const {return this;}

因为,这样潜在一个问题,比如 

helloB b;
sample sam(b);
vec.push_back(sam);

当b的生命周期结束,而vec的生命周期尚未结束时,调用(*iter)->A.func();就会出错,而更直接的是,这样做与直接用指针进行多态没有太大区别了。

参考文章:http://blog.csdn.net/linuxtiger/article/details/6879366/

你可能感兴趣的:(C++)