我设法编写了一个模板类,就像回调一样工作,从这个问题How to define a general member function pointer的接受答案中学习。
我希望有一个字符串键和回调值的映射,以便我可以调用匹配字符串的正确回调。这没关系,但我需要地图来支持来自不同类的回调。现在它只能用于一个类。它可以是任何类,因为模板只是来自同一类的回调集合。
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()放入地图中。
这是否可能或者我的观点是否有缺陷?
答案 0 :(得分: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"]();
答案 1 :(得分: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