C++回调函数问题的解决方案

本文介绍了一种使用C++模板来实现类的方法作为回调函数的方法。通过具体的代码示例,展示了如何定义和使用回调模板,并提供了两种不同的调用方式。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

 

 例子源代码下载地址: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;
}

 

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值