枚举支持继承

5
我经常遇到这样的情况:我们创建了一个作用于某个枚举类型的类,但后来又派生出子类,并希望在不改变基类的情况下添加更多的枚举值。
我看到了这个来自2009年的问题: Base enum class inheritance 然而,我知道在C++11、14、17中都对枚举类型进行了一些更改。这些变化中有哪些允许从基类扩展枚举类型到派生类呢?
class Base 
{ 
   enum State {STATE_1, STATE_2, STATE_3}; 
};

class Derived : public Base 
{ 
   enum State {STATE_4};
}; 

...在这里,我们希望派生类拥有一个描述它可能存在的状态(STATE_1、STATE_2、STATE_3和STATE_4)的枚举。我们不想更改基类中的枚举,因为其他派生类可能没有能够处于STATE_4状态的能力。我们也不想创建一个新的枚举,因为我们已经在基类中有一个State的枚举。

8年后,我们仍然使用静态常量值来实现这一点吗?

class Base 
{ 
   static int STATE_1= 0;
   static int STATE_2= 1;
   static int STATE_3= 2; 
};

class Derived : public Base 
{ 
   static int STATE_4= 3; 
};

2
不,自那时起的任何枚举更改都与那种事情无关。 - Kerrek SB
1
enum 在 11-14-17 版本中有很大的变化吗?我知道他们引入了强类型的 enum class,但我相信普通的 enum 基本上仍然和以前一样。 - ShadowRanger
2个回答

6
不,C++不支持这种操作。Base::Color是一种完全独立于Derived::Color的类型,与它们没有任何关系。这与其他嵌套类型没有区别;在基类中定义的嵌套类型与在派生类中定义的嵌套类型之间没有连接。
枚举也不能相互继承。
这种做法往往违反良好的OOP实践。毕竟,如果派生类引入了一个新的枚举器,基类如何处理它?不同的派生类实例如何处理它?
如果Base定义了一个对枚举的操作,那么Base定义了它所操作的枚举的总体,每个从它派生的类都应该能够处理所有这些选项。否则,你的虚拟接口出现了严重的问题。

好的,如果我们正在编写如何工作的内容,我的意见是:Base :: Foo(DERIVED :: Color :: YELLOW); 除非Foo是虚拟的并且解析为Derived或Derived的派生物,否则应该抛出异常。 实际上,在调用中我应该限定Derived :: YELLOW。Base :: Foo(BASE :: Color :: RED)应该按原样工作。 当然,我不是任何编译器的作者,也不知道那需要什么或其副作用。 - Christopher Pisz
1
毕竟,如果派生类引入了一个新的枚举器,基类会如何处理呢?可能的用例:基类使用枚举作为通用数据结构的索引,例如“属性”映射map<SomeEnum, boost::type_erasure::any>并在该映射上执行通用操作,例如序列化。在派生类中扩展该枚举以添加更多“属性”将非常方便。 - zett42

1
为什么不使用命名空间来分组枚举?
namespace my_codes {
   enum class color { red, green, blue } ;
   enum class origin { server, client } ;
} // my_codes

使用可能是

struct my_signal {
     my_codes::color  flag ;
     my_codes::origin  source ;
} ;

但要小心: "过度杀伤是我最大的恐惧..." :) 我不喜欢有很深的命名空间层次结构和其中的枚举等等...

我不明白你打算如何使用命名空间来扩展枚举集合。你的示例在功能上与我的不同。 - Christopher Pisz
@ChristopherPisz,坦白地说,我不打算“扩展枚举集合”,因为这是标准C++,不可能实现。我提供了一个可能作为逻辑替代的方案。而且似乎很多人都同意这个方案。关键是我不明白为什么有人想在C++中启用枚举继承。我们在这里不是“编造事物应该如何工作”,而是简单地思考标准C++的范围内的问题。 - Chef Gladiator
我不明白你的替换方法如何能够奏效。当然,如果你没有理解问题陈述,那也不足为奇。感谢你的努力,但我宁愿使用静态整数解决方案。 - Christopher Pisz
@ChristopherPisz,没有什么能解决你所要求的问题,我没有任何“替代品”可以使其工作。BaseDerived是两种不同的类型。类型中的enum是该类型的属性,而不是它的实例。因此,Base::StateDerived::State是两个不同的东西。这是语言设计上的故意安排。如果你需要像可扩展列表一样的相同类型的值,可以想象一下C++抽象,这可能在某些狭窄的上下文中是可行的 - Chef Gladiator
“可扩展的相同类型值列表”在标准C++中也被称为std::vector<T>。对于编译时解决方案,可能存在一些模板元编程解决方案。 - Chef Gladiator

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接