C++中模拟enum继承实现枚举公共父类型作为函数参数方案咨询
实现方案
方案1:使用C++17 std::variant(最推荐)
该方案天然类型安全,不需要自定义继承结构,也不需要手动管理状态,完全符合你的需求,现有枚举定义可以直接复用。
代码示例:
// 原有枚举无需修改 enum Fruit { apple, orange }; enum Drink { water, milk }; // 定义公共父类型 #include <variant> using Eatable = std::variant<Fruit, Drink>;
函数实现可根据场景选择两种分支判断方式:
#include <iostream> #include <variant> #include <type_traits> void LetsEat(Eatable eatable) { // 方式1:通过index判断类型,适合简单分支场景 if (eatable.index() == 0) { // 当前存储的是Fruit类型 Fruit f = std::get<Fruit>(eatable); switch(f) { case apple: std::cout << "吃苹果\n"; break; case orange: std::cout << "吃橙子\n"; break; } } else { // 当前存储的是Drink类型 Drink d = std::get<Drink>(eatable); switch(d) { case water: std::cout << "喝水\n"; break; case milk: std::cout << "喝牛奶\n"; break; } } // 方式2:通过重载lambda访问,代码更整洁,适合分支较多的场景 std::visit([](auto&& arg) { using T = std::decay_t<decltype(arg)>; if constexpr (std::is_same_v<T, Fruit>) { switch(arg) { case apple: std::cout << "吃苹果\n"; break; case orange: std::cout << "吃橙子\n"; break; } } else if constexpr (std::is_same_v<T, Drink>) { switch(arg) { case water: std::cout << "喝水\n"; break; case milk: std::cout << "喝牛奶\n"; break; } } }, eatable); }
调用时直接传入枚举值即可,无需额外初始化操作:
int main() { LetsEat(apple); LetsEat(milk); return 0; }
该方案完全类型安全,如果传入既不是Fruit也不是Drink的类型,编译阶段会直接报错。
方案2:自定义带标签的联合体(兼容C++11/14)
如果你使用的C版本不支持C17,可以自己封装轻量的标签联合体,不需要继承结构:
enum EatableType { TYPE_FRUIT, TYPE_DRINK }; struct Eatable { EatableType type; union { Fruit fruit; Drink drink; }; // 隐式转换构造,调用时不需要额外写初始化代码 Eatable(Fruit f) : type(TYPE_FRUIT), fruit(f) {} Eatable(Drink d) : type(TYPE_DRINK), drink(d) {} };
函数分支判断逻辑:
void LetsEat(Eatable eatable) { switch(eatable.type) { case TYPE_FRUIT: switch(eatable.fruit) { case apple: /* 业务逻辑 */ break; case orange: /* 业务逻辑 */ break; } break; case TYPE_DRINK: switch(eatable.drink) { case water: /* 业务逻辑 */ break; case milk: /* 业务逻辑 */ break; } break; } }
调用方式和方案1一致,直接传枚举值即可。
方案3:枚举值偏移合并(最简单,适合枚举固定不扩展的场景)
把两个枚举的取值范围错开,合并到同一个大枚举类型中:
enum Eatable { // Fruit取值范围0~99 apple = 0, orange, // Drink取值范围100~199 water = 100, milk };
该方案代码最简洁,缺点是原有Fruit和Drink枚举无法单独使用,适合不需要单独区分两类枚举的场景。
内容的提问来源于stack exchange,提问作者Aryan Firouzian
相关产品推荐
相关产品推荐

