Есть ли шаблон, по которому я могу наследовать перечисление от другого перечисления в С++??
Что-то такое:
enum eBase
{
one=1, two, three
};
enum eDerived: public eBase
{
four=4, five, six
};
Есть ли шаблон, по которому я могу наследовать перечисление от другого перечисления в С++??
Что-то такое:
enum eBase
{
one=1, two, three
};
enum eDerived: public eBase
{
four=4, five, six
};
Невозможно. В перечислениях нет наследования.
Вместо этого вы можете использовать классы с именованными константами int.
Пример:
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;
};
Colors
. Вы используете только значения int в статических членах const.
- person jiandingzhe; 20.01.2015
Color
, как вы могли бы для enum
.
- person Drew Dormann; 15.10.2017
static const int RED
он становится static const Colors RED
, инициализирующим переменную e, помещая значение int в приватное поле, он мог бы это сделать
- person Moia; 26.07.2018
static const Colors RED
, то как называется окружающий класс? Я пытаюсь сделать что-то похожее на OP и задаюсь вопросом о вашем обходном пути.
- person ; 12.12.2019
Вы не можете сделать это напрямую, но можете попробовать использовать решение из этого. статья.
Основная идея состоит в том, чтобы использовать вспомогательный класс шаблона, который содержит значения перечисления и имеет оператор приведения типа. Учитывая, что базовым типом для перечисления является int
, вы можете легко использовать этот класс-держатель в своем коде вместо перечисления.
К сожалению, это невозможно в С++ 14. Я надеюсь, что у нас будет такая языковая функция в C++17. Поскольку у вас уже есть несколько обходных путей для вашей проблемы, я не буду предлагать решение.
Я хотел бы отметить, что формулировка должна быть «расширение», а не «наследство». Расширение позволяет использовать больше значений (поскольку в вашем примере вы переходите от 3 к 6 значениям), тогда как наследование означает наложение дополнительных ограничений на данный базовый класс, поэтому набор возможностей сокращается. Следовательно, потенциальное приведение будет работать прямо противоположно наследованию. Вы можете привести производный класс к базовому классу, а не наоборот с наследованием класса. Но при наличии расширений вы «должны» иметь возможность преобразовать базовый класс в его расширение, а не наоборот. Я говорю «должен», потому что, как я уже сказал, такой языковой функции до сих пор не существует.
extends
— это ключевое слово для наследования в языке Eiffel.
- person Cheers and hth. - Alf; 28.06.2015
Как насчет этого? Хорошо, экземпляр создается для каждого возможного значения, но, кроме того, он очень гибкий. Есть ли недостатки?
.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;
}
BaseEnum::i
общедоступным и BaseEnum::maxI
закрытым.
- person Knitschi; 11.01.2017
Что ж, если вы определите enum
с тем же именем в производном классе и начнете его с последнего элемента соответствующего enum
в базовом классе, вы получите почти то, что хотите - унаследованное перечисление. Посмотрите на этот код:
class Base
{
public:
enum ErrorType
{
GeneralError,
NoMemory,
FileNotFound,
LastItem,
};
};
class Inherited: public Base
{
public:
enum ErrorType
{
SocketError = Base::LastItem,
NotEnoughBandwidth,
};
};
Как заявил bayda
, перечисление не имеет (и/или не должно) функциональности, поэтому я применил следующий подход к вашему затруднению, адаптировав ответ Mykola Golubyev
:
typedef struct
{
enum
{
ONE = 1,
TWO,
LAST
};
}BaseEnum;
typedef struct : public BaseEnum
{
enum
{
THREE = BaseEnum::LAST,
FOUR,
FIVE
};
}DerivedEnum;
Вы можете использовать проект 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
const int&
для простого int
- person Moia; 26.07.2018
Немного хакерский, но это то, что я придумал, если имел дело с перечислениями с областью действия:
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;
Этот ответ является вариантом ответа Брайана Р. Бонди. Поскольку это было запрошено в комментарии, я добавляю его как ответ. Я не указываю на то, действительно ли это стоит.
#include <iostream>
class Colors
{
public:
static Colors RED;
static Colors GREEN;
operator int(){ return value; }
operator int() const{ return value; }
protected:
Colors(int v) : value{v}{}
private:
int value;
};
Colors Colors::RED{1};
Colors Colors::GREEN{2};
class RGB : public Colors
{
public:
static RGB BLUE;
private:
RGB(int v) : Colors(v){}
};
RGB RGB::BLUE{10};
int main ()
{
std::cout << Colors::RED << " " << RGB::RED << std::endl;
}
Невозможно.
Но вы можете анонимно определить перечисление в классе, а затем добавить дополнительные константы перечисления в производных классах.
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];
int basic(EnumBase b) { return b; }
и int derived(EnumDeriv d) { return d; }
, эти типы не будут конвертироваться в int
, в отличие от простых перечислений. И когда вы попробуете даже такой простой код, как этот: cout << basic(EnumBase::One) << endl;
, то вы получите ошибку: conversion from ‘EnumBase::<anonymous enum>’ to non-scalar type ‘EnumBase’ requested
. Эти проблемы, вероятно, можно решить, добавив несколько операторов преобразования.
- person SasQ; 12.12.2012