0

我已經設法編寫了一個模板類,像回調一樣工作,從這個問題的接受答案中學到了How to define a general member function pointer「事件」和成員函數指針的C++地圖

我希望有一個字符串鍵和回調值的映射,以便我可以調用與字符串匹配的正確回調。這會很好,但我需要地圖來支持不同類別的回調。現在它只能與一個類一起工作。它可以是任何類,因爲模板只有來自同一類的回調集合。

class Apple { 
public: 
    void Red() { 
     cout << "aa"; 
    } 
}; 

class Orange { 
public: 
    void Blue() { 
     cout << "bb"; 
    } 
}; 

template <typename T> 
class Callback { 
    T *obj; 
    void (T::*ptr) (void); 

public: 
    Callback (T *obj, void (T::*ptr) (void)) : obj (obj), ptr (ptr) { 

    } 

    void Call() { 
     (obj->*ptr)(); 
    } 
}; 

我可以用這個像這樣

Apple apple; 
Orange orange; 
Callback <Apple> callA (&apple, &Apple::Red); 
Callback <Orange> callB (&orange, &Orange::Blue); 
callA.call(); 
callB.call(); 

std::map <std::string, Callback <Apple>> appleCallbacks; 

我希望能夠做到這一點

std::map <std::string, Callback <anything>> anyCallbacks; 

我打算與共享相同的基礎一堆類使用類和除了名稱和它屬於哪個類之外,其他函數在定義上是相同的。

class Base { }; 

class ChildA : public Base { 
public: 
    void Talk(); 
} 

class ChildB : public Base { 
public: 
    void Walk(); 
} 

所以,如果這個工作,我將能夠把Talk()和Walk()放到地圖中。

這是可能的或我的觀點是有缺陷的開始?

回答

6

瘋狂的謊言,這樣:不要將回調綁定到特定的類。相反,使用std::function<Signature>對象並創建合適的函數對象:當您需要操作不同的類時,還需要操作不同類型的對象。使用std::function<...>應該做的伎倆,例如:

std::map<std::string, std::function<void()>> operations; 
operations["talk"] = std::bind(&ChildA::Talk, ChildA()); 
operations["walk"] = std::bind(&ChildB::Walk, ChildB()); 
operations["talk"](); 
4

沒有必要繼承在這裏。只需使用std::function來存儲成員函數指針和std::bind以將成員函數指針和對象實例綁定在一起。

#include <functional> 
#include <map> 
#include <string> 
#include <iostream> 

struct Apple { 
    void Red() { 
     std::cout << "aa\n"; 
    } 
}; 

struct Orange { 
    void Blue() { 
     std::cout << "bb\n"; 
    } 
}; 

int main() 
{ 
    std::map<std::string, std::function<void()>> m; 
    Apple a; 
    Orange o; 

    m["apple"] = std::bind(&Apple::Red, a); 
    m["orange"] = std::bind(&Orange::Blue, o); 

    m["apple"](); 
    m["orange"](); 
} 

輸出:

aa 
bb