映射不同类的成员函数指针

C++ map of member function pointers of different classes

本文关键字:函数 指针 成员 同类 映射      更新时间:2023-10-16

我试图创建一个包含不同类的成员函数指针的映射。成员函数都有相同的签名。为了做到这一点,我的所有类都继承了一个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;

当我在map中添加两个成员函数指针时,会得到以下错误:

  1. 不能转换的空白(B:: *)() ', '无效(对象::*)()
  2. 不能转换的空白(A:: *)() ', '无效(对象::*)()

不管类A和类B都是对象,我都不能进行这种转换。我怎样才能做到这一点呢?我需要成员函数指针的多态。我选择的实现不起作用。什么好主意吗?

为了做到这一点,我所有的类都继承了一个Object类,这个类只有默认构造函数、虚析构函数和虚ToString() const方法。

对于存储具有相似签名的多态函数来说,这是一个糟糕的解决方案。

这里有两个更好的解决方案:

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

在这个解决方案中,Execute将解析为A::Execute,定义如下:

class A : public Object
{
     void AFunc();
public:
    virtual void Execute() override { AFunc(); }
};

使用此解决方案,您不需要函数映射(因为Object 的虚表本质上是一个函数映射)。

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(); };

必须将派生成员函数强制转换为基类成员函数。它的语法有点笨拙,但完全符合逻辑。一个限制是基类不能是抽象的。

下面是一个例子:

#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;
}