使用类成员的c++回调
C++ callback using class member
我知道这个问题已经被问过很多次了,正因为如此,很难从一堆乱七八糟的东西中找出一个简单的例子。
我有这个,它很简单,它适用于MyClass
…
#include <iostream>
using std::cout;
using std::endl;
class MyClass
{
public:
MyClass();
static void Callback(MyClass* instance, int x);
private:
int private_x;
};
class EventHandler
{
public:
void addHandler(MyClass* owner)
{
cout << "Handler added..." << endl;
//Let's pretend an event just occured
owner->Callback(owner,1);
}
};
EventHandler* handler;
MyClass::MyClass()
{
private_x = 5;
handler->addHandler(this);
}
void MyClass::Callback(MyClass* instance, int x)
{
cout << x + instance->private_x << endl;
}
int main(int argc, char** argv)
{
handler = new EventHandler();
MyClass* myClass = new MyClass();
}
class YourClass
{
public:
YourClass();
static void Callback(YourClass* instance, int x);
};
如何重写使EventHandler::addHandler()
与MyClass
和YourClass
同时工作?我很抱歉,但这只是我的大脑工作的方式,我需要看到一个简单的例子,什么工作之前,我可以理解为什么/如何工作。如果你有一个最喜欢的方法来完成这个工作,现在是时候展示它了,请标记代码并把它发回来。
[编辑]
回答了,但是在我打勾之前答案被删除了。在我的例子中,答案是模板化函数。
class EventHandler
{
public:
template<typename T>
void addHandler(T* owner)
{
cout << "Handler added..." << endl;
//Let's pretend an event just occured
owner->Callback(owner,1);
}
};
您可以使用新的c++ 11标准中的功能,而不是使用静态方法和传递指向类实例的指针:std::function
和std::bind
:
#include <functional>
class EventHandler
{
public:
void addHandler(std::function<void(int)> callback)
{
cout << "Handler added..." << endl;
// Let's pretend an event just occured
callback(1);
}
};
addHandler
方法现在接受一个std::function
参数,并且这个"函数对象"没有返回值,并接受一个整数作为参数。
使用std::bind
:
class MyClass
{
public:
MyClass();
// Note: No longer marked `static`, and only takes the actual argument
void Callback(int x);
private:
int private_x;
};
MyClass::MyClass()
{
using namespace std::placeholders; // for `_1`
private_x = 5;
handler->addHandler(std::bind(&MyClass::Callback, this, _1));
}
void MyClass::Callback(int x)
{
// No longer needs an explicit `instance` argument,
// as `this` is set up properly
cout << x + private_x << endl;
}
在添加处理程序时需要使用std::bind
,因为您需要显式地指定否则隐式的this
指针作为参数。如果你有一个独立的函数,你不需要使用std::bind
:
void freeStandingCallback(int x)
{
// ...
}
int main()
{
// ...
handler->addHandler(freeStandingCallback);
}
让事件处理程序使用std::function
对象,还可以使用新的c++ 11 lambda函数:
handler->addHandler([](int x) { std::cout << "x is " << x << 'n'; });
这里有一个简洁的版本,可以使用类方法回调和常规函数回调。在本例中,为了显示如何处理参数,回调函数接受两个参数:bool
和int
。
class Caller {
template<class T> void addCallback(T* const object, void(T::* const mf)(bool,int))
{
using namespace std::placeholders;
callbacks_.emplace_back(std::bind(mf, object, _1, _2));
}
void addCallback(void(* const fun)(bool,int))
{
callbacks_.emplace_back(fun);
}
void callCallbacks(bool firstval, int secondval)
{
for (const auto& cb : callbacks_)
cb(firstval, secondval);
}
private:
std::vector<std::function<void(bool,int)>> callbacks_;
}
class Callee {
void MyFunction(bool,int);
}
//then, somewhere in Callee, to add the callback, given a pointer to Caller `ptr`
ptr->addCallback(this, &Callee::MyFunction);
//or to add a call back to a regular function
ptr->addCallback(&MyRegularFunction);
这将c++ 11特定的代码限制为addCallback方法和类Caller中的私有数据。至少对我来说,这将实现它时犯错误的可能性降到最低。
注意,在c++ 20的bind_front
中,你可以将类成员函数的add_callback
简化为:
template<class T> void addCallback(T* const object, void(T::* const mf)(bool,int))
{
callbacks_.emplace_back(std::bind_front(mf, object));
}
你要做的是创建一个接口来处理这些代码,并且你所有的类都实现了这个接口。
class IEventListener{
public:
void OnEvent(int x) = 0; // renamed Callback to OnEvent removed the instance, you can add it back if you want.
};
class MyClass :public IEventListener
{
...
void OnEvent(int x); //typically such a function is NOT static. This wont work if it is static.
};
class YourClass :public IEventListener
{
请注意,为了使其工作,"Callback"函数是非静态的,我认为是一个改进。如果您希望它是静态的,您需要按照JaredC对模板的建议来做。
上面代码的完整工作示例....对于c++ 11:
#include <stdlib.h>
#include <stdio.h>
#include <functional>
#if __cplusplus <= 199711L
#error This file needs at least a C++11 compliant compiler, try using:
#error $ g++ -std=c++11 ..
#endif
using namespace std;
class EventHandler {
public:
void addHandler(std::function<void(int)> callback) {
printf("nHandler added...");
// Let's pretend an event just occured
callback(1);
}
};
class MyClass
{
public:
MyClass(int);
// Note: No longer marked `static`, and only takes the actual argument
void Callback(int x);
private:
EventHandler *pHandler;
int private_x;
};
MyClass::MyClass(int value) {
using namespace std::placeholders; // for `_1`
pHandler = new EventHandler();
private_x = value;
pHandler->addHandler(std::bind(&MyClass::Callback, this, _1));
}
void MyClass::Callback(int x) {
// No longer needs an explicit `instance` argument,
// as `this` is set up properly
printf("nResult:%dnn", (x+private_x));
}
// Main method
int main(int argc, char const *argv[]) {
printf("nCompiler:%ldn", __cplusplus);
new MyClass(5);
return 0;
}
// where $1 is your .cpp file name... this is the command used:
// g++ -std=c++11 -Wall -o $1 $1.cpp
// chmod 700 $1
// ./$1
输出应该是:
Compiler:201103
Handler added...
Result:6
MyClass
和YourClass
都可以从具有抽象(虚拟)Callback
方法的SomeonesClass
派生。您的addHandler
将接受类型为SomeonesClass
和MyClass
的对象,YourClass
可以覆盖Callback
,以提供回调行为的特定实现。
如果你有不同参数的回调,你可以使用模板如下:
//编译:c++ -std=c++11 myTemplatedCPPcallbacks.cpp -o myTemplatedCPPcallbacksApp
#include <functional> // c++11
#include <iostream> // due to: cout
using std::cout;
using std::endl;
class MyClass
{
public:
MyClass();
static void Callback(MyClass* instance, int x);
private:
int private_x;
};
class OtherClass
{
public:
OtherClass();
static void Callback(OtherClass* instance, std::string str);
private:
std::string private_str;
};
class EventHandler
{
public:
template<typename T, class T2>
void addHandler(T* owner, T2 arg2)
{
cout << "nHandler added..." << endl;
//Let's pretend an event just occured
owner->Callback(owner, arg2);
}
};
MyClass::MyClass()
{
EventHandler* handler;
private_x = 4;
handler->addHandler(this, private_x);
}
OtherClass::OtherClass()
{
EventHandler* handler;
private_str = "moh ";
handler->addHandler(this, private_str );
}
void MyClass::Callback(MyClass* instance, int x)
{
cout << " MyClass::Callback(MyClass* instance, int x) ==> "
<< 6 + x + instance->private_x << endl;
}
void OtherClass::Callback(OtherClass* instance, std::string private_str)
{
cout << " OtherClass::Callback(OtherClass* instance, std::string private_str) ==> "
<< " Hello " << instance->private_str << endl;
}
int main(int argc, char** argv)
{
EventHandler* handler;
handler = new EventHandler();
MyClass* myClass = new MyClass();
OtherClass* myOtherClass = new OtherClass();
}
- 架构决策:返回std::future还是提供回调
- 正在为Xtensa simcall函数编写回调函数
- 如何在C++中使用非静态成员函数作为回调函数
- FLTK:按下哪个按钮 - 将数字传递给按钮的回调 (lambda)
- 在简单示例中,Python3 + ctypes 回调会导致内存泄漏
- 用于在回调中调用解析器的设计模式
- 如何使用C++对象的成员函数作为 C 样式回调?
- Java从C++回调到C++回调
- 如何将成员函数作为回调参数传递给需要"typedef-ed"自由函数指针的函数?
- 从不同的 cpp 调用回调函数会导致bad_function_call
- pcap_handler回调仅在使用 NPCAP v0.9991 时包含空数据包
- 不带轮询的 SDL2 事件回调
- C++存储带有可变参数的回调
- 如何使用 Node-addon-API 实现 node-nan 回调
- 处理影响跨不同线程共享对象的定时回调的最佳方法是什么?
- 访问类C++ C 样式回调
- 处理类内的回调时,必须调用对非静态成员函数的引用
- 如果 C 函数仍然可以间接执行(通过回调函数),那么将它声明为静态函数是否是一种不好的做法?
- 在C++中实现回调
- C++ 事件管理器的回调,使用 std::function 和 std:bind 以及派生类作为参数