C++中的回调函数——指向类成员的指针
2014-03-12 14:44
99 查看
C++中的回调函数
——指向类成员的指针
在C中我们能够很容易地实现一个指向函数的指针,因此能够方便地实现函数的回调机制。但是在C++中很多人认为类的成员函数不能作为回调函数,因此很多C程序不能移植到C++上来。其实不是这样的,在C++中我们同样可以获取类的成员函数的指针,也能方便地实现函数回调机制。
下面先说一下C/C++中普通函数作为回调函数的情况,然后再说C++ 中类成员函数做为回调函数的情况。
先说一下自己对于回调函数的理解:回调函数通常是指通过函数指针进行调用的函数。例如,我有一个函数指针pFunc,我可以在运行时将不同的函数的地址给pFunc,同时可以通过pFunc来调用它所指向的函数,此时被pFunc指向的函数就称为是一个回调函数。
那么什么是函数指针:首先函数指针是一个指针,只是他不是指向一个变量而是指向一个函数的地址,也就是指向一个函数的入口地址,我们也可以修改该指针,指向不同的函数。函数指针的一般形式如下:
这样,FUCNPTR就是一个函数指针的类型,我们可以直接通过它进行定义函数指针,如:
1
2
pFunc1 and pFunc2 point to the same function
在C/C++中普通函数最为回调函数很简单了,下面给出一个简单的例子,一目明了:
在这个例子中,increse()和decress()函数的指针都被存储在operations数组中,作为numOperation()函数的回调函数。用户调用numOperation()函数时,通过改变传入参数来指定要完成的操作,numOperation()函数会根据第二个参数调用不同的回调函数,完成操作。例如,如果用户传入INCRESS,就会调用operations[INCRESS]指针所指向的函数,也就是对value的数值进行加以,如果传入DECRESS,就会调用operations[DECRESS]指针所指的函数。
下面说一下C++中类成员函数作为回调函数的情况,首先我们要得到类成员函数的指针。
C++类的成员(这里主要说成员函数)分为静态成员和非静态成员,对于静态成员由于它不是任何对象实例的组成部分,所以不需要特殊的语法来指向static的成员,static成员的指针就是普通的指针。而non-static的成员指针需要特殊的语法——成员指针,成员指针包含类的类型以及成员的类型。一个定义类的成员指针例子如下:
在这个例子中我们可以看出,定义成员变量和成员函数的指针的格式如下:
其中,成员函数指针必须在三个方面与它所指函数的类型保持一致:
(1)函数形参的类型和数目,包括成员是否为const。
(2)函数返回类型。
(3)函数所属的类。
注意:调用操作符的优先级高于成员指针操作,因此,调用的时候包围(类名 :: *)的括号不能省略。如:(a.*pFun)(10);不能写成a.*pFun(10);否则,编译出错。
这里出现了一个新的操作符.*
与之像对应,c++中也有操作符->*。它们类似于成员访问操作符.和->,它们能使我们将成员指针绑定到实际对象。这两个操作符的左操作数必须是类类型的对象或类类型的指针,右操作符是该类型的成员指针。(引用《C++ Primer》)
明白了这些,我们就可以动手写一个简单的C++类成员函数作为回调函数的例子了。
输出结果:
dd a.funA, a.funB, a.funC
cat--A
cat--B
cat--C
Remove a.funA
cat--C
cat--B
Add b.funA, b.funB
cat--C
cat--B
dog--A
dog--B
Remove a.funB, a.funC
dog--A
dog--B
在C++中,信号与槽才是回调的完美解决方案,其实本质上是一个观察者模式
可以参看:http://www.cnblogs.com/dankye/archive/2012/08/25/2655816.html
OK,基本就是这样了,如果有错误之处还请大家指出,共同学习进步!
参考:
《C++ Primer》 http://blog.csdn.net/lvjinhua/article/details/349220 http://blog.csdn.net/jackystudio/article/details/11720325 http://my.oschina.net/apoptosis/blog/82572 http://www.dewen.org/q/4538/C%2B%2B%E4%B8%AD%E6%80%8E%E4%B9%88%E8%8E%B7%E5%8F%96%E7%B1%BB%E7%9A%84%E6%88%90%E5%91%98%E5%87%BD%E6%95%B0%E7%9A%84%E5%87%BD%E6%95%B0%E6%8C%87%E9%92%88%EF%BC%9F
——指向类成员的指针
在C中我们能够很容易地实现一个指向函数的指针,因此能够方便地实现函数的回调机制。但是在C++中很多人认为类的成员函数不能作为回调函数,因此很多C程序不能移植到C++上来。其实不是这样的,在C++中我们同样可以获取类的成员函数的指针,也能方便地实现函数回调机制。
下面先说一下C/C++中普通函数作为回调函数的情况,然后再说C++ 中类成员函数做为回调函数的情况。
先说一下自己对于回调函数的理解:回调函数通常是指通过函数指针进行调用的函数。例如,我有一个函数指针pFunc,我可以在运行时将不同的函数的地址给pFunc,同时可以通过pFunc来调用它所指向的函数,此时被pFunc指向的函数就称为是一个回调函数。
那么什么是函数指针:首先函数指针是一个指针,只是他不是指向一个变量而是指向一个函数的地址,也就是指向一个函数的入口地址,我们也可以修改该指针,指向不同的函数。函数指针的一般形式如下:
返回值类型 (*函数指针变量名) (参数列表) ;通常为了方便,我可以对其进行类型重定义:
typedef 返回值类型 (*FUNCPTR) (参数列表) ;
这样,FUCNPTR就是一个函数指针的类型,我们可以直接通过它进行定义函数指针,如:
#include <iostream> using namespace std ; int increse(int &value) { ++ value ; } int main (int argc, char **argv) { //重定义函数指针类型 typedef int (*FUNCPTR)(int&) ; FUNCPTR pFunc1 = &increse ; //通过类型重定义的方式声明一个指针 int (*pFunc2)(int&) = &increse ; //直接申明一个指针 int value = 0 ; pFunc1(value) ;//通过函数指针调用 cout << value << endl; pFunc2(value) ;//通关函数指针调用 cout << value << endl; if (pFunc1 == pFunc2) cout << "pFunc1 and pFunc2 point to the same function" << endl; else cout << "pFunc1 and pFunc2 point different functions" << endl; return 0 ; }执行的结果:
1
2
pFunc1 and pFunc2 point to the same function
在C/C++中普通函数最为回调函数很简单了,下面给出一个简单的例子,一目明了:
#include <iostream> using namespace std ; typedef int (*FUNCPTR)(int&) ; enum OPTION {INCRESS, DECRESS, OPTION_NUM} ; FUNCPTR operations[OPTION_NUM] ; int increse(int &value) { ++ value ; } int decress(int &value) { -- value ; } int& numOperation(int &value, OPTION op) { if (op >= 0 && op < OPTION_NUM && operations[op]) operations[op](value) ; //执行回调函数 return value ; } int main (int argc, char **argv) { operations[INCRESS] = &increse ; operations[DECRESS] = &decress ; int value = 0 ; cout << numOperation(value, INCRESS) << endl ; cout << numOperation(value, INCRESS) << endl ; cout << numOperation(value, DECRESS) << endl ; cout << numOperation(value, DECRESS) << endl ; return 0 ; }
在这个例子中,increse()和decress()函数的指针都被存储在operations数组中,作为numOperation()函数的回调函数。用户调用numOperation()函数时,通过改变传入参数来指定要完成的操作,numOperation()函数会根据第二个参数调用不同的回调函数,完成操作。例如,如果用户传入INCRESS,就会调用operations[INCRESS]指针所指向的函数,也就是对value的数值进行加以,如果传入DECRESS,就会调用operations[DECRESS]指针所指的函数。
下面说一下C++中类成员函数作为回调函数的情况,首先我们要得到类成员函数的指针。
C++类的成员(这里主要说成员函数)分为静态成员和非静态成员,对于静态成员由于它不是任何对象实例的组成部分,所以不需要特殊的语法来指向static的成员,static成员的指针就是普通的指针。而non-static的成员指针需要特殊的语法——成员指针,成员指针包含类的类型以及成员的类型。一个定义类的成员指针例子如下:
#include <iostream> using namespace std ; class A { public: A(int _p1 = 0, int _p2 = 0):publicValue(_p1), privateValue(_p2){} ; ~A(){} ; void Foo(int value){ cout << value + publicValue << endl ;} ; public: int publicValue ; private: int privateValue ; }; int main (int argc, char **argv) { //指向成员变量的指针 int A :: *pValue = &A :: publicValue ; //int A :: *pValue = &A :: privateValue ; //编译错误,不能是私有成员变量 //指向成员函数的指针 void (A :: *pFun)(int) = &A :: Foo ; A a ; a.*pValue = 20 ; //对a的publicValue进行赋值 (a.*pFun)(10) ; //调用a的Foo函数 }
在这个例子中我们可以看出,定义成员变量和成员函数的指针的格式如下:
//定义类成员变量指针的格式 类型 类名 :: * 变量指针名 ; //定义类成员函数指针的格式 返回值类型 (类名 :: * 函数指针名) (参数类型列表) ;
其中,成员函数指针必须在三个方面与它所指函数的类型保持一致:
(1)函数形参的类型和数目,包括成员是否为const。
(2)函数返回类型。
(3)函数所属的类。
注意:调用操作符的优先级高于成员指针操作,因此,调用的时候包围(类名 :: *)的括号不能省略。如:(a.*pFun)(10);不能写成a.*pFun(10);否则,编译出错。
这里出现了一个新的操作符.*
与之像对应,c++中也有操作符->*。它们类似于成员访问操作符.和->,它们能使我们将成员指针绑定到实际对象。这两个操作符的左操作数必须是类类型的对象或类类型的指针,右操作符是该类型的成员指针。(引用《C++ Primer》)
明白了这些,我们就可以动手写一个简单的C++类成员函数作为回调函数的例子了。
#include <iostream> #include <utility> #include <vector> #include <algorithm> #include <string> using namespace std ; class A { typedef void (A :: *FUNCPTR)(void) ; public: A(string _n): name(_n){} ; ~A(){} ; //注册一个回调函数 void registerCallBack(A *inst, FUNCPTR pFun) ; //溢出一个回调函数 void removeCallBack(A *inst, FUNCPTR pFun) ; //触发所有注册的回调函数 void trigger() ; inline void funA() {cout << string(name).append("--A") << endl;} ; inline void funB() {cout << string(name).append("--B") << endl;} ; inline void funC() {cout << string(name).append("--C") << endl;} ; private: //判断一个回调函数是否已经被注册 size_t isIn(const pair<A*, FUNCPTR> &p) ; string name ; vector< pair<A*, FUNCPTR> > callBackList ; }; size_t A :: isIn(const pair<A *, FUNCPTR> &p) { size_t index = -1 ; for (size_t i = 0; i < callBackList.size(); ++ i) if (p == callBackList[i]) { index = i ; break ; } return index ; } void A :: registerCallBack(A *inst, FUNCPTR pFun) { pair<A*, FUNCPTR> addPair = make_pair(inst, pFun) ; if (isIn(addPair) == -1) callBackList.push_back(addPair) ; } void A :: removeCallBack(A *inst, FUNCPTR pFun) { pair<A*, FUNCPTR> rmPair = make_pair(inst, pFun) ; size_t index = isIn(rmPair) ; if (index != -1) { swap(callBackList[index], callBackList.back()) ; callBackList.pop_back() ; } } void A:: trigger() { for (size_t i = 0; i < callBackList.size(); ++ i) { A *pInst = callBackList[i].first ; FUNCPTR pFun = callBackList[i].second ; (pInst->*pFun)() ; } } int main (int argc, char **argv) { A a("cat") ; A b("dog") ; cout << "Add a.funA, a.funB, a.funC" << endl ; a.registerCallBack(&a, &A::funA) ; a.registerCallBack(&a, &A::funB) ; a.registerCallBack(&a, &A::funC) ; a.trigger() ; cout << "Remove a.funA" << endl ; a.removeCallBack(&a, &A::funA) ; a.trigger() ; cout << "Add b.funA, b.funB" << endl; a.registerCallBack(&b, &A::funA) ; a.registerCallBack(&b, &A::funB) ; a.trigger() ; cout << "Remove a.funB, a.funC" << endl ; a.removeCallBack(&a, &A::funB) ; a.removeCallBack(&a, &A::funC) ; a.trigger() ; return 0 ; }
输出结果:
dd a.funA, a.funB, a.funC
cat--A
cat--B
cat--C
Remove a.funA
cat--C
cat--B
Add b.funA, b.funB
cat--C
cat--B
dog--A
dog--B
Remove a.funB, a.funC
dog--A
dog--B
在C++中,信号与槽才是回调的完美解决方案,其实本质上是一个观察者模式
可以参看:http://www.cnblogs.com/dankye/archive/2012/08/25/2655816.html
OK,基本就是这样了,如果有错误之处还请大家指出,共同学习进步!
参考:
《C++ Primer》 http://blog.csdn.net/lvjinhua/article/details/349220 http://blog.csdn.net/jackystudio/article/details/11720325 http://my.oschina.net/apoptosis/blog/82572 http://www.dewen.org/q/4538/C%2B%2B%E4%B8%AD%E6%80%8E%E4%B9%88%E8%8E%B7%E5%8F%96%E7%B1%BB%E7%9A%84%E6%88%90%E5%91%98%E5%87%BD%E6%95%B0%E7%9A%84%E5%87%BD%E6%95%B0%E6%8C%87%E9%92%88%EF%BC%9F
相关文章推荐
- c++ 指向类成员函数的函数指针
- 从汇编看c++中指向成员变量的指针(二)
- [疑问]C/C++中为什么在类外利用多态基类指向派生类指针可以调用类的私有成员函数?
- 【C++】学习笔记草稿版系列9(指向类成员的指针)
- C++指向类成员函数的指针
- Thinking in C++: Pointers to members 指向成员的指针
- c++指向成员的指针(二)
- 回调函数的实现(指向类成员函数的指针)
- C/C++学习笔记:指向类成员变量的指针
- c++ 指向 类成员函数(thiscall)的 函数指针
- 从汇编看c++中指向成员变量的指针(一)
- C++之指向数据成员的指针和指向成员函数的指针
- C++指向类成员函数的指针
- 深入探索C++对象模型之指向成员函数的指针
- 重学C++(2)——指向类成员的指针(转自:http://www.wangchao.net.cn/bbsdetail_73812.html)
- C++指向类成员函数的指针详细解析
- C++之指向成员的指针
- 【转载】C++成员函数指针的应用,可作为回调函数实参
- C++ 指向成员函数指针问题
- C++指向类成员函数的指针