C++中句柄
一、句柄的概念
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/
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 从 HTTP 原因短语缺失研究 HTTP/2 和 HTTP/3 的设计差异
· AI与.NET技术实操系列:向量存储与相似性搜索在 .NET 中的实现
· 基于Microsoft.Extensions.AI核心库实现RAG应用
· Linux系列:如何用heaptrack跟踪.NET程序的非托管内存泄露
· 开发者必知的日志记录最佳实践
· TypeScript + Deepseek 打造卜卦网站:技术与玄学的结合
· Manus的开源复刻OpenManus初探
· 写一个简单的SQL生成工具
· AI 智能体引爆开源社区「GitHub 热点速览」
· C#/.NET/.NET Core技术前沿周刊 | 第 29 期(2025年3.1-3.9)
2015-08-20 Python|绝不乱入的靠谱书单
2015-08-20 当你念大学时,你需要忙些什么?
2015-08-20 Productivity tips, tricks and hacks for academics (2015 edition)
2015-08-20 如何画好科技论文中的插图
2015-08-20 怎样出色完成 1 分钟左右的英语自我介绍?
2015-08-20 matlab的rem()和mod()函数