태터데스크 관리자

도움말
닫기
적용하기   첫페이지 만들기

태터데스크 메시지

저장하였습니다.

* 최근에 C++로 코딩하면서 옛날에 머물러있었던 C++ 개발 실력이었기 때문에 새로 보는 내용들이 아주 많다. 지금은 그냥 여기서 그렇게 하고 있으니까 따라한다는 마음이 크지만, 조금씩은 왜 그렇게 하고 있는지 알아가면서 C++ 관련 글도 정리하면서 쓰려고 한다. 기존에 보지 못했던 키워드 중 가장 먼저 눈에 들어온 것은 enum class 였다.


* enum class


C++11에서는 기존의 enum과 다른 새로운 키워드 조합인 enum class를 선호이고 있다. 사용법은 기존의 enum에서 크게 벗어나지는 않으나 가장 다른 점은 개발자들이 기존의 enum이 가지고 있었다고 주장하는 문제점들을 해결하고자 하였다. 그 중 가장 대표적인 것은 바로 기존의 C++의 enum은 내부적으로 int와 동일하게 사용되고, 바로 int형 변수와 비교도 하고 서로 다른 enum 끼리도 비교가 가능했다. 하지만 개발자들은 이러한 경우는 맞지 않다고 생각하고 더 제약적인 enum을 만들어낸 것이 바로 enum class이다. 따라서 가장 큰 차이점은 바로 이제 enum class는 형 변환이 기존보다 제약적이 되어 개발자의 실수로 발생할 버그를 방지하고자 하는 점과 기존의 enum이 가지고 있던 스코프 문제를 해결하고자 한 것이다.


* 기존의 스코프 문제 해결: 스코프를 생성하는 enum class

이렇게 형의 제약이 크다고 하는 것은 기존의 enum은 정의하면 해당 스코프에 각 enum 값들이 정의되었지만, 이제는 각 enum형의 새로운 스코프 하위에 위치하게 되었다. 아래가 간단한 예이다.

// 컴파일 오류 발생!
enum Color {
    RED,
    GREEN,
    BLUE
};
enum TrafficLight {
    GREEN, // 오류
    YELLOW,
    RED  // 오류
};

위의 예를 보면 각 enum형 Color와 TrafficLight는 GREEN와 RED가 동일하게 정의 되어있기 때문에 컴파일 오류가 일어난다. 기존의 enum은 현재의 스코프에 해당 값들을 정의하기 때문에 문제가 발생하는 것이다. 이러한 enum들을 각각 enum class로 바꾸게 되면 문제는 해결된다.

// 컴파일 오류 해결 enum class Color { RED, GREEN, BLUE }; enum class TrafficLight { GREEN, YELLOW, RED };

단순히 이렇게만 한다고 해서 해결이 된 것이 아니라, enum class는 새로운 scope 안에 각각의 값들을 넣는 것이다. 따라서, 기존의 enum은 현재 스코프에 상수/변수가 정의된 것처럼 enum의 값들을 사용했지만, enum class는 반드시 스코프를 명시해줘야 한다. 아래가 그 차이를 나타낸다.

enum Color {
    RED,
    GREEN,
    BLUE
};
enum class TrafficLight {
    GREEN,
    YELLOW,
    RED
};
Color background = RED; // 정상
Color foreground = Color::BLUE; //C++98 오류, C++11 정상
Color fontColor = TrafficLight::RED; // 오류

TrafficLight stop = RED; // 오류
TrafficLight go = TrafficLight:GREEN; // 정상

위와 같이 정상 케이스와 오류 케이스를 비교해보면 일반 enum은 현재의 스코프에 값이 정의되고, 별도로 스코프를 명시해도 정상동작한다. 하지만 enum class는 스코프를 명시하지 않으면 오류가 일어나므로 반드시 스코프를 명시한 다음 값을 대입해야 한다.


* Type safe enum class

또 다른 차이점은 바로 int 등의 값으로 변환하는 부분을 보면 알 수 있다. 기존의 enum은 int로 상호 변환이 내부적으로 자동 변환이 되었다면, enum class는 내부적으로 자동 변환하지 않고 오류를 발생시킨다. 이러한 부분은 원래 enum의 용도가 int를 사용하기 위함이 아니라 목록의 항목들을 표기하기 위함이기 때문에 조금 더 제약적인 문법을 추가하게 된 것이다. 위의 예에 이어서 보면 아래와 같다.

int rgb = RED; // 정상, 자동 변환 허용
int traffic = TrafficLight::RED; // 오류, 자동 변환 허용 안 함
int yield = static_cast<int>(TrafficLight::Yellow); //정상

어떻게 보면 int로 자동으로 변환되는 것이 좋을수도 있지만, 다른 프로그래밍 언어들의 enum이 동작하는 방식과 비교해서 더 이해하기 쉽고 공통적으로 수행하도록 하기 위해서 enum class는 명시적으로 형변환을 해줘야 한다. 이렇게 C언어가 새로운 표준으로 인하여 프로그래밍언어 자체에 대한 난이도를 낮추고 다른 언어들과 맞추어 가려고 하는 것이 돋보인다.


위와 같이 int로 자동으로 변경이 안된다면 다른 것보다도 불편한 점(?)이라면 바로 옵션 등과 같은 flag로서 enum을 사용하고자 한다면 명시적인 변환을 해야 하는 불편함이 있지만, 기존에 int로 사용하고자 하는 경우가 아닐 때 발생할 수 있는 오류를 방지하고자 컴파일 오류를 발생 시키는 것이다. 


* 선언 후 정의 기능 허용

기존의 enum과 또 다른 점이라면 특정 함수에 등에서 enum class를 사용하기 위해서는 해당 함수 위에 모든 값을 정의할 필요없이 선언 후 아래에서 별도로 정의하면 된다.

enum class Color; //선언
class FontStyle {
    Color getColor();
};


enum class Color { //정의
    RED,
    GREEN,
    BLUE
};

이렇게 선언이 별도로 가능하게 됨으로써 enum class를 정의할 때 헤더와 CPP 파일로 분리하는 등의 관리가 가능하다.


* 크기 정의 및 기본 크기 할당

기존의 enum은 struct의 멤버로 설정하게 되면 컴파일하는 환경마다 struct의 실제크기는 달라질 수 있다. 그렇기 때문에 enum class에서는 기본적으로 int의 크기를 가지도록 정의하고 이를 명시적으로 정의할 수 있다. 이는 enum 키워드에도 같이 적용되어 실제 크기를 정의할 수 있게 되었다.

enum class Color : char {
    RED,
    GREEN,
    BLUE
}

위와 같이 정의하면 각 enum의 크기는 char 크기가 되어 struct 등의 멤버로 활용되도 개발자가 임의로 설정하여 크기를 정의할 수 있다.


정리

enum class는 필수적으로 사용해야 되는 것은 아니지만 C++이 내재적으로 가지고 있었던 개발자의 실수로 인하여 발생하는 버그를 방지하기 위하여 나왔으며 사용할 수 있을 때에는 사용하는 것이 좋다.




추가로 읽을 거리

http://www.cprogramming.com/c++11/c++11-nullptr-strongly-typed-enum-class.html

http://blog.smartbear.com/c-plus-plus/closer-to-perfection-get-to-know-c11-scoped-and-based-enum-types/

http://stackoverflow.com/questions/6936030/do-we-really-need-enum-class-in-c11

http://stackoverflow.com/questions/18335861/why-is-enum-class-preferred-over-plain-enum

http://www.ibm.com/developerworks/rational/library/scoped-enums/index.html

http://stackoverflow.com/questions/12581064/enum-vs-strongly-typed-enum

http://en.cppreference.com/w/cpp/language/enum


저작자 표시 비영리 동일 조건 변경 허락
신고

이 글을 공유하세요.

Tag , ,
질문이나 의견을 댓글로 달아 주세요

티스토리 툴바