您的位置:首页 > 编程语言 > C语言/C++

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

2012-08-26 19:49 260 查看
例子源代码下载地址:http://download.csdn.net/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;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: