C++回调函数

在学习C++的函数和实习的过程中,我发现回调函数在工作中用的特别多,下面来记录总结一下:

C++函数是利用函数签名(name mangling)完成对于函数的区分的。
同时,C++函数支持重载,但是在重载的过程中,会出现下列问题:

1
2
3
4
5
6
7
8
9
10
11
12
int test(int a)
{
return a;
}

int test(int a = 1, double b = 2.0)
{
return a+b;
}

// test(1) :这样会报错
// 可以使用函数指针解决这个问题

指向函数的指针#

1
2
3
4
5

// 函数指针
int (*p)(int);
p = test;
cout << (*p)(1);

每个函数都占有一段内存单元,它们有一个起始地址,指向函数入口地址的指针称为函数指针。

形式:(注意指针名和*必须用括号括起来)

1
2
3
return_type (*)(parameter_type_1, parameter_type_2, parameter_type_3)
// i.e. a pointer to foo has the type:
int (*)(int)

例如:int(*p)(int)

同时,也可以使用using声明让其可读性更强:

1
using f_int_t = int(*)(int);

从而我们可以用下面两种方式实现回调函数:

1
2
3
4
5
// foobar having a callback argument named moo of type
// pointer to function returning int taking int as its argument
int foobar (int x, int (*moo)(int));
// if f_int is the function pointer typedef from above we can also write foobar as:
int foobar (int x, f_int_t moo);

下面再给出一个例子:

指向函数的指针可以实现很多东西,比如回调函数:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
int maxValue(int x, int y)
{
return x > y ? x : y;
}

int minValue(int x, int y)
{
return x < y ? x : y;
}

int add(int x, int y)
{
return x+y;
}

// 回调函数
int pNum(int x, int y, int(*p)(int a, int b))
{
// 真正调用函数的一方在函数体内部
cout << p(x,y) << endl;
}

pNum(x,y,maxValue);
pNum(x,y,minValue);
pNum(x,y,add);

回调函数#

什么是回调函数?简单来说,回调函数是

  • 可执行代码 作为 参数 传入 其他的可执行代码
  • 并由 其他的可执行代码 执行这段 可执行代码

其具体过程主要可以由下列逻辑表示:

1
2
3
4
5
6
7
8
9
10
11
A() {
// output P
}

B(fn) {
fn(); // B knows only fn, not A
// B treats fn as a variable
}

B(A); // B called at T
// B calling fn() (i.e. calling A())

使用回调函数主要可以写出更为generic的代码,使代码逻辑与被调用函数分离,并可以为不同的回调函数使用。

标准库头文件用了很多回调的方法,如for_each接受一个UnaryFunction f也就是unary的回调函数:

1
2
3
4
5
6
7
8
template<class InputIt, class UnaryFunction>
UnaryFunction for_each(InputIt first, InputIt last, UnaryFunction f)
{
for (; first != last; ++first) {
f(*first);
}
return f;
}

回调函数实现方法#

  1. 函数指针(function pointers)上面已经介绍过了

  2. 指向成员函数的指针(Pointer to member function)

    这是一种特殊的函数指针,因为其需要一个类去操作:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    struct C
    {
    int y;
    int foo(int x) const { return x+y; }
    };

    // A pointer to member function type for some class T has the notation
    // can have more or less parameters
    return_type (T::*)(parameter_type_1, parameter_type_2, parameter_type_3)
    // i.e. a pointer to C::foo has the type
    int (C::*) (int)


    // i.e. a type `f_C_int` representing a pointer to member function of `C`
    // taking int returning int is:
    typedef int (C::* f_C_int_t) (int x);

    // The type of C_foo_p is a pointer to member function of C taking int returning int
    // Its value is initialized by a pointer to foo of C
    int (C::* C_foo_p)(int) = &C::foo;
    // which can also be written using the typedef:
    f_C_int_t C_foo_p = &C::foo;

    举例:将指向成员函数的指针作为回调传入函数:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    // C_foobar having an argument named moo of type pointer to member function of C
    // where the callback returns int taking int as its argument
    // also needs an object of type c
    int C_foobar (int x, C const &c, int (C::*moo)(int));
    // can equivalently declared using the typedef above:
    int C_foobar (int x, C const &c, f_C_int_t moo);

    int C_foobar (int x, C const &c, int (C::*moo)(int))
    {
    return x + (c.*moo)(x); // function pointer moo called for object c using argument x
    }
    // analog
    int C_foobar (int x, C const &c, f_C_int_t moo)
    {
    return x + (c.*moo)(x); // function pointer moo called for object c using argument x
    }

    如果传入的是指向c的指针,那么必须也对c解引用:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    int C_foobar_2 (int x, C const * c, int (C::*meow)(int))
    {
    if (!c) return x;
    // function pointer meow called for object *c using argument x
    return x + ((*c).*meow)(x);
    }
    // or equivalent:
    int C_foobar_2 (int x, C const * c, int (C::*meow)(int))
    {
    if (!c) return x;
    // function pointer meow called for object *c using argument x
    return x + (c->*meow)(x);
    }

    C my_c{2}; // aggregate initialization
    int a = 5;
    int b = C_foobar(a, my_c, &C::foo); // call C_foobar with pointer to foo as its callback
  3. 使用std::function

Reference#

  1. Callback functions in C++