一、句柄的概念
1.windows方面理解:
- 句柄,是整個windows編程的基礎。
- 一個句柄是指使用的一個唯一的整數值,即一個四字節長的數值,來標志應用程序中的不同對象和同類對象中的不同的實例,諸如,一個窗口,按鈕,圖標,滾動條,輸出設備,控件或者文件等。
- 應用程序能夠通過句柄訪問相應的對象的信息,但是句柄不是一個指針,程序不能利用句柄來直接閱讀文件中的信息。如果句柄不用在I/O文件中,它是毫無用處的。
- 句柄是windows用來標志應用程序中建立的或是使用的唯一整數,windows使用了大量的句柄來標志很多對象。
2.本人理解:
- C++句柄是一種指向指針的指針。
- C++句柄類的主要目的是在對象層面上實現多態。
二、實例詳細說明
1.在visual studio 2010 創建控件器平台:

2.添加兩個類,helloA,helloB
helloA.h
- #pragma once
- class helloA
- {
- public:
- helloA(void);
- ~helloA(void);
- virtual void func()const{printf("A");}
- };
- #pragma once
- #include "helloa.h"
- class helloB :
- public helloA
- {
- public:
- helloB(void);
- ~helloB(void);
- void func()const{printf("B");}
- };
- #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);}
- };
- #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.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;}
- };
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/