类型重定义typedef | |
|
============================================================
MFC源代码:
#ifdef STRICT
typedef void *HANDLE;
#define DECLARE_HANDLE(name) struct name##__ { int unused; }; typedef struct name##__ *name
#else
typedef PVOID HANDLE;
#define DECLARE_HANDLE(name) typedef HANDLE name
#endif
DECLARE_HANDLE(HMODULE);
DECLARE_HANDLE(HINSTANCE);
DECLARE_HANDLE(HLOCAL);
DECLARE_HANDLE(HGLOBAL);
DECLARE_HANDLE(HDC);
DECLARE_HANDLE(HRGN);
DECLARE_HANDLE(HWND);
DECLARE_HANDLE(HMENU);
DECLARE_HANDLE(HACCEL);
DECLARE_HANDLE(HTASK);
理解:
HANDLE就是PVOID,也就是无类型指针,
上面这些资源的句柄Handles都不过是指向struct的指针,至于这个struct的用处,连M$都说unused了,现在解释下M$这么做的意义,这就是所谓数据封装,你可以在你的程序中把M$的内部结构指针传来传去,可是你却不知道它到底指向的内容是什么。
句柄与指针确实是完全不同的两个概念。句柄仅仅是一个32位整数,WIN32中用于标记某个系统或进程的对象,可以理解为对象索引(由于M$未完全公开相关技术,在一定程度上只能如此理解),这个索引更像是一种映射关系(从句柄到对象指针的映射),而不是纯粹意义上的“数组下标”。
句柄可以理解为用于指向或标识内存的一块“资源”,这些资源如:文件(file)、内存块(block of memory)、菜单(menu)等等。操作系统通过句柄来定位核心对象和系统资源。
指针即为指向内存的“数据或指令”某一单元。
说的确切一点,句柄实际上是一种指向某种资源的指针,但与指针又有所不同:指针对应着一个数据在内存中的地址,得到了指针就可以自由地修改该数据。Windows并不希望一般程序修改其内部数据结构,因为这样太不安全。所以Windows给每个使用GlobalAlloc等函数声明的内存区域指定一个句柄(本质上仍是一个指针,但不要直接操作它),平时你只是在调用API函数时利用这个句柄来说明要操作哪段内存。
====================================================
函数指针(function pointer),是一个让人既爱又恨的东东,爱的是,它的确是很强大,用的好的话,能写出结构很清晰的代码,比较常见的就是一些事件处理模型中用到的处理事件的回调函数等。恨的是,函数指针的使用,是一个比较高级的话题,对一般的程序员来说,这个语法不容易掌握,用的时候容易出错,调试的时候还比较麻烦。C++中提出了虚函数(virtual function),有人说可以用虚函数功能来替代函数指针了,函数指针可以被抛弃了,但是,我们知道,使用虚函数有额外的开销的,因此,很多追求高效率的程序员还是更加钟爱函数指针。下面就函数指针的使用,进行举例一一说明:
1. 最普通的使用方式,函数指针指向普通函数的情况
#include <stdio.h> typedef void (*Handle)(void *); void HandleChar(void * pArg) { printf("%c\n", *(char *)pArg); } void HandleInt(void * pArg) { printf("%d\n", *(int *)pArg); } void TestHandle(void * pArg, Handle pHandle) { (*pHandle)(pArg); } int main() { char bCh = 'I'; TestHandle(&bCh, &HandleChar); int nNum = 100; TestHandle(&nNum, &HandleInt); }
2. 函数指针指向静态类成员函数的情况
#include <stdio.h> class Test { public: static void HandleChar(void * pArg) { printf("%c\n", *(char *)(pArg)); } static void HandleInt(void * pArg) { printf("%d\n", *(int *)(pArg)); } }; typedef void (*Handle)(void *); void TestHandle(void * pArg, Handle pHandle) { (*pHandle)(pArg); } int main() { char bCh = 'I'; TestHandle(&bCh, &Test::HandleChar); int nNum = 100; TestHandle(&nNum, &Test::HandleInt); }
3.函数指针指向普通的类成员函数,在类成员函数中的调用的情况
#include <stdio.h> class Test { public: typedef void (Test::*Handle)(void *); void HandleChar(void * pArg) { printf("%c\n", *(char *)(pArg)); } void HandleInt(void * pArg) { printf("%d\n", *(int *)(pArg)); } void TestHandle(void * pArg, Handle pHandle) { (this->*pHandle)(pArg); } }; int main() { Test oTest; char bCh = 'I'; oTest.TestHandle(&bCh, &Test::HandleChar); int nNum = 100; oTest.TestHandle(&nNum, &Test::HandleInt); }
3.函数指针指向类成员函数,在全局函数中调用的情况。
#include <stdio.h> class Test { public: void HandleChar(void * pArg) { printf("%c\n", *(char *)(pArg)); } void HandleInt(void * pArg) { printf("%d\n", *(int *)(pArg)); } }; typedef void (Test::*Handle)(void *); void TestHandle(Test &obj, void * pArg, Handle pHandle) { (obj.*pHandle)(pArg); } int main() { Test oTest; char bCh = 'I'; TestHandle(oTest, &bCh, &Test::HandleChar); int nNum = 100; TestHandle(oTest, &nNum, &Test::HandleInt); }
通过上面的例子,以及结合我自己在写代码过程中一的一些经验,我觉得,在使用函数指针时,需要注意以下几点:
1. 在使用函数指针的时候,最好用typedef进行类型定义,这样语法看起会来会比较清晰,减少出错概率
2. 当类成员函数作为函数的函数指针型参数时,一定要加上类名做其作用域前缀,如上面的Test::HandleChar和Test::HandleInt
3. 当函数指针为在成员函数类型时,调用某个确定的函数时,一定要显式地指名其所在的域,如上面的(this->*pHandle)(pArg)和(obj.*pHandle)(pArg)
OK, that’s all, good luck!
http://www.wuzesheng.com/?p=348
====================================
文章评论(0条评论)
登录后参与讨论