Enums поддерживает наследование

Я часто сталкиваюсь с ситуацией, когда мы создаем класс, который воздействует на какое-то перечисление, но потом мы получаем его и хотим добавить в перечисление больше значений, не меняя базовый класс.

Я вижу этот вопрос из 2009 года: Наследование базового класса enum

Однако я знаю, что в C++ 11, 14, 17 был внесен ряд изменений в перечисление. Позволяют ли какие-либо из этих изменений расширить перечисления из базового класса в производный?

class Base 
{ 
   enum State {STATE_1, STATE_2, STATE_3}; 
};

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

... где мы хотим, чтобы производное имело перечисление, описывающее состояния, в которых оно может находиться, а именно: СОСТОЯНИЕ_1, СОСТОЯНИЕ_2, СОСТОЯНИЕ_3 и СОСТОЯНИЕ_4. На самом деле мы не хотим менять перечисление в базовом классе, потому что другие производные классы могут не иметь возможности находиться в STATE_4. Мы также не хотим создавать новое перечисление, потому что у нас уже есть одно для состояния в базе.

Используем ли мы вместо этого статические значения const, чтобы добиться этого 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; 
};

person Christopher Pisz    schedule 20.03.2017    source источник
comment
Нет, любые изменения перечисления с тех пор не имеют ничего общего с такого рода вещами.   -  person Kerrek SB    schedule 20.03.2017
comment
Сильно ли изменился enum в 11-14-17? Я знаю, что они ввели строго типизированный enum class, но я почти уверен, что простой enum остается в основном таким же, как и всегда.   -  person ShadowRanger    schedule 20.03.2017


Ответы (2)


Нет, С++ не допускает такого рода вещей. Base::Color — это совершенно отдельный тип от Derived::Color, никак не связанный с ними. Это ничем не отличается от любых других вложенных типов; вложенные типы, определенные в базовом классе, не связаны с вложенными типами, определенными в производном классе.

Перечисления также не могут наследоваться друг от друга.

Такого рода вещи в любом случае идут вразрез с хорошей практикой ООП. В конце концов, если производный класс вводит новый перечислитель, как с ним справится базовый класс? Как с этим справятся разные экземпляры производных классов?

Если Base определяет операцию над перечислением, то Base определяет совокупность перечисления, над которым оно работает, и каждый производный от него класс должен иметь возможность обрабатывать все эти параметры. В противном случае что-то не так с вашим виртуальным интерфейсом.

person Nicol Bolas    schedule 20.03.2017
comment
Что ж, если мы придумываем, как все должно работать, мое мнение таково: Base::Foo(DERIVED::Color::YELLOW); должен бросать, если только Foo не является виртуальным и не разрешается в Derived или что-то производное от Derived. На самом деле, я все равно должен квалифицировать Derived::YELLOW в вызове. Base::Foo(BASE::Color::RED) должен нормально работать как есть. Конечно, я не являюсь автором какого-либо компилятора и не знаю, что для этого потребуется, или его побочных эффектов. - person Christopher Pisz; 21.03.2017
comment
В конце концов, если производный класс вводит новый перечислитель, как с ним справится базовый класс? ... возможный вариант использования: базовый класс использует enum как индекс универсальной структуры данных, т.е. г. карту свойств map<SomeEnum, boost::type_erasure::any> и выполняет общие операции, такие как сериализация на этой карте. Было бы очень удобно расширить это перечисление в производных классах, чтобы добавить больше свойств. - person zett42; 21.03.2017

Почему бы просто не использовать пространства имен для группировки перечислений?

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 ;
} ;

Но будьте осторожны: «мой самый большой страх - излишество ...» :) Мне бы не понравилась какая-то глубокая иерархия пространств имен с перечислениями в них и тому подобное ...

person Chef Gladiator    schedule 05.01.2019
comment
Я не понимаю, как вы собираетесь расширять коллекцию перечислений с помощью пространств имен. Ваш пример функционально отличается от моего. - person Christopher Pisz; 07.01.2019
comment
@ChristopherPisz, честно говоря, я не собираюсь расширять коллекции перечислений, так как это стандартный C ++, где это невозможно. Я предложил то, что могло бы сработать в качестве логической замены. И, кажется, многие согласны. В частности, я не понимаю, почему нужно включить наследование перечислений в C++. Мы не придумываем, как здесь все должно работать, мы просто думаем в рамках стандартного C++. - person Chef Gladiator; 08.01.2019
comment
Я не понимаю, как ваша замена будет работать. Конечно, если вы не понимаете условия задачи, это неудивительно. Спасибо за усилия, я думаю. Я бы предпочел просто прибегнуть к использованию статического решения int. - person Christopher Pisz; 08.01.2019
comment
@ChristopherPisz отмечает, что это поможет решить, о чем вы просите, у меня нет замены, которая заставит эту работу работать. Base и Derivedэто два разных типа. enum в типе является атрибутом этого типа, а не его экземпляром. Таким образом, Base::State и Derived::State - это две разные вещи. Это сделано намеренно при разработке языка. Если вам нужно иметь что-то вроде расширяемых списков значений одного и того же типа, можно представить себе абстракцию C++, которая сделает это возможно правдоподобным в некотором узком контексте. - person Chef Gladiator; 08.01.2019
comment
расширяемые списки значений одного типа также известны как std::vector<T> в стандартном C++. Для решения времени компиляции, возможно, есть какое-то решение для метапрограммирования шаблонов. - person Chef Gladiator; 08.01.2019