使用类成员的 C++ 回调
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/14189440/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
C++ callback using class member
提问by BentFX
I know this has been asked so many times, and because of that it's difficult to dig through the cruft and find a simple example of what works.
我知道这已经被问过很多次了,因此很难深入挖掘这些问题并找到一个简单的例子来说明什么是有效的。
I've got this, it's simple and it works for MyClass
...
我有这个,它很简单,而且适用于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);
};
How can that be rewritten so EventHandler::addHandler()
will work with both MyClass
and YourClass
. I'm sorry but it's just the way my brain works, I need to see a simple example of what works before I can comprehend why/how it works. If you've got a favorite way to make this work now's the time to show it off, please markup that code and post it back.
如何重写它,以便EventHandler::addHandler()
同时使用MyClass
和YourClass
。我很抱歉,但这只是我大脑的工作方式,我需要先看看一个简单的例子,然后才能理解它为什么/如何工作。如果您有最喜欢的方式来完成这项工作,现在是时候展示它了,请标记该代码并将其发回。
[edit]
[编辑]
It was answered but the answer was deleted before I could give the checkmark. The answer in my case was a templated function. Changed addHandler to this...
它得到了回答,但在我给出复选标记之前答案已被删除。就我而言,答案是模板化函数。将 addHandler 更改为此...
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);
}
};
回答by Some programmer dude
Instead of having static methods and passing around a pointer to the class instance, you could use functionality in the new C++11 standard: std::function
and std::bind
:
您可以使用新的 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);
}
};
The addHandler
method now accepts a std::function
argument, and this "function object" have no return value and takes an integer as argument.
该addHandler
方法现在接受一个std::function
参数,这个“函数对象”没有返回值,并接受一个整数作为参数。
To bind it to a specific function, you use std::bind
:
要将其绑定到特定函数,请使用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;
}
You need to use std::bind
when adding the handler, as you explicitly needs to specify the otherwise implicit this
pointer as an argument. If you have a free-standing function, you don't have to use std::bind
:
您需要std::bind
在添加处理程序时使用,因为您需要明确指定其他隐式this
指针作为参数。如果您有独立功能,则不必使用std::bind
:
void freeStandingCallback(int x)
{
// ...
}
int main()
{
// ...
handler->addHandler(freeStandingCallback);
}
Having the event handler use std::function
objects, also makes it possible to use the new C++11 lambda functions:
让事件处理程序使用std::function
对象,还可以使用新的 C++11 lambda 函数:
handler->addHandler([](int x) { std::cout << "x is " << x << '\n'; });
回答by rsjaffe
Here's a concise version that works with class method callbacks and with regular function callbacks. In this example, to show how parameters are handled, the callback function takes two parameters: bool
and int
.
这是一个简洁的版本,适用于类方法回调和常规函数回调。在此示例中,为了显示如何处理参数,回调函数采用两个参数: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);
This restricts the C++11-specific code to the addCallback method and private data in class Caller. To me, at least, this minimizes the chance of making mistakes when implementing it.
这将特定于 C++11 的代码限制为类 Caller 中的 addCallback 方法和私有数据。至少对我来说,这最大限度地减少了在实施时出错的机会。
回答by Karthik T
What you want to do is to make an interface which handles this code and all your classes implement the interface.
您想要做的是制作一个处理此代码的接口,并且您的所有类都实现该接口。
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
{
Note that for this to work the "Callback" function is non static which i believeis an improvement. If you want it to be static, you need to do it as JaredC suggests with templates.
请注意,为此,“回调”功能是非静态的,我认为这是一种改进。如果你希望它是静态的,你需要按照 JaredC 建议的模板来做。
回答by s.bandara
MyClass
and YourClass
could both be derived from SomeonesClass
which has an abstract (virtual) Callback
method. Your addHandler
would accept objects of type SomeonesClass
and MyClass
and YourClass
can override Callback
to provide their specific implementation of callback behavior.
MyClass
并且YourClass
都可以从中派生出SomeonesClass
具有抽象(虚拟)Callback
方法的方法。您addHandler
将接受类型为SomeonesClass
and 的对象,MyClass
并且YourClass
可以覆盖Callback
以提供它们对回调行为的特定实现。
回答by Craig D
A complete working example from the code above.... for C++11:
来自上面代码的完整工作示例......对于 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:%d\n\n", (x+private_x));
}
// Main method
int main(int argc, char const *argv[]) {
printf("\nCompiler:%ld\n", __cplusplus);
new MyClass(5);
return 0;
}
// where is your .cpp file name... this is the command used:
// g++ -std=c++11 -Wall -o .cpp
// chmod 700
// ./
Output should be:
输出应该是:
Compiler:201103
Handler added...
Result:6
回答by mohDady
If you have callbacks with different parameters you can use templates as follows:
// compile with: g++ -std=c++11 myTemplatedCPPcallbacks.cpp -o myTemplatedCPPcallbacksApp
如果您有具有不同参数的回调,您可以使用如下模板:
// compile with: g++ -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();
}