分享

函数指针详解

 lchjczw 2012-11-22

这篇文章把函数指针的各种常用情况做了一个详解的总结。

 

1. 指向普通函数的指针

 

很简单,如下的例子可以说明基本格式和用法:

  1. int int_add(int a, int b)  
  2. {  
  3.     return (a+b);  
  4. }  
  5. int int_sub(int a, int b)  
  6. {  
  7.     return (a-b);  
  8. }  
  9. int (*int_operator)(intint) = int_add;  
  10.    
  11. int _tmain(int argc, _TCHAR* argv[])  
  12. {  
  13.     cout<<int_operator(4, 5)<<endl; // output 9  
  14.     int_operator = int_sub;  
  15.     cout<<int_operator(4, 5)<<endl; // output -1  
  16.     return 0;  
  17. }  
  18.    
 

 

上例中,int_operator会被编译器解释成类型int(*)(int, int)的一个指针。

调用方式还可以写作:(*int_operator)(4, 5),这样的好处是让人一眼就能看到int_operator是一个函数指针。

注意:函数指针和指向函数的返回值的类型和参数都必须严格一致;

 

2. 函数指针数组

 

我们还可以声明一个函数指针的数组,比如:

int (*pFuncArray[10])();

[]的优先级高于*,该语句将pFuncArray声明为拥有10个元素的数组,每一个元素都是指向一个函数的函数指针,该函数没有参数,返回值类型为int

 

注意不能写作:int ((*pFuncArray)[10])(),这样会产生编译错误;

(*pFuncArray)[10]表明了pFuncArray是一个指针,该指针指向一个含有 10个元素的数组

其类型为int()(),显然,编译不能通过。

 

将上面的声明转换为typedef格式,会使程序可读性增加:

typedef int(*pFunc)();

pFunc pFuncArray[10];

如果需要调用其中的第三个函数,那么调用方式为:pFuncArray[2]();

 

3. 指向‘函数指针数组’的指针

还可以声明一个指向‘函数指针数组’的指针,比如下面的例子代码:

 


  1. int cmp_len(const char *str1, const char *str2)  
  2. {return ((int)strlen(str1) - (int)strlen(str2));}  
  3. int cmp_str(const char *str1, const char *str2)  
  4. {return strcmp(str1, str2);}  
  5.    
  6. typedef int(*PCMP_FUNC)(const char*, const char*);  
  7.    
  8. PCMP_FUNC pCmpFuncs[2] =  
  9. {  
  10.     cmp_len,  
  11.     cmp_str,  
  12. };  
  13. // 声明指向pCmpFuncs的指针  
  14. PCMP_FUNC (*ppCmps)[2] = &pCmpFuncs;  

 

 

声明分解说明如下:

(*ppCmps):表明ppCmps是一个指针;

(*ppCmps)[2]:后面紧跟[2],表明ppCmps是一个指向‘两个元素数组’的指针

PCMP_FUNC表明了该数组元素的类型,它是指向函数的指针,返回值为int,有两个const char*类型的参数;

实际上语句PCMP_FUNC (*ppCmps)[2] = &pCmpFuncs;

将会被编译器解释为:

int (*(*ppCmps)[2])(const char*, const char*) = &pCmpFuncs;

声明分解:

(*ppCmps):表明ppCmps是一个指针;

(*ppCmps)[2]:后面紧跟[2],表明ppCmps是一个指向‘两个元素数组’的指针

int (*)(const char*, const char *):表明了该数组元素的类型,它是指向函数的指针,返回值为int,有两个const char*类型的参数;

 

3. 函数指针与类

 

C++语言中,使用函数指针可以指向类的一个成员函数或变量,虽然这种用法很少能用到,至少我是没有用过,不过了解一下还是有点必要的。

为了支持这类指针,C++有三个特殊的运算法符:::*.->.*

指向成员函数的指针必须与向其赋值的函数类型匹配,这包括:1)参数的类型和个数;2)返回值类型;3)它所属的类型;

指向成员变量的指针必须与向其赋值的变量类型匹配,这包括:1)变量类型;2)它所属的类型;

成员函数和变量必须被绑定到一个对象或者指针上,然后才能得到调用对象的this指针,然后才能指向成员变量或函数;

AClass的成员变量int m_iValue,其完整类型是:int型的类AClass的成员m_iValue

AClass的成员函数int Add(int),其完整类型是:返回值为int型,带一个int类型参数的类AClass的成员Add

 

注意:指向类的静态变量或静态成员函数的指针和普通成员不同;

 

3.1 指向类成员变量的指针

 

有了上面的一些说明,看下面的例子就很容易理解了;

.* 是一个新的操作符,表明是指向成员操作符的指针(另一个是->*,是指针对象的调用方式)

 

 

  1.    
  2. class AClass  
  3. {  
  4. public:  
  5.     void Add(int a){m_iValue += a;}  
  6.     int  m_iValue;  
  7. };  
  8. int _tmain(int argc, _TCHAR* argv[])  
  9. {  
  10.     AClass a;  
  11.    // 声明并指向AClass的一个成员变量的指针  
  12.     int AClass::*pValue = &AClass::m_iValue;  
  13.     // 或者如下方式:  
  14.     // int AClass::*pValue;// 指针变量声明  
  15.     // pValue = &AClass::m_iValue;// 指向A的m_iValue成员  
  16.     a.*pValue = 4; // 使用方式,赋值  
  17.     cout<<a.m_iValue<<endl; // 输出4  
  18.     return 0;  
  19. }  
 

3.2 指向类成员函数的指针

 

有了上面的一些说明,看下面的例子就很容易理解了;

下面的例子中,注意调用方式:(a.*pAAdd)(5);不能写作a.*pAAdd(5);

因为操作符()的优先级是高于.*的因此,它将被解释为a.*(pAAdd(5));显然这是不被支持的。

 

  1.    
  2. class AClass  
  3. {  
  4. public:  
  5.     void Add(int a){m_iValue += a;}  
  6.     int  m_iValue;  
  7. };  
  8. // 指向类AClass成员函数的指针的声明方式  
  9. typedef void (AClass::*pAFunc)(int);  
  10. // 声明一个指向AClass::Add()的函数指针  
  11. pAFunc pAAdd = &(AClass::Add);  
  12.    
  13. int _tmain(int argc, _TCHAR* argv[])  
  14. {  
  15.     AClass a;  
  16.     // 声明并指向AClass的一个成员变量的指针  
  17.     int AClass::*pValue = &AClass::m_iValue;  
  18.     // 或者如下方式:  
  19.     // int AClass::*pValue;// 指针变量声明  
  20.     // pValue = &AClass::m_iValue;// 指向A的m_iValue成员  
  21.     a.*pValue = 4; // 使用方式,赋值  
  22.     cout<<a.m_iValue<<endl; // 输出  
  23.     (a.*pAAdd)(5); // 指向成员函数指针的调用方式  
  24.     cout<<a.m_iValue<<endl; // 输出  
  25.     return 0;  
  26. }  
 



3.3 指向类静态成员的指针

 

类的静态成员属于该类的全局对象和函数,并不需要this指针;因此指向类静态成员的指针声明方式和普通指针相同。

该类指针和普通指针的声明和调用方式完全相同;唯一的不同就是设置指向的对象时,仍然需要类信息,这一点和指向普通成员的指针相同。

下面的例子可以说明使用方式。

 

 

  1. class AClass  
  2. {  
  3. public:  
  4.     static void Add(int a){m_iValue += a;}  
  5.     static int  m_iValue;  
  6. };  
  7. int AClass::m_iValue;  
  8.    
  9. typedef void(*pAAdd)(int);  
  10.    
  11. int _tmain(int argc, _TCHAR* argv[])  
  12. {  
  13.     // 声明并指向AClass的一个静态成员变量的指针  
  14.     int *pValue = &AClass::m_iValue;  
  15.     // 或者如下方式:  
  16.     // int *pValue;// 指针变量声明  
  17.     // pValue = &AClass::m_iValue;// 指向A的m_iValue成员  
  18.     *pValue = 4; // 使用方式同普通指针,赋值  
  19.     cout<<*pValue<<endl; // 输出  
  20.     pAAdd p = &AClass::Add;  
  21.     p(5); // 调用方式同普通函数指针  
  22.     cout<<*pValue<<endl; // 输出  
  23.     return 0;  

    本站是提供个人知识管理的网络存储空间,所有内容均由用户发布,不代表本站观点。请注意甄别内容中的联系方式、诱导购买等信息,谨防诈骗。如发现有害或侵权内容,请点击一键举报。
    转藏 分享 献花(0

    0条评论

    发表

    请遵守用户 评论公约

    类似文章 更多