C++回调函数问题的解决方案
2012-08-26 19:49
260 查看
例子源代码下载地址:http://download.csdn.net/detail/xiaoding133/4527165
1.问题提出
C++不像其他面向对象语言(如Object Pascal,Ada语言,Java和C#)提供了将一个类的方法作为回调函数的解决方案。在C语言中,这些回调函数普遍存在以事件驱动的应用程序当中。问题的解决是围绕这样一个事实:即一个特定的类的多个实例存放于不同的内存地址,将导致不仅需要函数指针,也需要一个指向实例本身的指针。从上面讨论的一个事实可以得出一个直观的解决方案,就是用类模板和编译时实例化来解决。
2.解决方案的实现
下面的例子采用一个参数的成员函数模板,当然也可以采用可变参数模板类。模板类如下:
3.使用上面的模板
使用上面的模板很简单,模板类本身可以实例化为一个对象的指针或只作为一个简单的类。当作为一个对象指针使用时,C++有一个局限性就是该指针不解引用就不能调用operator(),一个简单的解决方法就是在模板类中定义一个函数execute(),在该函数中调用模板类中的operator()方法。除了这个以为,用一对象指针来实例化一个SingularCallBack模板类,可以允许你将这些回调函数分组放入vector容器,这对于基于事件驱动的程序非常重要。
假设有下面两个类,我们让methodB()作为回调函数,从下面的代码我们可以看出,methodB()被调用时,类A的函数将调用其output()方法,如果在终端输出“I am class A :D”,则类的回调成功。
有两种方法可以从一个回调模板类的对象指针(指的是SingularCallBack类对象)调用回调函数,第一种方法是对SingularCallBack对象的指针进行解引用然后运行回调方法(即:()操作符),第二个选项是直接运行execute()方法。
第一种方法:
第二种方法:
用一个对象来实例化回调模板类
Example 1:回调模板类SingularCallBack应用到更复杂的例子中
Example 2:比Example 1更复杂一点的例子类继承使用回调模板,利用多态性
在实际的项目中,应该加入类实例为NULL的验证,如有必要可以结合C++STL中的两个指针指针auto_ptr 和 shared_ptr。上面的回调模板类也可以实现可变参数的形式:如下:
1.问题提出
C++不像其他面向对象语言(如Object Pascal,Ada语言,Java和C#)提供了将一个类的方法作为回调函数的解决方案。在C语言中,这些回调函数普遍存在以事件驱动的应用程序当中。问题的解决是围绕这样一个事实:即一个特定的类的多个实例存放于不同的内存地址,将导致不仅需要函数指针,也需要一个指向实例本身的指针。从上面讨论的一个事实可以得出一个直观的解决方案,就是用类模板和编译时实例化来解决。
2.解决方案的实现
下面的例子采用一个参数的成员函数模板,当然也可以采用可变参数模板类。模板类如下:
template < class Class, typename ReturnType, typename Parameter > class SingularCallBack { public: typedef ReturnType (Class::*Method)(Parameter);//定义一个指向函数的指针,返回类型为ReturnType,参数类型为Parameter,Method为指针名,Class为指针类型 SingularCallBack(Class* _class_instance, Method _method) { class_instance = _class_instance; method = _method; }; ReturnType operator()(Parameter parameter)//定义了operator()的class实体都市仿函数 { return (class_instance->*method)(parameter); }; ReturnType execute(Parameter parameter) { return operator()(parameter); }; private: Class* class_instance;//类实例 Method method; //函数指针 };
3.使用上面的模板
使用上面的模板很简单,模板类本身可以实例化为一个对象的指针或只作为一个简单的类。当作为一个对象指针使用时,C++有一个局限性就是该指针不解引用就不能调用operator(),一个简单的解决方法就是在模板类中定义一个函数execute(),在该函数中调用模板类中的operator()方法。除了这个以为,用一对象指针来实例化一个SingularCallBack模板类,可以允许你将这些回调函数分组放入vector容器,这对于基于事件驱动的程序非常重要。
假设有下面两个类,我们让methodB()作为回调函数,从下面的代码我们可以看出,methodB()被调用时,类A的函数将调用其output()方法,如果在终端输出“I am class A :D”,则类的回调成功。
class A { public: void output() { std::cout << "I am class A :D" << std::endl; }; }; class B { public: bool methodB(A a) { a.output(); return true; } };
有两种方法可以从一个回调模板类的对象指针(指的是SingularCallBack类对象)调用回调函数,第一种方法是对SingularCallBack对象的指针进行解引用然后运行回调方法(即:()操作符),第二个选项是直接运行execute()方法。
第一种方法:
A a; B b; SingularCallBack< B,bool,A >* cb; cb = new SingularCallBack< B,bool,A >(&b,&B::methodB); if((*cb)(a)) { std::cout << "CallBack Fired Successfully!" << std::endl; } else { std::cout << "CallBack Fired Unsuccessfully!" << std::endl; }
第二种方法:
A a; B b; SingularCallBack< B,bool,A >* cb; cb = new SingularCallBack< B,bool,A >(&b,&B::methodB); if(cb->execute(a)) { std::cout << "CallBack Fired Successfully!" << std::endl; } else { std::cout << "CallBack Fired Unsuccessfully!" << std::endl; }
用一个对象来实例化回调模板类
A a; B b; SingularCallBack< B,bool,A >cb(&b,&B::methodB); if(cb(a)) { std::cout << "CallBack Fired Successfully!" << std::endl; } else { std::cout << "CallBack Fired Unsuccessfully!" << std::endl; }
Example 1:回调模板类SingularCallBack应用到更复杂的例子中
class AClass { public: AClass(unsigned int _id): id(_id){}; ~AClass(){}; bool AMethod(std::string str) { std::cout << "AClass[" << id << "]: " << str << std::endl; return true; }; private: unsigned int id; }; typedef SingularCallBack < AClass, bool, std::string > ACallBack; int main() { std::vector < ACallBack > callback_list; AClass a1(1); AClass a2(2); AClass a3(3); callback_list.push_back(ACallBack(&a1, &AClass::AMethod)); callback_list.push_back(ACallBack(&a2, &AClass::AMethod)); callback_list.push_back(ACallBack(&a3, &AClass::AMethod)); for (unsigned int i = 0; i < callback_list.size(); ++i) { callback_list[i]("abc"); } for (unsigned int i = 0; i < callback_list.size(); ++i) { callback_list[i].execute("abc"); } return 0; }
Example 2:比Example 1更复杂一点的例子类继承使用回调模板,利用多态性
class BaseClass { public: virtual ~BaseClass(){}; virtual bool DerivedMethod(const std::string& str){ return true; }; }; class AClass : public BaseClass { public: AClass(unsigned int _id): id(_id){}; ~AClass(){}; bool AMethod(const std::string& str) { std::cout << "AClass[" << id << "]: " << str << std::endl; return true; }; bool DerivedMethod(const std::string& str) { std::cout << "Derived Method AClass[" << id << "]: " << str << std::endl; return true; }; private: unsigned int id; }; class BClass : public BaseClass { public: BClass(unsigned int _id): id(_id){}; ~BClass(){}; bool BMethod(const std::string& str) { std::cout << "BClass[" << id << "]: " << str << std::endl; return true; }; bool DerivedMethod(const std::string& str) { std::cout << "Derived Method BClass[" << id << "]: " << str << std::endl; return true; }; private: unsigned int id; }; typedef SingularCallBack < BaseClass, bool, std::string > BaseCallBack; int main() { std::vector < BaseCallBack > callback_list; AClass a(1); BClass b(2); callback_list.push_back(BaseCallBack(&a, &BaseClass::DerivedMethod)); callback_list.push_back(BaseCallBack(&b, &BaseClass::DerivedMethod)); for (unsigned int i = 0; i < callback_list.size(); ++i) { callback_list[i]("abc"); } for (unsigned int i = 0; i < callback_list.size(); ++i) { callback_list[i].execute("abc"); } return 0; }
在实际的项目中,应该加入类实例为NULL的验证,如有必要可以结合C++STL中的两个指针指针auto_ptr 和 shared_ptr。上面的回调模板类也可以实现可变参数的形式:如下:
template < class Class, typename ReturnType, typename Parameter1 = void, typename Parameter2 = void, typename Parameter3 = void, typename Parameter4 = void > class CallBack { public: typedef ReturnType (Class::*Method)(Parameter1, Parameter2, Parameter3, Parameter4); CallBack(Class* _class_instance, Method _method) { class_instance = _class_instance; method = _method; }; ReturnType operator()(Parameter1 p1, Parameter2 p2, Parameter3 p3, Parameter4 p4) { return (class_instance->*method)(p1, p2, p3, p4); }; ReturnType execute(Parameter1 p1, Parameter2 p2, Parameter3 p3, Parameter4 p4) { return operator()(p1, p2, p3, p4); }; private: Class* class_instance; Method method; }; template < class Class, typename ReturnType, typename Parameter1, typename Parameter2, typename Parameter3> class CallBack < Class, ReturnType, Parameter1, Parameter2, Parameter3 > { public: typedef ReturnType (Class::*Method)(Parameter1, Parameter2, Parameter3); CallBack(Class* _class_instance, Method _method) { class_instance = _class_instance; method = _method; }; ReturnType operator()(Parameter1 p1, Parameter2 p2, Parameter3 p3) { return (class_instance->*method)(p1, p2, p3); }; ReturnType execute(Parameter1 p1, Parameter2 p2, Parameter3 p3) { return operator()(p1, p2, p3); }; private: Class* class_instance; Method method; }; 可以用下面的方式来调用: class AClass { public: AClass(unsigned int _id): id(_id){}; ~AClass(){}; bool AMethod(const std::string& str) { std::cout << "AClass[" << id << "]: " << str << std::endl; std::cout.flush(); return true; }; bool method4(int a, int b, int c, int d) { std::cout << "Method - 4" << std::endl; return true; }; bool method3(int a, int b, int c) { std::cout << "Method - 3" << std::endl; return true; }; private: unsigned int id; }; typedef CallBack< AClass, bool, int, int ,int, int > callback_type4; typedef CallBack< AClass, bool, int, int ,int > callback_type3; int main() { AClass aclass(1); callback_type4 cb4(&aclass, &AClass::method4); callback_type3 cb3(&aclass, &AClass::method3); std::vector< std::pair< int ,void* > > callback_list; callback_list.push_back(std::pair< int ,void* >( 4, static_cast(&cb4))); callback_list.push_back(std::pair< int ,void* >( 3, static_cast(&cb3))); for (unsigned int i = 0; i < callback_list.size(); ++i) { switch (callback_list[i].first) { case 4: (*static_cast< callback_type4* >(callback_list[i].second))(1,2,3,4); break; case 3: (*static_cast< callback_type3* >(callback_list[i].second))(1,2,3); break; } } for (unsigned int i = 0; i < callback_list.size(); ++i) { switch (callback_list[i].first) { case 4: static_cast< callback_type4* >(callback_list[i].second)->execute(1,2,3,4); break; case 3: static_cast< callback_type3* >(callback_list[i].second)->execute(1,2,3); break; } } return 0; }
相关文章推荐
- OpenGL网格化回调函数问题解决方案
- 在c++中回调c#函数遇到的字符串问题
- exceptional c++:47个c++工程难题、编程问题和解决方案(中文版)
- C++继承时子类定义同名成员变量时的调用继承函数的问题
- Unity3D在IOS、Android上使用C++并回调的究极解决方案
- 关于C/C++的二维数组作为函数参数问题
- 理财平台C++定时结算任务的容灾问题的解决方案
- C++中函数返回值的问题与产生随机数
- [cocos2d-x3.3]cocostudio的Button按钮触发两次回调函数问题解决
- c++智能指针循环引用带来的问题及解决方案
- C++ 调用webservice 出现 函数返回值为 3 (SOAP_TAG_MISMATCH) 的解决方案
- C++ 类里面,函数占用存储空间问题
- C++中list的erase()函数问题
- C++中动态内存分配引发问题的解决方案
- C++ - 函数模板(function template)右值引用参数 问题 及 解决
- C/C++语言调用lua函数和编译问题
- C++中构造函数和析构函数避免调用虚函数的问题 转载
- Java中的回调函数问题
- C/C++之回调函数介绍
- [置顶] Eclipse C++出现Launch failed,Binary not found问题安装MinGW编译器解决方案(Win7)