c++实现回调函数

CPP实现回调函数

得到函数的地址是其中一个关键步骤。
普通和函数和类的静态成员函数都分配有确定的函数地址,但是类的普通函数是类共用的,并不会给类的每一个实例都分配一个独立的成员函数,这样就太浪费存储资源了。所以类的非静态函数作为回调函数是有区别的

普通函数作为回调函数

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
#include <iostream>

void programA_FunA1() { printf("I'am ProgramA_FunA1 and be called..\n"); }

void programA_FunA2() { printf("I'am ProgramA_FunA2 and be called..\n"); }

void programB_FunB1(void (*callback)()) {
printf("I'am programB_FunB1 and be called..\n");
callback();
}

int main(int argc, char **argv) {
programA_FunA1();

programB_FunB1(programA_FunA2);
}

类的静态函数作为回调函数

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
#include <iostream>

class ProgramA {
public:
void FunA1() { printf("I'am ProgramA.FunA1() and be called..\n"); }

static void FunA2() { printf("I'am ProgramA.FunA2() and be called..\n"); }
};

class ProgramB {
public:
void FunB1(void (*callback)()) {
printf("I'am ProgramB.FunB1() and be called..\n");
callback();
}
};

int main(int argc, char **argv) {
ProgramA PA;
PA.FunA1();

ProgramB PB;
PB.FunB1(ProgramA::FunA2);
}

可以看出,以上两种方式没有什么本质的区别。
但这种实现有一个很明显的缺点:static 函数不能访问非static 成员变量或函数,会严重限制回调函数可以实现的功能。

类的非静态函数作为回调函数

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
#include <iostream>

class ProgramA {
public:
void FunA1() { printf("I'am ProgramA.FunA1() and be called..\n"); }

void FunA2() { printf("I'am ProgramA.FunA2() and be called..\n"); }
};

class ProgramB {
public:
void FunB1(void (ProgramA::*callback)(), void *context) {
printf("I'am ProgramB.FunB1() and be called..\n");
((ProgramA *)context->*callback)();
}
};

int main(int argc, char **argv) {
ProgramA PA;
PA.FunA1();

ProgramB PB;
PB.FunB1(&ProgramA::FunA2, &PA); // 此处都要加&
}

这种方法可以得到预期的结果,看似完美,但是也存在明显不足。
比如在programB中FunB1还使用 programA的类型,也就我预先还要知道回调函数所属的类定义,当programB想独立封装时就不好用了。

std::funtion和std::bind的使用

C++编译器给每个“非静态的成员函数“增加了一个隐藏的指针参数,让该指针指向当前对象(函数运行时调用该函数的对象),在函数体中所有成员变量的操作,都是通过该指针去访问。只不过所有的操作对用户是透明的,即用户不需要来传递,编译器自动完成

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
26
27
28
29
30
31
32
33
34
35
36
#include <iostream>

#include <functional> // fucntion/bind

class ProgramA {
public:
void FunA1() { printf("I'am ProgramA.FunA1() and be called..\n"); }

void FunA2() { printf("I'am ProgramA.FunA2() and be called..\n"); }

static void FunA3() { printf("I'am ProgramA.FunA3() and be called..\n"); }
};

class ProgramB {
typedef std::function<void ()> CallbackFun;
public:
void FunB1(CallbackFun callback) {
printf("I'am ProgramB.FunB2() and be called..\n");
callback();
}
};

void normFun() { printf("I'am normFun() and be called..\n"); }

int main(int argc, char **argv) {
ProgramA PA;
PA.FunA1();

printf("\n");
ProgramB PB;
PB.FunB1(normFun);
printf("\n");
PB.FunB1(ProgramA::FunA3);
printf("\n");
PB.FunB1(std::bind(&ProgramA::FunA2, &PA));
}

std::funtion支持直接传入函数地址,或者通过std::bind指定。
简而言之,std::funtion是定义函数类型(输入、输出),std::bind是绑定特定的函数(具体的要调用的函数)。


c++实现回调函数
https://macbook-pro-gala.github.io/2023/06/08/c-实现回调函数/
作者
lyh
发布于
2023年6月8日
许可协议