나만의 작은 도서관
[C++][Keyword] 열거형(enum, enum class) 본문
열거형이란?
열거형(Enumerations)은 열거자(enumerator)라 불리는 정수 상수 집합으로 구성된 사용자 정의 형식을 말한다.
enum 키워드
C언어에서 넘어온 열거형 키워드이다. 사용법은 아래와 같다.
enum [identifier] [: type] {enum-list}
// identifier: 열거형에 지정된 형식 이름 ⇒ 변수 이름
// type: 열거자(enumerator)의 타입. 모든 열거자는 해당 타입으로 표현된다. 모든 “정수” 계열 타입이 가능하다.
// enum-list: 열거자가 쉼표로 구분된 리스트. 범위에 있는 모든 열거자의 이름은 고유해야 하지만, 값은 중복될 수 있다.
// 지역 변수와 같이 선언된 범위 내에서만 살아있다.
// ex.
enum A : int {ZERO = 0, ONE = 1, TWO = 2} // 모든 옵션 추가
enum A : {ZERO = 0, ONE = 1, TWO = 2} // [: type] 옵션 생략
enum {ZERO = 0, ONE = 1, TWO = 2} // [identifier], [: type] 옵션 생략
// 열거자의 정수값 생략시 첫번째 열거자는 0, 다른 열거자는 이전 열거자에 1을 더한 값을 가진다.
enum {ZERO = 0, ONE, TWO} // enum {ZERO = 0, ONE = 1, TWO = 2}과 동일
고유한 스코프가 없다.
enum은 고유한 스코프가 없어 전역 네임스페이스에 값을 정의하므로, 이름까지 넣어서 열거자를 구분한다해도 실제로 구분되지 않는다. 따라서, 아래 코드와 같이 같은 범위 내에 다른 enum이 동일한 이름의 열거자를 사용했다면 오류가 발생한다.
#include <iostream>
using namespace std;
int main(void){
enum A {ZERO = 0, ONE = 1, TWO = 2};
enum B {ZERO = 0, ONE = 1, TWO = 2};
return 0;
}
// 실행 결과
// error: 'ZERO' conflicts with a previous declaration
// error: 'ONE' conflicts with a previous declaration
// error: 'TWO' conflicts with a previous declaration
암시적 변환의 자유로움
enum의 열거자는 int와 같은 정수형으로 암시적 변환이 가능하다.
#include <iostream>
using namespace std;
int main(void){
enum A {ZERO = 0, ONE = 1, TWO = 2};
cout << (int)ZERO << '\n'; // 0
return 0;
}
enum class의 등장
C++11부터 enum class가 추가되었다. 멀쩡한 enum이 있음에도 enum class가 나온 이유는 앞서 살펴본 1) 고유한 스코프가 없어 서로 다른 enum끼리 이름 충돌이 발생한다는 점, 2) 정수형 타입으로 암시적 변환이 허용되어 타입 안정성이 떨어진다는 점 떄문이다. 사용법은 아래와 같다.
enum [class | struct] [identifier] [: type] {enum-list}
// class: 선언에 사용하는 키워드이며, 열거형의 범위를 지정하기 위해 사용한다.
// struct를 대신 사용할 수 있다. (class와 struct는 의미가 같기 때문)
// identifier: 열거형에 지정된 형식 이름 ⇒ 변수 이름
// type: 열거자(enumerator)의 타입. 모든 열거자는 해당 타입으로 표현된다. 모든 “정수” 계열 타입이 가능하다.
// enum-list: 열거자가 쉼표로 구분된 리스트. 범위에 있는 모든 열거자의 이름은 고유해야 하지만, 값은 중복될 수 있다. enum의 범위는 주변 범위이며, enum class는 enum-list 자체가 범위가 된다. enum class는 목록이 비어 있을 수 있으며, 새 정수 형식을 정의한다.
// 고유한 범위를 가진다
// ex.
enum class B {ZERO = 0, ONE = 1, TWO = 2}; // 스코프가 있는 enum은 int가 기본 타입.
enum class C : short {ZERO = 0, ONE = 1, TWO = 2} // 타입을 지정한 enum
고유한 스코프를 반드시 지정해서 사용해야한다.
enum class는 enum과 달리 반드시 스코프를 지정해야 사용할 수 있다.
#include <iostream>
using namespace std;
int main(void){
enum class A {ZERO = 0, ONE = 1, TWO = 2};
enum class B {ZERO = 0, ONE = 1, TWO = 2};
A a = A::ZERO; // 스코프 지정 필요
return 0;
}
암시적 변환 불가능 -> 타입 안정성 강화
enum class는 암시적 변환이 불가능하다. 이로써 타입 안정성이 강화되었다!
#include <iostream>
using namespace std;
int main(void){
enum class A {ZERO = 0, ONE = 1, TWO = 2};
enum class B {ZERO = 0, ONE = 1, TWO = 2};
int num1 = A::ZERO; // Error: "A" 형식의 값을 사용하여 "int" 형식의 엔터티를 초기화할 수 없습니다.
int num2 = static_cast<int>(A::ZERO); // 명시적 캐스팅은 가능(C++ 스타일)
int num3 = (int)A::ZERO; // 명시적 캐스팅은 가능(C 스타일)
return 0;
}
참고자료
https://blockdmask.tistory.com/405
https://learn.microsoft.com/ko-kr/cpp/cpp/enumerations-cpp?view=msvc-170
'C++ > 문법 및 메소드(STL)' 카테고리의 다른 글
[C++] 레퍼런스(Reference) (0) | 2025.03.13 |
---|---|
[C++] 포인터(Pointer) (0) | 2025.03.13 |
[C++][Class] struct와 class의 차이 (0) | 2025.02.19 |
[C++][Keyword] 정적 변수(static 키워드) (0) | 2025.02.18 |
[C++][Keyword] 타입의 별칭: typedef, using 키워드 (0) | 2024.12.21 |