Saya tahu ini telah ditanyakan berkali-kali, dan karena itu sulit untuk menggali lebih dalam dan menemukan contoh sederhana tentang apa yang berhasil.
Saya punya ini, sederhana dan berfungsi untuk 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);
};
Bagaimana itu bisa ditulis ulang sehingga EventHandler::addHandler()
akan bekerja dengan MyClass
dan YourClass
. Maaf, tapi ini hanya cara otak saya bekerja, saya perlu melihat contoh sederhana tentang apa yang berhasil sebelum saya dapat memahami mengapa / bagaimana cara kerjanya. Jika Anda punya cara favorit untuk membuat ini berfungsi, sekaranglah waktunya untuk memamerkannya, tandai kode itu dan kirim kembali.
[edit]
Itu dijawab tetapi jawabannya telah dihapus sebelum saya dapat memberikan tanda centang. Jawaban dalam kasus saya adalah fungsi template. Mengubah addHandler menjadi ini ...
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);
}
};
Jawaban:
Alih-alih memiliki metode statis dan meneruskan pointer ke instance kelas, Anda dapat menggunakan fungsionalitas dalam standar C ++ 11 yang baru:
std::function
danstd::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
Metode sekarang menerimastd::function
argumen, dan ini "fungsi objek" tidak memiliki nilai kembali dan mengambil integer sebagai argumen.Untuk mengikatnya ke fungsi tertentu, Anda menggunakan
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; }
Anda perlu menggunakan
std::bind
saat menambahkan handler, karena Anda secara eksplisit perlu menentukanthis
pointer implisit sebagai argumen. Jika Anda memiliki fungsi yang berdiri sendiri, Anda tidak perlu menggunakanstd::bind
:void freeStandingCallback(int x) { // ... } int main() { // ... handler->addHandler(freeStandingCallback); }
Memiliki event handler menggunakan
std::function
objek, juga memungkinkan untuk menggunakan fungsi lambda C ++ 11 yang baru :handler->addHandler([](int x) { std::cout << "x is " << x << '\n'; });
sumber
std::bind
hanya mengembalikan objek (tidak ditentukan), dan ketika Anda selesai dengannya Anda bisa membiarkannya keluar dari ruang lingkup. Jika objek terikat dihancurkan dan Anda mencoba memanggil fungsi tersebut, Anda akan mendapatkan perilaku tidak terdefinisi .handler->addHandler()
, berarti di suatu tempat Anda membuat objekEventHandler
? Jawaban bagus btw, +1....., _1, _2)
dan seterusnya.Berikut adalah versi ringkas yang berfungsi dengan callback metode kelas dan dengan callback fungsi reguler. Dalam contoh ini, untuk menunjukkan bagaimana parameter ditangani, fungsi callback mengambil dua parameter:
bool
danint
.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);
Ini membatasi kode khusus C ++ 11 ke metode addCallback dan data pribadi di kelas Pemanggil. Bagi saya, setidaknya, ini meminimalkan kemungkinan membuat kesalahan saat menerapkannya.
sumber
Apa yang ingin Anda lakukan adalah membuat antarmuka yang menangani kode ini dan semua kelas Anda mengimplementasikan antarmuka tersebut.
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 {
Perhatikan bahwa agar ini berfungsi, fungsi "Callback" adalah non-statis yang menurut saya merupakan peningkatan. Jika Anda ingin menjadi statis, Anda perlu melakukannya seperti yang disarankan JaredC dengan template.
sumber
Contoh kerja lengkap dari kode di atas .... untuk 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
Output harus:
Compiler:201103 Handler added... Result:6
sumber
MyClass
danYourClass
keduanya bisa diturunkanSomeonesClass
yang memiliki metode abstrak (virtual)Callback
. AndaaddHandler
akan menerima objek bertipeSomeonesClass
danMyClass
danYourClass
dapat menimpaCallback
untuk menyediakan implementasi spesifik dari perilaku callback.sumber
Jika Anda memiliki callback dengan parameter berbeda, Anda dapat menggunakan template sebagai berikut:
// kompilasi dengan: 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(); }
sumber
YourClass
. Anda tampaknya telah menghapus kelas itu dan menambahkan yang berbedaOtherClass
. Apalagi pertanyaan itu sudah mendapat jawaban yang baik. Sejauh mana solusi Anda lebih baik sehingga layak untuk diposting?