본문 바로가기
C,C++/C++

[C++] C 스타일 enum과 C++ 11의 Enum class에 차이에 대해 알아보자

by woohyeon 2019. 12. 18.
반응형

기존의 C 스타일 enum과 달리 C++ 11에서 등장한 enum class는 확실한 타입이 생겼다. 기존 enum은 타입이 정해져있지 않고 컴파일러가 암시적으로 정수로 변환해주는 형식이였다.

또한 다음과 같이 2개의 다른 enum 타입이 있을 때, 서로 비교가 가능했다. 이는 실제론 단순히 숫자이기 때문에 비교가 되지만 의미상으론 서로 다른 enum 타입을 비교한다는 것이 옳지 않았다.

enum eColor
{
  Red,   // 0
  Green, // 1
  Blue,  // 2
  Count  // 3
};

enum eAnimal
{
  Tiger, // 0
  Lion,  // 1
  Hipo,  // 2
  Count2 // 3
  // Count // 다른 enum 멤버의 이름과 중복될 수 없음
};

void main()
{
  eColor c = Green;
  eAnimal a = Lion;
  
  int n = c; // c가 묵시적으로 int 타입으로 변환되어 들어가짐
  static_assert(c == s); // 1(Green)과 1(Lion)을 비교
  
  for(size_t i = 0; i < Count; ++i)
  {
     ...
  }
}


위 코드엔 여러 문제점 들이 있다.

1. 서로 다른 enum의 멤버의 이름이 중복될 수 없다.
eColor 멤버의 Count와 eAnimal 멤버의 Count와 같이 이름이 중복될 수 없다.

2. enum 타입의 값들이 자동으로 정수로 변환되어 계산, 비교 및 출력된다.
따라서 eColor 타입의 멤버와 eAnimal 타입의 멤버끼리 비교가 가능하며 이는 의미상으로 옳지 못하다.
또한 반복문과 같이 바로 정수처럼 사용할 수 있다. 이는 컴파일러가 묵시적으로 정수타입으로 변환해주기 때문이다.

3. 특정 enum 멤버를 따로 선언 및 초기화하지 않고 사용 가능하기 때문에 소속이 불분명하며 실수할 여지를 줄 수 있다.

4. 기본적으로 enum 멤버는 int 타입을 가진다. 만약 작은 범위의 수를 사용한다면 메모리 낭비가 될 것이고, 더 큰 범위가 필요하다면 문제가 될 수도 있다.





이를 보완하여 등장한 enum class는 다음과 같이 강화되었다.

1.  enum class라는 특정 타입을 가진다. 따라서 서로 다른 enum class 멤버의 이름이 중복될 수 있다.

enum class eColor {
  Red, Green, Blue, Count
};

enum class eAnimal {
  Tiger, Lion, Hipo, Count
};


2. class라는 타입이 생겼기 때문에 멤버를 소속없이 이름만 가지고 사용할 수 없다.

int a = Lion; // 에러
eAnimal b = eAnimal::Lion; // OK
int c = static_cast<int>(eAnimal::Lion); // OK 


3. 형변환을 하지 않는 이상 서로 다른 enum class 타입끼리 비교할 수 없다.

eColor c = eColor::Red;
eAnimal a = eAnimal::Tiger;

if(c == a) // 비교 불가
{
  ...
}



4. enum class 멤버의 타입을 정해줄 수 있다. (int 내에서)

enum class eAnimal : int8_t // 1바이트(8bit) 타입 정수형
{
  Tiger
};

enum class eAnimal2 : int16_t // 2바이트(16bit) 타입 정수형
{
  Lion
};

static_assert(sizeof(eAnimal::Tiger) == 1);
static_assert(sizeof(eAnimal2::Lion) == 2);


이처럼 많은 것이 제한적이고 명확하게 변경됨으로써 이전 C 스타일 enum에 비해 사용자가 실수할 여지를 많이 줄여주었다.




댓글