【问题标题】:Is it possible to use a callback table which contains {sub,super}class function pointers?是否可以使用包含 {sub,super} 类函数指针的回调表?
【发布时间】:2019-05-25 13:07:00
【问题描述】:

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

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

这很好用,但我意识到我需要多个具有不同主要角色的不同网络接口(想想“管理接口”与“客户端数据接口”),所以我将 Conn 类复制到 ConnMgmt 和 ConnData .然而,很快就发现处理程序之间有足够的重叠,因此为两者创建一个公共类是有意义的。

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

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

我希望有一个表来将命令请求字符串映射到回调函数,但是我希望方法指针能够引用派生类中的方法。 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();
}

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

  • 拥有一个包含指向 ConnBase 和 ConnMgmt 中的方法指针的“ConnMgmt::handlers”表的想法是否从根本上被打破了?编译器发出嘶嘶声,说指针类型错误。
  • 如果有一种方法可以解决问题,我是否会进入未定义行为的领域(或更糟)?我已经读过它“应该”可以为子类使用方法指针类型,但是有一些与虚拟类相关的警告(并且在那个注释中:类中有 are 虚拟函数,但是所有处理函数都不是虚拟的)。
  • 考虑到我想要完成的任务(创建一个字符串到方法的调度程序,其中方法可能驻留在不同的类中(尽管总是属于同一个类层次结构)),是否有一些惯用的 C++17 方法来做到这一点?

(不允许提升)。

【问题讨论】:

  • 您需要将您的方法设为虚拟并将它们全部放在您的基类中。根据需要覆盖。如果做不到这一点,则存储绑定的std::functions 而不是内置函数指针。

标签: c++ inheritance c++17 pointer-to-member


【解决方案1】:

你可以做一些你需要的改变。

如果你把ProcFn的类型改为

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

那么您几乎可以构建您的ConnMgmt::handlers 表了。您需要指定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) };

每个派生类都需要自己的处理程序表和ProcFn typedef。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2019-03-28
    • 1970-01-01
    • 2010-12-06
    • 1970-01-01
    • 1970-01-01
    • 2012-10-28
    • 1970-01-01
    相关资源
    最近更新 更多