函数指针

函数指针:是指向函数的指针变量,在C编译时,每一个函数都有一个入口地址,那么这个指向这个函数的函数指针便指向这个地址。

函数指针的用途是很大的,主要有两个作用:用作调用函数和做函数的参数。

函数指针的声明方法:

数据类型标志符 (指针变量名) (形参列表); 一般函数的声明为:

int func ( int x );

而一个函数指针的声明方法为:

int (*func) (int x);

前面的那个(*func)中括号是必要的,这会告诉编译器我们声明的是函数指针而不是声明一个具有返回型为指针的函数,后面的形参要视这个函数指针所指向的函数形参而定。

1
2
3
4
5
6
int (*f)(int, int); // 声明函数指针,指向返回值类型为int,有两个参数类型都是int的函数
int max(int a, int b) {
    return a > b ? a : b;
}
f = max; // 函数指针f指向求最大值的函数max
int c = (*f)(1, 2);//利用函数指针执行函数

然而这样声明我们有时觉得非常繁琐,于是typedef可以派上用场了,我们也可以这样声明:

1
2
typedef int (*PF) (int x);
PF pf;

这样pf便是一个函数指针,方便了许多。

1
2
3
4
5
6
7
8
9
typedef void (*PFT) ( char ,int );
void bar(char ch, int i)
{
    cout<<"bar "<<ch<<''<<i<<endl;
    return ;
}
PFT pft;
pft = bar;
pft('e',91);

例子中函数指针pft指向了一个已经声明的函数bar(),然后通过pft来实现输出字符和整型的目的。

函数指针另一个作用便是作为函数的参数,我们可以在一个函数的形参列表中传入一个函数指针,然后便可以在这个函数中使用这个函数指针所指向的函数,这样便可以使程序变得更加清晰和简洁,而且这种用途技巧可以帮助我们解决很多棘手的问题,使用很小的代价就可获得足够大的利益(速度+复杂度)。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
typedef void (*PFT) ( char ,int );
void bar(char ch, int i)
{
    cout<<"bar "<<ch<<''<<i<<endl;
    return ;
}
void foo(char ch, int i, PFT pf)
{
    pf(ch,i);
    return ;
}
PFT pft;
pft = bar;
foo('e',12,pft);

上述例子我们首先利用一个函数指针pft指向bar(),然后在foo()函数中使用pft指针来调用bar(),实现目的。将这个特点稍加利用,我们就可以构造出强大的程序,只需要同样的foo函数便可以实现对不同bar函数的调用。

仿函数

从一般的函数回调意义上来说,函数对象和函数指针是相同的,但是函数对象却具有许多函数指针不具有的有点,函数对象使程序设计更加灵活,而且能够实现函数的内联(inline)调用,使整个程序实现性能加速。

就实现观点而言,仿函数其实上就是一个“行为类似函数”的对象。为了能够 “行为类似函数”,其类别定义中必须自定义(或说改写、重载)functioncall运算子(operator).

拥有这样的运算子后,我们就可以在仿函数的对象后面加上一对小括号,以此调用仿函数所定义的operator (),像这样:

1
2
3
4
5
6
7
8
9
#include <functional>
#include <iostream>
using namespace std
int main{)
{
greater<int> ig;
cout <<boolalpha << ig(4, 6);	// (A)	false1
cout << greater<int>()(6, 4);	// (B) true
}

其中第一种用法比较为大家所熟悉,greater ig的意思是产生一个名为ig的对象,ig(4,6)则是调用其 operator(),并给予两个参数4,6。

第二种用法中的greater ()意思是产生一个临时(无名的)对象,之后的(4,6)才是指定两个参数4,6。

STL中的谓词

谓词(predicate)是一个判断式,一个返回bool值的函数或者仿函数,几元就是函数有几个参数,至于定义和使用,函数定义和一般的函数定义一样。

谓词如果可以用仿函数实现,那么你应该用仿函数,而不要用回调。原因在于:

  1. 仿函数比一般函数更灵巧,因为它可以拥有状态。

  2. 执行速度上,仿函数通常比函数指针更快。

    仿函数的operator()函数通常被声明为内联的(或者通过inline显式地声明,或者被定义在类定义的内部,即隐式内联),它的函数体将可以直接在编译期确定。

    如果回调函数也使用inline, 若这个回调函数很简单,那么也可能和仿函数同时被调用。在这种情形下,函数指针与仿函数性能相同。

    如果回调函数是非inline函数的话,或者比较复杂而无法内联(这种情况很常见,函数指针机制本身就抑制内联)。此时CallBack函数作为一个函数指标传入,编译器会产生一个间接的函数调用。仿函数虽然需要先实例化函数模板和类模板,然后调用相应的operator()函数,但是所有这些负担都会在编译期结束,在运行时以内联方式进行函数调用,比起普通的回调函数速度要快相当多。

常用仿函数

仿函数在头文件中,很多情况下即使不用声明头文件也可以使用仿函数。

算术类

plus 加法

Addition function object class (class template )

minus 减法

Subtraction function object class (class template )

multiplies 乘法

Multiplication function object class (class template )

divides 除法

Division function object class (class template )

modulus 取余

Modulus function object class (class template )

negate 取反

Negative function object class (class template )

关系运算类

equal_to 等于

Function object class for equality comparison (class template )

not_equal_to 不等于

Function object class for non-equality comparison (class template )

greater 大于

Function object class for greater-than inequality comparison (class template )

greater_equal 大于等于

Function object class for greater-than-or-equal-to comparison (class template )

less 小于

Function object class for less-than inequality comparison (class template )

less_equal 小于等于

Function object class for less-than-or-equal-to comparison (class template )

逻辑运算类

logical_and 与

Logical AND function object class (class template )

logical_or 或

Logical OR function object class (class template )

logical_not 非

Logical NOT function object class (class template )

位运算 bit_and 按位与

Bitwise AND function object class (class template )

bit_or 按位或

Bitwise OR function object class (class template )

bit_xor 按位异或

Bitwise XOR function object class (class template )

参考:http://www.cplusplus.com/