C++中句柄


 C++中句柄

一、句柄的概念

 

1.windows方面理解:

 

  • 句柄,是整個windows編程的基礎。
  • 一個句柄是指使用的一個唯一的整數值,即一個四字節長的數值,來標志應用程序中的不同對象和同類對象中的不同的實例,諸如,一個窗口,按鈕,圖標,滾動條,輸出設備,控件或者文件等。
  • 應用程序能夠通過句柄訪問相應的對象的信息,但是句柄不是一個指針,程序不能利用句柄來直接閱讀文件中的信息。如果句柄不用在I/O文件中,它是毫無用處的。 
  • 句柄是windows用來標志應用程序中建立的或是使用的唯一整數,windows使用了大量的句柄來標志很多對象。

 

2.本人理解:

 

  • C++句柄是一種指向指針的指針。
  • C++句柄類的主要目的是在對象層面上實現多態。

二、實例詳細說明

 
1.在visual studio 2010 創建控件器平台:
 
 
 
2.添加兩個類,helloA,helloB
helloA.h
[cpp]  view plain  copy
 
  1. #pragma once  
  2. class helloA  
  3. {  
  4. public:  
  5.     helloA(void);  
  6.     ~helloA(void);  
  7.     virtual void func()const{printf("A");}  
  8. };  
helloB.h
[cpp]  view plain  copy
 
  1. #pragma once  
  2. #include "helloa.h"  
  3. class helloB :  
  4.     public helloA  
  5. {  
  6. public:  
  7.     helloB(void);  
  8.     ~helloB(void);  
  9.      void func()const{printf("B");}  
  10. };  
handel.cpp
[cpp]  view plain  copy
 
  1. #include "stdafx.h"  
  2. #include "helloA.h"  
  3. #include "helloB.h"  
  4. #include <vector>  
  5. using namespace std;  
  6.   
  7. int _tmain(int argc, _TCHAR* argv[])  
  8. {  
  9.     vector<helloA> vec;  
  10.     helloA a;  
  11.     helloB b;  
  12.     vec.push_back(a);  
  13.     vec.push_back(b);  
  14.       
  15.     for ( vector<helloA>::iterator iter=vec.begin();iter!=vec.end();iter++)  
  16.     {  
  17.         (*iter).func();  
  18.     }  
  19.   
  20.     return 0;  
  21. }  
運行的結果:
 
 
原因:vec.push_back(b);  ,其實把截斷了,將b轉化為了它的基類helloA.
 
如何解決這個問題,可以用指針代替對象方法:如:vector<helloA*>vec;這樣做可以達到多態的目的,但程序員必須接管內存管理,例如,更改下handel.cpp代碼:
 
[cpp]  view plain  copy
 
  1. vector<helloA*> vec;  
  2.     helloA *a = new helloA;  
  3.     helloB *b = new helloB;  
  4.     vec.push_back(a);  
  5.     vec.push_back(b);  
  6.   
  7.     for ( vector<helloA*>::iterator iter=vec.begin();iter!=vec.end();iter++)  
  8.     {  
  9.         (*iter)->func();  
  10.     }  

運行結果:
 
 
 
效果達到,但問題來了,這里假如vec的生命周期結束了,vec不會主動釋放b所占用的內存,如果不手動delete b,就會產生內存泄漏。
 
接下來,就實現下句柄類,來解決如上問題。
 
更改下helloA,helloB的代碼:
helloA.h
[cpp]  view plain  copy
 
  1. #pragma once  
  2. class helloA  
  3. {  
  4. public:  
  5.     helloA(void);  
  6.     ~helloA(void);  
  7.     virtual void func()const{printf("A");}  
  8.     virtual helloA* clone() const {return new helloA(*this);}  
  9. };  
helloB.h
[cpp]  view plain  copy
 
  1. #pragma once  
  2. #include "helloa.h"  
  3. class helloB :  
  4.     public helloA  
  5. {  
  6. public:  
  7.     helloB(void);  
  8.     ~helloB(void);  
  9.      void func()const{printf("B");}  
  10.      virtual helloB* clone() const{return new helloB(*this);}  
  11. };  
同時,添加sample類,記得把sample.cpp的代碼注釋掉,我們只在sample頭文件更改代碼即可。
sample.h
[cpp]  view plain  copy
 
  1. #pragma once  
  2. #include "helloA.h"  
  3. #include "helloB.h"  
  4. #include <stddef.h>  
  5. class sample  
  6. {  
  7. public:  
  8.   
  9.     sample():p(0),use(1){};  
  10.     sample(const helloA& a):p(a.clone()),use(1){};  
  11.     sample(const sample&i):p(i.p),use(i.use){use++;}  
  12.     ~sample(){decr_use();};  
  13.     sample& operator = (const sample& i)  
  14.     {  
  15.         use++;  
  16.         decr_use();  
  17.         p = i.p;  
  18.         use = i.use;  
  19.         return *this;  
  20.     }  
  21.     const helloA *operator->() const {if (p)return p;}  
  22.   
  23.     const helloA &operator*() const{if(p)return *p;}  
  24. private:  
  25.     helloA* p;  
  26.     size_t use;  
  27.     void decr_use(){if (-use == 0)delete p;}  
  28. };  
回到main函數,更改代碼
handle.cpp
[cpp]  view plain  copy
 
  1. // handle.cpp : 定義控制台應用程序的入口點。  
  2. //  
  3.   
  4. #include "stdafx.h"  
  5. #include "helloA.h"  
  6. #include "helloB.h"  
  7. #include "sample.h"  
  8. #include <vector>  
  9. #include <list>  
  10. using namespace std;  
  11.   
  12.   
  13. int _tmain(int argc, _TCHAR* argv[])  
  14. {  
  15.   
  16.     vector<sample> vec;  
  17.     helloA a;  
  18.     helloB b;  
  19.   
  20.     sample sample1(a);  
  21.     sample sample2(b);  
  22.   
  23.     vec.push_back(sample1);  
  24.     vec.push_back(sample2);  
  25.   
  26.       
  27.     for ( vector<sample>::iterator iter=vec.begin();iter!=vec.end();iter++)  
  28.     {  
  29.         (*iter)->func();  
  30.     }  
  31.   
  32.     return 0;  
  33. }  
運行結果:
 
 
 
我們得到了正確的輸出,如同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/


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM