基于字符串选择成员函数
Choosing a member function based on a string
我有一组硬件处理程序类,它们都是从基类派生的,必须响应传入的数据包。该数据包的一部分是ASCII字符串,它确定了硬件处理程序的哪个成员函数用于处理数据包(例如"风扇"将执行ToggleFan()
函数。
class HardwareHandler {
virtual void dispatchCommand(const String& cmd) = 0;
}
class FooblerHandler : public HardwareHandler {
void toogleFan();
void dispatchCommand(const String& cmd) {
//is this a "good" way to do this?
if (cmd == "fan")
toggleFan();
}
}
我使用JUCE作为一个框架,这意味着我有模板化的HashMap
s和String
。
然而,我很难想出一个基于这个字符串选择正确处理程序函数的整洁方法。构建
if (str == "hello")
FooCommand();
else if (str == "bar")
BarCommand();
在我看来,概念上很难看,因为里面有很多相对昂贵的字符串比较。然而,代码很容易编写,并且每个类的逻辑都保存在一个位置。
我尝试过的另一种选择是制作一个字符串到枚举的哈希映射,并使用该开关语句:
switch (str.getHash())
{
case CmdFoo:
FooCommnad();
break;
....and so on
}
然而,这也需要我设置一个静态哈希映射,以及维护开关以匹配。
我还尝试了一种从字符串到成员函数指针本身的哈希映射,希望能够直接从字符串跳到成员函数,而无需在case语句中列出它们,并且还允许一个非常通用的调度函数,因为它只需要在哈希映射中查找,它甚至不需要知道所有的选项——它们可以单独包含在哈希映射中,这样我就可以将dispatch函数推送到基本处理程序类中,而不必在每个特定的设备处理程序中重复。然而,这个方法让我很困惑,因为我不太清楚如何正确地完成它,甚至不知道是否可以使用静态哈希图和成员函数来完成它。
有没有一种惯用的方法可以基于字符串(或类似的难以比较的类型)向成员函数调度,最好是使用尽可能多的逻辑进行泛型化并移动到父类?
这是我的尝试。您可以将映射机制封装到一个类中:
#include <iostream>
#include <string>
#include <functional>
#include <map>
class X;
template<class X>
class handler_factory;
template<>
class handler_factory<X>
{
private:
using HandlerType = void (X::*)();
public:
handler_factory();
HandlerType get(const std::string& name) const
{
if (handlers.find(name) == handlers.end())
return nullptr;
else
return (*handlers.find(name)).second;
}
private:
std::map<std::string, HandlerType> handlers;
};
class X
{
public:
friend class handler_factory<X>;
private:
void f();
void h();
};
handler_factory<X>::handler_factory()
{
handlers["f"] = &X::f;
handlers["h"] = &X::h;
}
void X::f() { std::cout << "X::f();"; }
void X::h() { std::cout << "X::h();"; }
您的调度方法可以实现为:
void dispatch_method(const std::string& name)
{
if (find_handler(name))
(this->*find_handler(name))();
}
int main()
{
X().dispatch_method("f");
}
其中find_handler
被定义为私有助手方法:
private:
auto find_handler(const std::string& name)
-> decltype(handler_factory<X>().get(name))
{
return handler_factory<X>().get(name);
}
我认为处理这个问题最有效的方法是创建一个std::map
,将字符串映射到适当的函数中。该方法快速(由于采用了对数搜索算法),简单且安全。
class FooblerHandler : public HardwareHandler {
typedef void (HardwareHandler::*function)();
map<string,function> commandMap;
void dispatchCommand(const string& cmd) {
if(commandMap.count(cmd))
(this->*commandMap.find(cmd)->second)();
else
cout << "No command found with name "" <<cmd<< ""." << endl;
}
};
当然,您应该在构造函数中初始化映射(或者在使用它之前的某个地方):
commandMap["fan"] = &FooblerHandler::toogleFan;
commandMap["someOtherCommand"] = &FooblerHandler::otherFunction;
映射并包含在几乎所有IDE提供的标准模板库(STL)中。
编辑:我最后没有完全看完课文。现在你知道语法了:)
- 对RValue对象调用的LValue ref限定成员函数
- 为什么使用 "this" 指针调用派生成员函数?
- 将公共但非静态的成员函数与ALGLIB集成
- 使用指向成员的指针将成员函数作为参数传递
- 将重载的成员函数传递给函数模板
- 我不小心调用了一个没有自己类对象的成员函数.但这是怎么回事呢
- 如何在C++中使用非静态成员函数作为回调函数
- C++错误C2600:无法定义编译器生成的特殊成员函数(必须首先在类中声明)
- 关联容器的下界复杂性:成员函数与非成员函数
- 在 C++ 中用派生类型重写成员函数
- 链表的泛型函数remove()与成员函数remove)
- 如何将lambda作为模板类的成员函数参数
- constexpr构造函数需要常量成员函数时出现问题
- 将自由函数绑定为类成员函数
- 区分非成员函数和头文件中的成员函数
- 如何从子成员函数修改父公共成员变量
- 保留对其他类的成员函数的引用
- 在运算符重载定义中使用成员函数(const错误)
- 内联如何影响模块接口中的成员函数
- 将成员函数指针作为参数传递给模板方法