我正在尝试创建一个包含不同类的成员函数指针的映射。成员函数都具有相同的签名。为了做到这一点,我所有的类都继承了一个Object类,它只有默认构造函数,虚析构函数和虚拟ToString()const方法。
// The map looks like this
map<Object*, void (Object::*)()> mapOfMethodPointers;
// And here are the two classes that inherit Object
// Class A
class A : public Object
{
public:
void AFunc();
string ToString() const override;
};
void A::AFunc()
{
cout << "AFunc()" << endl;
}
string A::ToString() const
{
cout << "A" << endl;
}
// Class B
class B : public Object
{
public:
void BFunc();
string ToString() const override;
}
void B::BFunc()
{
cout << "BFunc()" << endl;
}
string B::ToString() const
{
cout << "B" << endl;
}
// Here is how add the member function pointers in the map
A a;
B b;
mapOfMethodPointers[*a] = &A::AFunc;
mapOfMethodPointers[*b] = &B::BFunc;
当我在地图中添加两个成员函数指针时,我得到以下错误:
无论A级和B级都是对象,我都无法进行此转换。我怎么能实现这样的呢?我需要像成员函数指针的多态这样的东西。我选择的实施并不起作用。有什么想法吗?
答案 0 :(得分:5)
为了做到这一点,我的所有类都继承了一个Object类,该类只有默认构造函数,虚拟析构函数和虚拟ToString()const方法。
这对于存储具有类似签名的多态函数来说是一个糟糕的解决方案。
以下是两个更好的解决方案:
&#39; 1。将函数指针实现为基本接口的特化(在您的情况下为Object
)。然后,在客户端代码中存储接口本身:
struct Object { virtual void Execute() = 0; }
/// old: map<Object*, void (Object::*)()> mapOfMethodPointers;
/// new:
std::vector<Object*> objects;
objects[10]->Execute(); // execution is agnostic of whichever instance you you use
在此解决方案中,执行将解析为A::Execute
,如下所述:
class A : public Object
{
void AFunc();
public:
virtual void Execute() override { AFunc(); }
};
使用此解决方案,您不需要功能映射(因为Object
的虚拟表本质上是一个功能映射)。
&#39; 2。根据泛型函数实现函数映射,然后用lambdas填充它:
代码:
/// old: map<Object*, void (Object::*)()> mapOfMethodPointers;
/// new:
map<Object*, std::function<void()>> mapOfMethodPointers;
// filling the map:
class A // not needed: public Object
{
public:
void AFunc(); // this is our interesting function
string ToString() const override;
};
A obj;
mapOfMethodPointers[&obj] = [&obj]() { obj.AFunc(); };
答案 1 :(得分:0)
您必须将派生成员函数强制转换为基类成员函数。这样做的语法有点笨拙,但完全合乎逻辑。一个限制是基类不能是抽象的。
这里是一个例子:
#include <iostream>
#include <map>
#include <string>
using namespace std;
class plant
{
public:
map<string, void(plant::*)(void)> _action;
void Action(string action);
};
void plant::Action(string action)
{
(this->*_action[action])();
}
class flower: public plant
{
public:
flower(void);
void look_at(void);
void smell(void);
void pick(void);
};
flower::flower(void)
{
_action["look at"] = (void(plant::*)(void))&flower::look_at;
_action["pick"] = (void(plant::*)(void))&flower::pick;
_action["smell"] = (void(plant::*)(void))&flower::smell;
}
void flower::look_at(void)
{
cout << "looking at flower" << endl;
}
void flower::smell(void)
{
cout << "smelling flower" << endl;
}
void flower::pick(void)
{
cout << "picking flower" << endl;
}
int main()
{
plant *myplant = new flower();
myplant->Action("look at");
myplant->Action("pick");
myplant->Action("smell");
delete myplant;
}