【发布时间】: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