在c++调用一些使用回调的c代码库时,因为回调函数要声明为static方式,而static成员是在类的每个对象中共享的,这就破坏了c++的封装性,且静态方法无法调用非静态成员,代码就会变得拧巴,使用c++11的一些新特性我们可以解决这个问题,现记录下常用的c++使用回调的方式。
这种方法是比较常规的,也是受限较大的,使用静态方法就不能使用类的非静态成员,破坏了类的封装性,具体实现方法如下:
#include
class MyClass {
public:
// This is our application callback handler for when a message is received, we will
// pass this into the library which deals with message parsing
// The "static" keyword makes it easy, as now this function does not
// take a this pointer and has the same signature as a plain C function
static void onMsg(int num1, int num2) {
printf("onMsg() called with num1=%i, num2=%i\n", num1, num2);
// NOTE: Can't call any non-static method functions here!
}
};
class LibraryClass {
public:
// For the library class to call the onMsg, it has to be passed both an instance
// of MyClass and a pointer to the member function to call
// Note that MyClass has to be known here! This creates undesired coupling...in
// reality your library should never have to know about MyClass
void passACallbackToMe(void (*onMsg)(int num1, int num2)) {
// Call the callback function
onMsg(1, 2);
}
};
int main() {
MyClass myClass;
LibraryClass libraryClass;
// Provide the instance and function to call
libraryClass.passACallbackToMe(&myClass.onMsg);
}
这种方法略微复杂,使用了c++的模板函数等特性,但是灵活性非常好,以下为代码
/*fun.h*/
#pragma once
#include
#define MY_CALLBACK
typedef void (MY_CALLBACK* m_CallBack)(int,int);
static m_CallBack p_callback = NULL;
void fun1(int a, int b)
{
p_callback(a, b);
}
void setCallback(m_CallBack p)
{
p_callback = p;
}
/*main.cpp*/
#include
#include
#include
#include "fun1.h"
using namespace std;
template <typename T>
struct Callback;
template <typename Ret, typename... Params>
struct Callback<Ret(Params...)> {
template <typename... Args>
static Ret callback(Args... args) {
return func(args...);
}
static std::function<Ret(Params...)> func;
};
template <typename Ret, typename... Params>
std::function<Ret(Params...)> Callback<Ret(Params...)>::func;
class ClassWithCallback {
public:
void init() {
Callback<void(int, int)>::func = std::bind(&ClassWithCallback::method_to_callback, this, std::placeholders::_1, std::placeholders::_2);
myCallBack func = static_cast<myCallBack>(Callback<void(int, int)>::callback);
setCallback(func);
}
void dosomething() {
fun1(5, 2);
}
void method_to_callback(int num1, int num2) {
int o = num1 + num2;
printf("--Value: %i\n", o);
}
};
int main() {
ClassWithCallback my_class;
// Now we can pass this function to a C API which just wants a standard function callback
my_class.init();
my_class.dosomething();
}
这一种有个前提就是回调函数可修改,且回调函数语言为c++,受限也比较大,但是对于c++语言编程优化是一种提高,代码如下:
#include
#include
class LibraryClass {
public:
void passACallbackToMe(std::function<int(int, int)> callback) {
// Now invoke (call) the callback
int o = callback(1, 2);
printf("Value: %i\n", o); // We might be on an embedded system, use printf() and not std::cout
}
};
class MyClass {
public:
int methodToCallback(int num1, int num2) {
return num1 + num2;
}
};
int main()
{
MyClass myClass;
LibraryClass libraryClass;
// Use a lambda to capture myClass and call the member method
libraryClass.passACallbackToMe([&myClass](int num1, int num2) -> int {
return myClass.methodToCallback(num1, num2);
});
}
因为想要实现在classWithCallback
中调用lib效果,我对上述代码做了以下修改:
/*fun1.h*/
#pragma once
#include
#include
#include
using namespace std;
class callbackLib {
public:
void passACallbackToMe(std::function<void(int, int)> callback) {
m_callback = callback;
}
void dosomething(int a,int b) {
if (m_callback) {
m_callback(a, b);
}
}
private:
function<void(int, int)> m_callback = nullptr;
};
回调实现类和main实现:
/*main.cpp*/
#include
#include
#include
#include "fun1.h"
using namespace std;
class ClassWithCallback {
public:
void init() {
pLib = new callbackLib();
pLib->passACallbackToMe(std::bind(&ClassWithCallback::method_to_callback, this, std::placeholders::_1, std::placeholders::_2));
}
void method_to_callback(int num1, int num2) {
int o = num1 + num2;
printf("--Value: %i\n", o);
}
void dosomething() {
pLib->dosomething(6, 7);
}
private:
callbackLib* pLib = nullptr;
};
int main() {
ClassWithCallback my_class;
// Now we can pass this function to a C API which just wants a standard function callback
my_class.init();
my_class.dosomething();
}
这三种是我找到的比较常见的c++调用回调的方式,不足之处请大家指教。
参考链接