[c++] 클래스 멤버를 사용한 C ++ 콜백
나는 이것이 여러 번 요청되었다는 것을 알고 있으며, 그 때문에 균열을 파헤 치고 작동하는 간단한 예를 찾기가 어렵습니다.
나는 이것을 가지고 있으며, 간단하고 작동합니다 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
. 미안하지만 뇌가 작동하는 방식 일뿐입니다. 작동 원리와 작동 방식을 이해하기 전에 작동하는 간단한 예를 봐야합니다. 이 작업을 할 수있는 가장 좋은 방법이 있다면 지금이 그것을 보여줄 때입니다. 코드를 마크 업하고 다시 게시하십시오.
[편집하다]
답변을 받았지만 확인 표시를하기 전에 답변이 삭제되었습니다. 제 경우의 대답은 템플릿 함수였습니다. 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);
}
};
답변
정적 메서드를 사용하고 클래스 인스턴스에 대한 포인터를 전달하는 대신 새로운 C ++ 11 표준의 기능을 사용할 수 있습니다. std::function
and 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 람다 함수 를 사용할 수 있습니다 .
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 특정 코드를 Caller 클래스의 addCallback 메소드 및 개인 데이터로 제한합니다. 나에게 적어도 이것은 그것을 구현할 때 실수 할 가능성을 최소화합니다.
답변
원하는 것은이 코드를 처리하는 인터페이스를 만들고 모든 클래스가 인터페이스를 구현하는 것입니다.
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
{
이것이 작동하려면 “콜백”기능이 개선 되었다고 생각 하는 정적이 아닙니다 . 정적으로 만들려면 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:%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 $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
둘 다 SomeonesClass
추상 (가상) Callback
방법 을 가진 파생 될 수 있습니다 . 당신은 addHandler
유형의 개체를 받아들이 SomeonesClass
및 MyClass
및 YourClass
재정의 할 수 있습니다 Callback
콜백 행동의 특정 구현을 제공 할 수 있습니다.
답변
다른 매개 변수를 가진 콜백이있는 경우 다음과 같이 템플릿을 사용할 수 있습니다.
// 다음으로 컴파일 : 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();
}