• 4.7.1 열거형 구현 방식 안 좋은 예
  • 4.7.2 Enumerated Types
  • 4.7.3 열거형 타입 사용 시 주의사항

 


4.7.1 열거형 구현 방식 안 좋은 예

 

어떤 특성에 대해 여러 종류로 분류하는 경우가 굉장히 많다. 실무에서도 입자의 성분을 분류하거나 계산 축을 설정하기 위해 정수형으로 나열해서 쓰곤 했다. 그냥 하드코딩으로 된 것도 있으며, 매크로를 사용하는 경우도 많았다. 아래의 예시를 보자.

int computeDamage(int weapon_id)
{
	if (weapon_id == 0) // sword
	{
		return 1;
	}

	if (weapon_id == 1) // hammer
	{
		return 2;
	}

	// ... 이런식으로 구현하면 힘들어진다.
}

무기별로 데미지를 다르게 해서 구현을 하려 했다. 0을 sword로 생각하고 구현했으며, 주석을 달아서 나름 친절하게 구현을 했다고 볼 수 있겠다. 하지만 무기 특성을 데미지 계산뿐만 아니라 다른 곳에서도 쓴다면 계속 위처럼 조건문을 작성해야 하는데 모든 곳에 주석을 달기엔 비효율적이다.


4.7.2 Enumerated Types

 

위와 같은 고민을 해결해줄 수 있는 것이 열거형 타입인 enum이 되겠다. 바로 적용된 버전의 코드를 보자.

enum Weapon
{
	WEAPON_SWORD,
	WEAPON_HAMMER,	// 마지막 쉼표 있어도 된다.
};

int computeDamage(int weapon_id)
{
	if (weapon_id == WEAPON_SWORD)
	{
		return 1;
	}

	if (weapon_id == WEAPON_HAMMER)
	{
		return 2;
	}

	// ...
}

아까보다 주석이 줄었으며, 가독성도 좋아졌다. enum의 경우 직접 수치를 입력하지 않을 경우 0부터 1씩 커지는 숫자가 enum 안에 들어간다. 여기서 WEAPON_SWORD가 0이고 다음이 1이 들어가 있다. enum은 헤더에 넣어두고 include하는 방식으로 사용하며, enum 마지막엔 ;으로 끝맺음을 해줘야 한다.

 

열거형 타입을 반드시 0부터 시작되게 사용하지 않아도 된다. 프로그래머가 값을 입력하면 그 값을 입력한 다음 항목에 대해서는 1씩 증가하게 구현이 된다.

#include <iostream>
#include <typeinfo>

enum Color
{
	COLOR_BLACK = -3,
	COLOR_RED,
	COLOR_BLUE = 5,
	COLOR_GREEN,
	COLOR_SKYBLUE,
};

int main()
{
	using namespace std;

	// 초기화 방식은 다른 타입들과 같다.
	Color paint = COLOR_BLACK;
	Color house(COLOR_BLUE);
	Color apple{ COLOR_RED };

	Color my_color = COLOR_BLACK;

	cout << my_color << " " << COLOR_BLACK << endl;

	return 0;

위의 예시는 순서대로 -3, -2, 5, 6, 7이 할당된다. 이처럼 사용자가 할당할 수는 있지만 권장하지 않는 방식이다.


4.7.3 열거형 타입 사용 시 주의사항

 

하나의 enum에 같은 수를 배정할 수 있지만 의도와는 다르게 작동할 수 있다. 아래의 예시를 수행해보면 조건문이 참으로 되고 두 개가 다른 항목이지만 같다고 판단하는 꼴이 된다.

#include <iostream>

enum Color
{
	COLOR_BLACK,
	COLOR_RED,
	COLOR_BLUE = 5,
	COLOR_GREEN = 5,
	COLOR_SKYBLUE,
};

int main()
{
	using namespace std;

	if (COLOR_BLUE == COLOR_GREEN)
		cout << "equal" << endl;

	return 0;
}

 

다른 enum일지라도 같은 이름을 가지면 안된다. 아래 예시처럼 int 자료형에도 저장이 가능하기 때문에 같은 이름인 BLUE를 저장할 경우 C2365 에러가 생긴다. 만약 같은 이름을 다른 열거형에서 사용하고싶다면 C++11부터 생긴 enum class를 활용하자.

#include <iostream>

enum Color
{
	COLOR_BLACK,
	COLOR_RED,
	COLOR_BLUE,
	COLOR_GREEN,
	COLOR_SKYBLUE,
	BLUE
};
enum Feeling
{
	HAPPY,
	JOY,
	TIRED,
	BLUE,
};

int main()
{
	using namespace std;

	int color_id = BLUE;

	cout << color_id << endl;

	return 0;
}

BLUE가 중복되었다.

 

위에서처럼 int 자료형에 enum을 넣는 것은 가능하지만 반대는 안된다. 아래 주석 처리된 부분은 바로 에러가 뜬다. static_cast를 사용하면 넣을 수 있겠지만 애초에 숫자로 넣는 모호한 방식을 사용하지 않기 위해 사용된 것이 열거형이므로 이런 식으로 사용하는 경우는 없을 것으로 생각된다.

enum Color
{
	COLOR_BLACK,
	COLOR_RED,
	COLOR_BLUE,
	COLOR_GREEN,
	COLOR_SKYBLUE,
};

int main()
{
	using namespace std;

	int color_id = COLOR_BLUE;
	cout << color_id << endl;

	// 그냥 넣는건 안된다. 애초에 안그러기 위해 만들어진게 enum
	//Color test = color_id;
	//Color test = 3;

	Color my_color = static_cast<Color>(3);

	return 0;
}

 

cin으로 바로 enum 자료형에 값을 넣는 것은 안된다. 입력 받으려면 우회해야 한다. 입력을 정수로 받고 해당 정수와 enum의 숫자를 일치하는지 조건을 체크하여 구현하는 방법이 최선일 것이다.

#include <iostream>
#include <typeinfo>

enum Color // user-defined data types
{
	COLOR_BLACK,
	COLOR_RED,
	COLOR_BLUE,
	COLOR_GREEN,
	COLOR_SKYBLUE,
};

int main()
{
	using namespace std;

	Color my_color = static_cast<Color>(3);

	//cin >> my_color;

	// 우회하는 방법
	int in_number;
	cin >> in_number;

	if (in_number == 0) my_color = COLOR_BLACK;
	// ...

	return 0;
}

+ Recent posts