기본 열거 형 클래스 상속


79

C ++의 다른 열거 형에서 열거 형을 상속 할 수있는 패턴이 있습니까 ??

그런 것 :

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


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

답변:


67

불가능합니다. 열거 형에는 상속이 없습니다.

대신 명명 된 const 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;
};

이 솔루션에 문제가 있습니까? 예를 들어, (다형성에 대해 깊이 이해하지 못합니다) vector <Colors>를 가지고 p = std :: find (mycolors, mycolor + length, Colors :: ORANGE);를 사용하는 것이 가능할까요?
jespestana

1
@jespestana 아니요, Colors클래스 인스턴스를 사용하지 않습니다 . 정적 const 멤버에서만 int 값을 사용합니다.
jiandingzhe

내가 당신을 옳게 이해한다면; 그런 다음 vector <Int> 컨테이너를 사용해야합니다. 하지만 여전히 다음과 같이 쓸 수 있습니다. p = std :: find (mycolors, mycolor + length, Colors :: ORANGE) ;. 권리?
jespestana

1
@jespestana 절대적으로. 또한 검색이 매우 일반적인 작업 인 경우 flat_set 또는 열린 주소 해시 세트 사용을 고려하십시오.
v.oddou

1
Re : 이 솔루션에 문제가 있습니까? 이 값이 더 이상 구별 유형의 것을 문제. 당신은 필요한 함수 쓸 수 없습니다 Color당신이 수 등을 enum.
드류 Dormann에게

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

1
혼란스러워! 그런 다음 변수 또는 함수 인수에서 Enum 유형을 어떻게 참조하고 Enum을 예상하는 함수에 EnumDeriv가 제공되지 않았는지 어떻게 확인할 수 있습니까?
Sideshow Bob

21
작동하지 않습니다. 일부 함수 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. 이러한 문제는 일부 변환 연산자를 추가하여 극복 할 수 있습니다.
SasQ

10

직접 할 수는 없지만 기사의 솔루션을 사용해 볼 수 있습니다 .

주요 아이디어는 enum 값을 보유하고 유형 캐스트 ​​연산자를 갖는 도우미 템플릿 클래스를 사용하는 것입니다. enum의 기본 유형이 enum int대신 코드에서이 홀더 클래스를 원활하게 사용할 수 있다는 점을 고려하십시오 .


이 코드 스 니펫은 질문을 해결할 수 있지만 설명을 포함하면 게시물의 품질을 향상시키는 데 큰 도움이됩니다. 미래에 독자를 위해 질문에 답하고 있으며 해당 사용자는 코드 제안 이유를 모를 수 있습니다.
NathanOliver

이것은 훌륭한 대답입니다. 이는 "문제에 대해 다른 방식으로 생각"하는 사례 중 하나이며 템플릿을 사용한다는 아이디어가 실제로 계산서에 적합합니다.
Den-Jason

또한이 vis-a-vis 템플릿에 대한 몇 가지 솔루션을 살펴보십시오. stackoverflow.com/questions/5871722/…
Den-Jason

5

불행히도 C ++ 14에서는 불가능합니다. 나는 우리가 C ++ 17에서 그러한 언어 기능을 가지기를 바랍니다. 이미 문제에 대한 해결 방법이 거의 없으므로 해결책을 제공하지 않을 것입니다.

나는 그 표현이 "상속"이 아니라 "확장"이어야한다는 점을 지적하고 싶습니다. 확장은 더 많은 값을 허용하는 반면 (예제에서 3에서 6 값으로 점프 할 때) 상속은 주어진 기본 클래스에 더 많은 제약 조건을 적용하여 가능성 집합을 축소하는 것을 의미합니다. 따라서 잠재적 캐스팅은 상속과 정반대로 작동합니다. 파생 클래스를 기본 클래스로 캐스팅 할 수 있으며 클래스 상속을 사용하면 그 반대가 아닙니다. 그러나 확장이있을 때 당신은 기본 클래스를 역이 아닌 확장으로 캐스팅 할 수 있어야합니다. 내가 말했듯이 그런 언어 기능이 아직 존재하지 않기 때문에 "해야한다"고 말하는 것입니다.


참고 extends에펠 언어의 상속에 대한 키워드입니다.
건배와 hth. - 알프

이 경우 Liskov 대체 원칙이 존중되지 않기 때문에 당신이 옳습니다. 코미 티는이 때문에 구문 상 상속처럼 보이는 솔루션을 받아들이지 않을 것입니다.
v.oddou

4

이것은 어떤가요? 좋습니다. 가능한 모든 값에 대해 인스턴스가 생성되지만 그 외에도 매우 유연합니다. 단점이 있습니까?

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

내가 볼 수있는 유일한 단점은 더 높은 메모리 소비와 더 많은 코드 라인이 필요하다는 것입니다. 그러나 나는 당신의 해결책을 시도 할 것입니다.
Knitschi

나는 또한 BaseEnum::i공개 및 BaseEnum::maxI비공개로 설정했습니다.
Knitschi

보호 된 기본 생성자는 기본 생성자가 필요한 타사 매크로 또는 템플릿에서 열거 형을 사용해야하는 경우 문제가 될 수 있습니다.
Knitschi

3

음, enum파생 클래스에서 동일한 이름으로 정의 하고 enum기본 클래스에서 해당 항목의 마지막 항목에서 시작하면 거의 원하는대로 상속 된 열거 형을 받게됩니다. 이 코드를보십시오 :

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

class Inherited: public Base
{
public:
    enum ErrorType
    {
        SocketError = Base::LastItem,
        NotEnoughBandwidth,
    };
};

1
코드를 컴파일 할 수있는 동안에는 컴파일러가 base :: ErrorType에서 Inherited :: ErrorType으로 변환 할 수 없기 때문에 사용할 수 없습니다.
bavaza

1
@bavaza, 물론 값을 매개 변수로 전달할 때 열거 형 대신 정수를 사용해야합니다.
Haspemulator 2011 년

2

에 의해 언급했듯이 bayda열거 형에는 기능이 없으므로 Mykola Golubyev의 응답 을 조정하여 다음과 같은 접근 방식을 취했습니다 .

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

typedef struct : public BaseEnum
{
    enum
    {
        THREE = BaseEnum::LAST,
        FOUR,
        FIVE
    };
}DerivedEnum;

2
이 솔루션에는 몇 가지 문제가 있습니다. 첫째, DerivedEnum의 시작점을 설정하는 것 외에는 실제로 존재하지 않는 LAST로 BaseEnum을 오염시킵니다. 둘째, DerivedEnum 값과 충돌하는 BaseEnum의 일부 값을 명시 적으로 설정하려면 어떻게해야합니까? 어쨌든 그것은 아마도 C ++ 14에서 우리가 할 수있는 최선일 것입니다.
Огњен Шобајић

내가 언급처럼, 그것이 완전성을위한 방법을 표현하므로, 그것은 이전의 포스터가 논리적 자신의 예에서 문제가 나의 문제가되지 않습니다, 이전의 예에서 적응 것
경계를

2

프로젝트 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

1
오래된 게시물이지만 대답 할 가치가 있다고 생각합니다. 기본 생성자를 제거하고 명시 적 생성자를 개인으로 이동하는 것이 좋습니다. 수행하는 방식으로 변수를 초기화 할 수 있습니다. 물론 당신은 제거해야 const int&하는 간단한 위해int
Moia

2

일종의 해키이지만 범위가 지정된 열거 형을 다룰 때 내가 생각 해낸 것입니다.

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;

2

이 답변은 Brian R. Bondy 답변의 변형입니다. 댓글에서 요청되었으므로 답변으로 추가하고 있습니다. 그래도 정말 가치가 있는지 지적하지 않습니다.

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

Coliru에서 라이브


0

불가능한.
그러나 클래스에서 익명으로 열거 형을 정의한 다음 파생 클래스에서 추가 열거 형 상수를 추가 할 수 있습니다.


-2
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];
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.