是否可以使用包含 {sub,super}class 函数指针的回调 table?

Is it possible to use a callback table which contains {sub,super}class function pointers?

我目前有一个连接对象,它对传入的命令请求执行处理。每个命令都是一个字符串,使用无序映射映射到回调方法。一个说明核心功能的简化示例:

#include <iostream>
#include <string>
#include <unordered_map>
#include <functional>

class Conn;
typedef void (Conn::*ProcFn)();

class Conn
{
  private:
  void proc_ping();

  static const std::unordered_map<std::string, ProcFn> handlers;

  public:
  void simulate();
};

const std::unordered_map<std::string, ProcFn> Conn::handlers = {
  std::pair("ping", &Conn::proc_ping)
};

void Conn::proc_ping()
{
  std::cout << "ping!" << std::endl;
}

void Conn::simulate()
{
  auto pfn = handlers.at("ping");

  std::invoke(pfn, this);
}

int main()
{
  Conn c;

  c.simulate();
}

这工作正常,但我意识到我需要多个不同的网络接口,它们具有不同的主要角色(想想 "management interface" 与 "client data interface")所以我复制了 Conn class 到 ConnMgmt 和 ConnData。然而,很快就发现处理程序之间有足够的重叠,因此为两者创建一个公共 class 是有意义的。

我想做的是创建一个包含 ConnMgmt 和 ConnData 共享功能的 ConnBase。

我的问题与回调函数有关 table。

我想要一个 table 来将命令请求字符串映射到回调函数,但是我希望方法指针能够引用方法在派生的 classes 中。 IE。我有一个用于 ConnBase 和 ConnMgmt 或 ConnBase 和 ConnData 的调度程序(取决于调用哪个接口)。

这是[非功能性]代码,说明了我想要完成的要点:

#include <iostream>
#include <string>
#include <unordered_map>
#include <functional>

class ConnBase;
typedef void (ConnBase::*ProcFn)();

class ConnBase
{
  protected:
  void proc_ping();
};

void ConnBase::proc_ping()
{
  std::cout << "ping!" << std::endl;
}

class ConnMgmt : public ConnBase
{
  protected:
  static const std::unordered_map<std::string, ProcFn> handlers;

  void proc_create_user();

  public:
  void simulate();
};

void ConnMgmt::proc_create_user()
{
  std::cout << "create user!" << std::endl;
}

const std::unordered_map<std::string, ProcFn> ConnMgmt::handlers = {
  std::pair("ping", &ConnBase::proc_ping),
  std::pair("create_user", &ConnMgmt::proc_create_user)
};

void ConnMgmt::simulate()
{
  auto pfn = handlers.at("ping");

  std::invoke(pfn, this);

  pfn = handlers.at("create_user");

  std::invoke(pfn, this);
}

int main()
{
  ConnMgmt c;

  c.simulate();
}

这段代码在几个方面被破坏了,但我特别想知道是否:

(不允许提升)。

您可以通过一些更改来完成所需的操作。

如果将 ProcFn 的类型更改为

typedef void (ConnMgmt::*ProcFn)();

那么你几乎已经准备好构建你的 ConnMgmt::handlers table。您需要为 std::pair 指定类型。然后剩下的问题是 ConnBase::proc_ping 受到保护,无法访问。解决这个问题的方法是将引用更改为 ConnMgmt::proc_ping.

const std::unordered_map ConnMgmt::handlers = { std::pair("ping", &ConnMgmt::proc_ping), std::pair("create_user", &ConnMgmt::proc_create_user) };

每个派生的 class 都需要自己的处理程序 table 和 ProcFn 类型定义。