2013-01-07 23 views
49

我知道這已被問了很多次,因此很難挖掘cruft並找到一個簡單的例子。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()既要對付MyClassYourClass工作。我很抱歉,但這只是我的大腦的工作方式,我需要看到一個簡單的例子,說明在我能理解爲什麼/如何工作之前,哪些方法可行。如果您現在有一個最喜歡的方式來完成這項工作,請將該代碼標記並重新發布。

[編輯]

有人回答,但答案被刪除之前,我可以給複選標記。 我的答案是模板函數。更改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); 
     } 
}; 
+2

誰發佈了模板化函數示例?您有複選標記,但您在測試時刪除了您的答案。它完全符合我的需要。一個簡單的函數模板在我讀的所有其他信息的燉菜中迷失了。您的答案添加爲編輯問題。 – BentFX

+0

我認爲這是JaredC。你可能需要追捕他= P – WhozCraig

回答

115

而不必靜態方法和身邊掠過的指針類實例,你可以在新的C++ 11個標準使用功能:std::functionstd::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 functions

handler->addHandler([](int x) { std::cout << "x is " << x << '\n'; }); 
+3

感謝Joachim!這個例子對神祕的std :: function和std :: bind做了大量的工作。我一定會在將來使用它!我仍然沒有得到lambda :) – BentFX

+0

模板化的類只是我所需要的,但是靜態函數和實例指針並不能提供很好的讀取。 :)我越看越好,我越瞭解它,誰知道,這可能就是未來。 – BentFX

+0

@BentFX不客氣! :) –

2

你想要做的是做一個接口,處理這個代碼和所有的類實現接口。

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建議使用模板。

0

MyClassYourClass都可以從SomeonesClass得到,它有一個抽象(虛擬)Callback方法。您的addHandler將接受類型爲SomeonesClassMyClass的對象,並且YourClass可以覆蓋Callback以提供其回調行爲的具體實現。

+0

對於我正在做的事我玩弄了這個想法。但是由於那些使用我的處理程序的類別很多,我沒有把它看作是一個選項。 – BentFX

-1

如果有不同參數值的回調可以按如下方式使用模板:
//編譯:克++ -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(); 
} 
+1

你能解釋一下你做了什麼來解決OP的問題嗎?是否真的有必要包含OP的完整代碼? OP想讓他的代碼與他的'YourClass'一起工作。你似乎已經刪除了這個類並添加了一個不同的'OtherClass'。而且,這個問題已經得到了廣泛的回答。您的解決方案在多大程度上更好,因此值得發佈? – honk

+0

我沒有說我的帖子是一個更好的解決方案。我展示瞭如何以模板的方式使用「OtherClass」。 – mohDady

3

下面是一個簡潔的版本,它與類方法回調和常規函數回調一起使用。在本例中,爲了顯示參數如何處理,回調函數採用兩個參數:boolint

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方法和私有數據。至少對我來說,這可以最大限度地減少實施過程中犯錯的機率。