例子源代码下载地址:http://download.youkuaiyun.com/detail/xiaoding133/4527165
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;
}