Наследование базового перечислимого класса - PullRequest
71 голосов
/ 14 марта 2009

Есть ли шаблон, где я могу наследовать enum от другого enum в C ++ ??

Примерно так:

enum eBase 
{
   one=1, two, three
};


enum eDerived: public eBase
{
   four=4, five, six
};

Ответы [ 11 ]

88 голосов
/ 14 марта 2009
#include <iostream>
#include <ostream>

class Enum
{
public:
    enum
    {
        One = 1,
        Two,
        Last
    };
};

class EnumDeriv : public Enum
{
public:
    enum
    {
        Three = Enum::Last,
        Four,
        Five
    };
};

int main()
{
    std::cout << EnumDeriv::One << std::endl;
    std::cout << EnumDeriv::Four << std::endl;
    return 0;
}
58 голосов
/ 14 марта 2009

Не возможно. Наследования с перечислениями не существует.

Вместо этого вы можете использовать классы с именованными константами.

Пример:

class Colors
{
public:
  static const int RED = 1;
  static const int GREEN = 2;
};

class RGB : public Colors
{
  static const int BLUE = 10;
};


class FourColors : public Colors
{
public:
  static const int ORANGE = 100;
  static const int PURPLE = 101;
};
10 голосов
/ 08 апреля 2010

Вы не можете сделать это напрямую, но вы можете попробовать использовать решение из этой статьи.

Основная идея состоит в том, чтобы использовать вспомогательный шаблонный класс, который содержит значения enum и имеет оператор приведения типа. Учитывая, что базовым типом для enum является int, вы можете без проблем использовать этот класс держателя в своем коде вместо enum.

5 голосов
/ 19 сентября 2014

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

Я хотел бы отметить, что формулировка должна быть «расширение», а не «наследование». Расширение допускает большее количество значений (когда вы переходите от 3 до 6 значений в вашем примере), тогда как наследование означает наложение большего количества ограничений на данный базовый класс, так что набор возможностей уменьшается. Следовательно, потенциальное приведение будет работать с точностью до наследства. Вы можете привести производный класс к базовому классу, а не наоборот с наследованием класса. Но при наличии расширений вы «должны» иметь возможность приводить базовый класс к его расширению, а не наоборот. Я говорю «должен», потому что, как я уже сказал, такой языковой функции по-прежнему не существует.

3 голосов
/ 26 октября 2014

Как насчет этого? Хорошо, экземпляр создается для каждого возможного значения, но, кроме того, он очень гибкий. Есть ли минусы?

.h:

class BaseEnum
{
public:
  static const BaseEnum ONE;
  static const BaseEnum TWO;

  bool operator==(const BaseEnum& other);

protected:
  BaseEnum() : i(maxI++) {}
  const int i;
  static int maxI;
};

class DerivedEnum : public BaseEnum
{
public:
  static const DerivedEnum THREE;
};

.cpp:

int BaseEnum::maxI = 0;

bool BaseEnum::operator==(const BaseEnum& other) {
  return i == other.i;
}

const BaseEnum BaseEnum::ONE;
const BaseEnum BaseEnum::TWO;
const DerivedEnum DerivedEnum::THREE;

Использование:

BaseEnum e = DerivedEnum::THREE;

if (e == DerivedEnum::THREE) {
    std::cerr << "equal" << std::endl;
}
2 голосов
/ 05 января 2018

Вы можете использовать проект SuperEnum для создания расширяемых перечислений.

/*** my_enum.h ***/
class MyEnum: public SuperEnum<MyEnum>
{
public:
    MyEnum() {}
    explicit MyEnum(const int &value): SuperEnum(value) {}

    static const MyEnum element1;
    static const MyEnum element2;
    static const MyEnum element3;
};

/*** my_enum.cpp ***/
const MyEnum MyEnum::element1(1);
const MyEnum MyEnum::element2;
const MyEnum MyEnum::element3;

/*** my_enum2.h ***/
class MyEnum2: public MyEnum
{
public:
    MyEnum2() {}
    explicit MyEnum2(const int &value): MyEnum(value) {}

    static const MyEnum2 element4;
    static const MyEnum2 element5;
};

/*** my_enum2.cpp ***/
const MyEnum2 MyEnum2::element4;
const MyEnum2 MyEnum2::element5;

/*** main.cpp ***/
std::cout << MyEnum2::element3;
// Output: 3
2 голосов
/ 06 марта 2013

Как указано bayda, перечисления не имеют (и / или не должны) иметь функциональность, поэтому я применил следующий подход к вашему затруднительному случаю, адаптировав ответ Mykola Golubyev:

typedef struct
{
    enum
    {
        ONE = 1,
        TWO,
        LAST
    };
}BaseEnum;

typedef struct : public BaseEnum
{
    enum
    {
        THREE = BaseEnum::LAST,
        FOUR,
        FIVE
    };
}DerivedEnum;
2 голосов
/ 29 июня 2010

Что ж, если вы определите enum с тем же именем в производном классе и начнете его с последнего элемента соответствующего enum в базовом классе, вы получите почти то, что вы хотите - унаследованное перечисление. Посмотрите на этот код:

class Base
{
public:
enum ErrorType
  {
  GeneralError,
  NoMemory,
  FileNotFound,
  LastItem
  }
}

class Inherited: public Base
{
enum ErrorType
  {
  SocketError = Base::LastItem,
  NotEnoughBandwidth,
  }
}
0 голосов
/ 08 февраля 2019

Хак, но это то, что я придумал, имея дело с перечислениями с областью видимости:

enum class OriginalType {
   FOO,  // 0
   BAR   // 1
   END   // 2
};

enum class ExtendOriginalType : std::underlying_type_t<OriginalType> {
   EXTENDED_FOO = static_cast<std::underlying_type_t<OriginalType>>
                                           (OriginalType::END), // 2
   EXTENDED_BAR  // 3
};

и затем используйте как:

OriginalType myOriginalType = (OriginalType)ExtendOriginalType::EXTENDED_BAR;
0 голосов
/ 11 января 2019
enum xx {
   ONE = 1,
   TWO,
   xx_Done
};

enum yy {
   THREE = xx_Done,
   FOUR,
};

typedef int myenum;

static map<myenum,string>& mymap() {
   static map<myenum,string> statmap;
   statmap[ONE] = "One";
   statmap[TWO] = "Two";
   statmap[THREE] = "Three";
   statmap[FOUR] = "Four";
   return statmap;
}

Использование:

std::string s1 = mamap()[ONE];
std::string s4 = mymap()[FOUR];
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...