如何解决如何将“命令处理程序映射”从派生类重构为基类?
我试图通过将某些通用功能从派生类移到基类来重构一些C ++代码。假设我有一个基类Fruit
和两个派生类Apple
和Orange
。这两个派生类目前都拥有一个私有映射,该映射将命令映射到成员函数,例如对于Apple
类,将是
typedef void (Apple::*CommandHandler)();
static const std::map<std::string,CommandHandler> commandhandlers;
由于commandhandlers
映射不会随时间变化,因此我将其设为静态,并且对于每个派生类,它都使用静态函数(例如)填充了命令处理程序。用于Apple
类:
static std::map<std::string,Apple::CommandHandler> mpInitCommandHandlerMap()
{
std::map<std::string,Apple::CommandHandler> commandhandlers;
commandhandlers.insert(std::make_pair("eat",&Apple::eat));
// ... and so on...
return commandhandlers;
}
其中
void eat() { std::cout << "eating apple" << std::endl; }
是eat
类中Apple
命令的(专用)命令处理程序的示例。
Apple
和Orange
的派生类还具有handle
函数来处理不同的命令:
void handle(const std::string& command)
{
const auto handler = commandhandlers.at(command);
(this->*handler)();
}
由于两个导出类的此handle
函数相同,因此我想将其移至Fruit
类。但是,这就是我遇到的问题。 commandhandlers
映射当前同时存在于Apple
和Orange
类中,并且命令处理函数的类型不同(typedef void (Apple::*CommandHandler)();
类的Apple
和typedef void (Orange::*CommandHandler)();
类的Orange
。
所以我的问题是:我想在commandhandler
类中只有一个handle
映射和一个Fruit
函数。我该如何做(最好现在使用C ++ 14)?完整的代码可在https://godbolt.org/z/87zbGa
解决方法
您可以使用CRTP进行分解,例如:
template <typename Derived>
class Fruit
{
public:
void handle(const std::string& command)
{
const auto handler = commandhandlers.at(command);
(static_cast<Derived*>(this)->*handler)();
}
protected:
using CommandHandler = void (Derived::*)();
static const std::map<std::string,CommandHandler> commandhandlers;
};
template <typename Derived>
const std::map<std::string,typename Fruit<Derived>::CommandHandler>
Fruit<Derived>::commandhandlers = Derived::mpInitCommandHandlerMap();
然后
class Apple : public Fruit<Apple>
{
friend class Fruit<Apple>;
private:
static std::map<std::string,CommandHandler> mpInitCommandHandlerMap()
{
return {
{"eat",&Apple::eat}
// ... and so on...
};
}
void eat() { std::cout << "eating apple" << std::endl; }
};
我在Apple
和Orange
之间删除了通用基类,如果需要可以重新引入。
将命令处理程序映射和handle函数移动为Fruit基类为
class Fruit
{
public:
void handle(const std::string& command)
{
const auto handler = commandhandlers_.at(command);
handler();
}
protected:
std::map<std::string,std::function<void()>> commandhandlers_;
};
,然后在派生类中初始化命令处理程序映射,例如对于苹果
Apple()
{
commandhandlers_ = mpInitCommandHandlerMap();
}
mpInitCommandHandlerMap
是非静态的似乎有效。另请参见https://godbolt.org/z/jx1cs8
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。