C++如何在派生类重定义基类enum class以消除代码重复
方案1:使用类模板实现静态多态(最推荐,无运行时开销,完全保留enum class类型安全)
不需要用虚函数实现动态多态,直接将按键枚举类型作为模板参数传入通用基类即可抽离所有公用逻辑:
#include <unordered_map> // 模板基类,ButtonEnum为派生类自定义的枚举类型 template<typename ButtonEnum> class DeviceHandler { public: bool getState(ButtonEnum btn) const { return buttonStateMap.at(btn); } // 状态更新等通用逻辑都可以放到基类实现 void updateState(ButtonEnum btn, bool state) { buttonStateMap[btn] = state; } protected: std::unordered_map<ButtonEnum, bool> buttonStateMap; }; class KeyboardHandler : public DeviceHandler<KeyboardHandler::Button> { public: enum class Button { shift, ctrl, alt, win }; using Key = Button; void onEvent(Key key, SomeEventClass e) { // 键盘专属业务逻辑 } }; class MouseHandler : public DeviceHandler<MouseHandler::Button> { public: enum class Button { left, right, middle }; void onEvent(Button btn, SomeEventClass e) { // 鼠标专属业务逻辑 } };
该方案完全保留enum class的类型安全特性,没有额外运行时开销,派生类只需要实现自身业务逻辑和自定义枚举即可。
方案2:添加非模板公共基类实现运行时多态
如果有运行时统一调度不同设备Handler的需求(比如用同一个数组存储所有输入设备实例),可以拆分两层基类:
#include <unordered_map> #include <any> class BaseDeviceHandler { public: virtual ~BaseDeviceHandler() = default; // 统一事件分发接口 virtual void dispatchEvent(const std::any& btn, SomeEventClass e) = 0; }; template<typename ButtonEnum> class DeviceHandler : public BaseDeviceHandler { public: bool getState(ButtonEnum btn) const { return buttonStateMap.at(btn); } void updateState(ButtonEnum btn, bool state) { buttonStateMap[btn] = state; } protected: std::unordered_map<ButtonEnum, bool> buttonStateMap; }; class KeyboardHandler : public DeviceHandler<KeyboardHandler::Button> { public: enum class Button { shift, ctrl, alt, win }; using Key = Button; void onEvent(Key key, SomeEventClass e) { // 键盘专属业务逻辑 } void dispatchEvent(const std::any& btn, SomeEventClass e) override { onEvent(std::any_cast<Key>(btn), e); } }; // MouseHandler实现逻辑和KeyboardHandler完全一致
该方案既保留了enum class的类型安全,又支持运行时多态,仅在事件分发环节有可忽略的微小性能损耗。
方案3:非模板基类+类型安全封装(适合不想用模板的场景)
如果不想引入模板继承,也可以在基类用枚举的底层整数类型做存储,通过模板成员函数保证上层调用的类型安全:
#include <unordered_map> #include <type_traits> class DeviceHandler { public: template<typename ButtonEnum> bool getState(ButtonEnum btn) const { return buttonStateMap.at(static_cast<std::underlying_type_t<ButtonEnum>>(btn)); } template<typename ButtonEnum> void updateState(ButtonEnum btn, bool state) { buttonStateMap[static_cast<std::underlying_type_t<ButtonEnum>>(btn)] = state; } virtual ~DeviceHandler() = default; private: std::unordered_map<int, bool> buttonStateMap; };
所有派生类共享同一个基类类型,调用时模板会自动推导枚举类型,传错枚举类型会直接编译报错,完全保留类型安全特性。
内容的提问来源于stack exchange,提问作者Demiler
相关产品推荐
相关产品推荐

