浅谈一般函数指针和类的非静态成员…

来源:互联网 发布:python 对象转字符串 编辑:程序博客网 时间:2024/06/07 03:34
1,语法
2,应用场景
3,应用技巧
4,回调函数
参考《C++ Primer Plus》《Effective C++》和“博客:类的成员函数指针”

一、函数指针的一般原理
与数据项类似,函数也有地址。函数的地址是存储其机器语言代码的内存的起始地址。函数调用,实际上就是执行内存在以函数地址为起始点的这段机器码,故只要获取函数地址,即可执行函数调用。而函数指针就是这样一中指向某类特定函数的的内存的起始地址的指针类型。可以编写将另一个函数的地址作为参数的函数,它运行在不同的时间传递不同的函数的地址,这意味着可以在不同的时间使用不同的函数,它在一定程度上可以替代“继承多态”的功能,参考《EffectiveC++》item35
与类的非静态数据成员不同,类的成员函数不会在运行时为每个类的实例对象生成一份专有的机器语言代码,类的成员函数在内存中只有一份,即类的成员函数的地址也是唯一的。这也就解释了,取类的成员函数的地址时,只需要将类作为限定,而不需要知道类的实例对象。从内存角度看,类的成员函数和一般函数是一样的,特别是类的静态成员函数。但是,类的成员函数为了防止与其他类的成员函数名称冲突,编译器会添加一些额外的符号进行区分,故需要由类名进行引导搜素。

二、一般函数指针的用法
一般函数指针指的是除“类的非静态成员函数指针”之外的函数指针,它没有类的限定,只需要匹配函数签名(signature)和返回值即可。参考“博客:一般函数指针和类的成员函数指针”。在使用上有两种简化方式,一种是使用auto,另一种是使用typedef。如例:
已知函数:
int Func(int a, int b);
可定义函数指针(方式一):
auto pFunc = &Func;
方式二:
typedef int(*pFunc )(int, int);
pFunc pfFunc =&Func;
第二种方式适合反复使用和作为参数。

三、类的非静态成员函数指针的用法
类的静态成员函数与一般函数类似,其函数指针用法参考上一条,故以下将类的非静态成员函数简称类的成员函数。而类的成员函数指针在使用的时候,需要使用类名进行限定。
参考“博客:一般函数指针和类的成员函数指针”:
classCA;
typedefint(CA::*pClassFunc)(int ,int);
注意域运算符和指针标示符的顺序。此外,一般可以将该typedef放在类的构造函数附近进行声明,限定其作用域。
intResule(CA* pA, pClassFunc pfFunc, int a, int b)
{
   return (pA->*pClassFunc)(a, b);
}
注意函数调用符和解引用符的顺序。

四、函数指针应用
1,增加接口的弹性,提高代码复用。示例(来自于《C++Primer Plus》)
假设要设计一个名为estimate()的函数,估算编写指定行数的代码所需的时间,并且希望不同的程序员都将使用该函数。对于所有用户来说,estimate()中的一部分代码都是相同的,但该函数运行每个程序员提供自己的算法来估算时间。为实现这种目标,采用的机制是,将程序要使用的算法函数的地址传递给esimate()。
// fun_ptr.cpp -- pointer tofunctions
#include
double betsy(int);
double pam(int);

void estimate(int lines, double (*pf)(int));

int main()
{
    using namespacestd;
    int code;
    cout << "How manylines of code you need ? ";
    cin >> code;
    cout << "Here'sBetsy's estimate: \n";
   estimate(code,betsy);
    cout << "Here'sPam's estimate: \n";
    estimate(code,pam);
    cin.get();
    return 0;
}

double betsy(int lns)
{
    return 0.05 *lns;
}

double pam(int lns)
{
    return 0.03 * lns +0.0004 * lns * lns;
}

void estimate(int lines, double (*pf)(int))
{
    using namespacestd;
    cout << lines<< " lines will take ";
    cout <<(*pf)(lines) << " hour(s)\n";
}
附:通过这种设计,可以复用estimate()函数中除算法外的其他部分。如果将estimate作为接口,它将具有较强的弹性,用户可以根据自己的需要自由选择需要的函数传递给它。特别的,用户在不修改该接口(estimate())的情况下,可以自己实现一个算法函数,传递给该接口,实现不同个的计算效果。
STL的算法函数,传递给functor参数的设计方式也是基于这种设计模式。如自定义排序方式,参考《C++Primer Plus》P681。

2,替代虚函数机制实现多态,参考《EffectiveC++》item35。它实际上也是Strategy设计模式的一种应用。(策略与机制相分离)示例如下:
计算游戏任务的健康指数
classGameCharacter;    //前置声明
//以下函数是计算健康指数的缺省算法
intdefaultHealthCalc(const GameCharacter& gc);
classGameCharacter
{
   public:
       typedefint (*HealthCalcFunc)(constGameCharacter&);
      explict GameCharacter(HealthCalcFunc hcf= defaultHealthCalc)
        :healthFunc(hcf)
      {}
       int healthValue() const {return healthFunc(*this); }
      ...
   private:
      HealthCalcFunc healthFunc;      // 类成员是一个函数指针
}

五,函数指针用于回调
参考Qt中的“qInstallMessageHandler”的用法






0 0
原创粉丝点击