函数对象
首先我们看一下函数指针。
函数指针是指向函数的指针变量,在编译程序时,每一个函数都有一个入口地址,而指向这个函数的函数指针便指向这个地址。函数指针的作用主要有两个:用作调用函数和用作函数的参数。
函数指针用作调用函数的实例如下:
#include <iostream> using namespace std; typedef void (*PFT) ( char ,int ); void bar(char ch, int i) { cout<<ch<<' '<<i<<endl; } int main() { PFT pft; pft=bar; pft('e',91); return 0; }
我们可以在一个函数的形参列表中传入一个函数指针,然后便可以在这个函数中使用该函数指针所指向的函数,这样可以使程序变得更加清晰和简洁。函数指针用作函数参数的实例如下:
#include <iostream> using namespace std; typedef void (*PFT) ( char ,int ); void bar(char ch, int i) { cout<<ch<<' '<<i<<endl; } void func(char ch,int i,PFT pf) { pf(ch,i); } int main() { PFT pft; pft=bar; func('e',91,pft); return 0; }
上述例子中我们首先利用一个函数指针pft来指向函数bar,然后在函数func中使用函数指针pft来调用函数bar。将这个特点稍加利用,我们就可以构造出强大的程序,只需要用同样的func函数便可以实现对不同bar函数的调用。
前面讲的是函数指针的应用,从一般的函数回调意义上来说,函数对象和函数指针是相同的,但是函数对象却具有许多函数指针所不具有的特点,从而使得程序设计更加灵活,而且能够实现函数的内联(inline)调用,使整个程序实现性能加速。
重载函数调用操作符的类,其对象常称为函数对象,即它们是行为类似函数的对象。一个类对象,表现出一个函数的特征,就是通过“对象名+(参数列表)”的方式来实现的,如果没有上下文,完全可以把它看作一个函数对待。这是通过重载类的operator()来实现的,如下:
#include <iostream> using namespace std; class A { public: int operator()(int x){return x;} }; int main() { A a; a(5); return 0; }
这样a就成为一个函数对象,当我们执行a(5)时,实际上就是利用了重载运算符函数operator(),函数对象既然是一个类对象,那么我们当然可以在函数形参列表中调用它,它完全可以取代指针,如下:
#include <iostream> using namespace std; class Func { public: void operator()(int a ,int b) { cout<<a<<'+'<<b<<'='<<a+b<<endl; } }; void addFunc(int a,int b,Func &func) { func(a,b); } int main() { Func func; addFunc(1,3,func); return 0; }
上述例子中首先定义了一个函数对象类,并重载了operator()函数,然后在函数addFunc中的形参列表中使用这个类对象。
如果运用泛型思维来考虑,可以定义一个函数模板类,来实现一般类型的数据相加减等操作,如下:
#include <iostream> using namespace std; class Func { public: template<class T> void operator()(T a ,T b) { cout<<a<<'+'<<b<<'='<<a+b<<endl; } }; template<class T> void addFunc(T a,T b,Func &func) { func(a,b); } int main() { Func func; addFunc(1,3,func); addFunc(1.4,2.3,func); return 0; }