개발단에 가입하여 베르의 게임 개발 유튜브를 후원해주세요! 

 

베르의 게임 개발 유튜브

안녕하세요! 여러분들과 함께 게임 개발을 공부하는 베르입니다! 게임 개발에 도움이 되는 강좌들을 올리는 채널입니다! [투네이션 후원] https://toon.at/donate/637735212761460238 [유니티 어필리에이트

www.youtube.com

 

안녕하세요! 여러분들과 함께 게임 개발을 공부하는 베르입니다!

이번에는 C#의 enum에 대해서 알아봅시다.

 

타임라인

0:00 인트로

0:40 enum을 사용하지 않을 때

1:55 열거형 enum

3:30 아웃트로

 

[참고자료]

마이크로소프트 C# 공식 도큐먼트 - https://docs.microsoft.com/ko-kr/dotnet/csharp/language-reference/builtin-types/enum

예제로 배우는 C# 프로그래밍 - https://www.csharpstudy.com/CSharp/CSharp-enum.aspx

 

[예제]

https://drive.google.com/file/d/1E1MBAEJVS3iQ8u8OMT-_Z3BZv2SZ9j5E/view?usp=sharing

 

스크립트

인트로

안녕하세요. 여러분들과 함께 게임 개발을 공부하는 베르입니다.

이번에는 C#의 enum에 대해서 알아보도록 하겠습니다.

보통 인간은 문자와 기호 그리고 숫자를 이용하지만 컴퓨터는 모든 것을 0과 1로 된 숫자로 받아들입니다.

그렇기 때문에 인간이 알아보기 쉽게 문자열로 만들면 프로그램이 느려지고 컴퓨터가 알아보기 쉽게 숫자로 만들면 인간이 알아보기 어려워집니다.

이것을 해결하기 위한 방법의 하나가 바로 enum, 즉 열거형입니다.

열거형에 대해서 알아보기 위해서 먼저 비주얼 스튜디오를 실행하고 빈 C# 프로젝트를 생성해줍니다.

enum을 사용하지 않을 때

먼저 enum을 사용하지 않고 프로그램을 만들 때는 어떻게 되는지 알아봅시다.

프로그램은 아주 간단한 형태라고 해도 여러 가지의 상태나 타입을 가지게 되는 경우가 많습니다.

지금은 간단한 예시로 두 개의 숫자와 계산 타입을 받아서 결과 값을 돌려주는 함수를 만들어보겠습니다.

물론 실제 프로그래밍에서는 이렇게 Calculate 함수 하나만 만들고 타입에 따라서 계산 결과를 돌려주는 것보다는 각 계산 방식에 따라서 함수를 따로 만드는 방식을 채택하겠지만 지금은 예시를 보여드리기 위함이니 이렇게 만들도록 하겠습니다.

먼저 계산 타입을 int 형으로 받는 방식은 이렇게 구현됩니다.

이런 int 타입으로 구현 된 방식의 경우에는 각 숫자가 어떤 계산 타입을 말하는 것인지 알기 어려운 문제가 있음을 한 눈에 알 수 있습니다.

그래서 어떤 숫자가 어떤 계산 방식을 뜻하는지 함수 사용자에게 알리기 위해서는 많은 양의 주석을 달 수 밖에 없습니다.

그 다음 방법은 타입을 문자열로 받는 방식입니다.

이렇게 문자열로 타입을 받게 되면 사람이 코드를 읽기는 쉬워지지만, int 타입과 마찬가지로 어떤 문자열이 어떤 타입을 나타내는지 추가로 주석을 달아서 알려줘야 하며, 더 큰 문제는 타입을 입력할 때 오타가 발생할 수 있다는 점입니다.

열거형 enum

이렇게 타입이나 상태를 정의할 때 int나 string을 사용하면 발생하는 문제들을 살펴보았습니다.

이번에는 이 영상의 주제인 enum으로 계산 타입을 만들어보겠습니다.

enum을 만들 때는 이렇게 해당 열거형의 이름을 적고 중괄호 안에 각 타입의 이름을 적어주면 됩니다.

이 때 이름은 문자열로 적듯이 원하는 이름을 자유롭게 적어주면 됩니다.

그리고 이렇게 선언된 열거형 키워드들은 각각 하나의 정수에 대응되는데 추가로 값을 대응시켜주지 않으면 배열처럼 0부터 차례대로 숫자가 매겨집니다.

이렇게 각 키워드마다 배열처럼 숫자가 매겨지는 점을 이용해서 enum을 int 타입으로 바꿔서 배열에 접근하는 방식으로 사용할 수 있습니다.

물론 반대로 int 타입을 enum 형식으로 바꿀 수도 있습니다.

그리고 키워드들이 다른 값을 가지기를 원하면 이런 식으로 대입시켜주면 되고 대입해준 키워드부터는 대입해준 값을 기반으로 숫자가 올라갑니다.

추가로 이렇게 키워드에 값을 대입해주는 방식을 이용하면 서로 다른 키워드가 같은 값을 가지게 만들 수도 있습니다.

이렇게 만든 enum 타입으로 다시 Calculate 함수를 만들어보면 이런 방식으로 구현됩니다.

앞에서 int나 string으로 만든 함수와 별 차이는 없어보이지만, 실제로 사용했을 때는 별도의 주석이나 설명없이도 어떤 계산 타입이 존재하며 어떤 값을 넣어줘야 하는지 명확하게 알 수 있습니다.

이런 방식 외에도 아래의 참고자료 링크를 보시면 Flags 어트리뷰트를 이용해 비트 연산을 하는 응용법도 있습니다.

비트연산과 관련된 내용은 지금 영상 오른쪽 상단에 표시되는 영상 링크를 통해서 보실 수 있습니다.

아웃트로

이번 영상에서는 C#의 enum에 대해서 알아보았습니다.

이 강좌는 시청자 여러분들의 시청과 후원으로 제작되었습니다.

이상 베르의 게임 개발 유튜브였습니다. 감사합니다.

 

[유니티 어필리에이트 프로그램]

아래의 링크를 통해 에셋을 구매하시거나 유니티를 구독하시면 수익의 일부가 베르에게 수수료로 지급되어 채널의 운영에 도움이 됩니다.

 

에셋스토어

여러분의 작업에 필요한 베스트 에셋을 찾아보세요. 유니티 에셋스토어가 2D, 3D 모델, SDK, 템플릿, 툴 등 여러분의 콘텐츠 제작에 날개를 달아줄 다양한 에셋을 제공합니다.

assetstore.unity.com

 

Easy 2D, 3D, VR, & AR software for cross-platform development of games and mobile apps. - Unity Store

Have a 2D, 3D, VR, or AR project that needs cross-platform functionality? We can help. Take a look at the easy-to-use Unity Plus real-time dev platform!

store.unity.com

 

Create 2D & 3D Experiences With Unity's Game Engine | Unity Pro - Unity Store

Unity Pro software is a real-time 3D platform for teams who want to design cross-platform, 2D, 3D, VR, AR & mobile experiences with a full suite of advanced tools.

store.unity.com

[투네이션]

 

-

 

toon.at

[Patreon]

 

WER's GAME DEVELOP CHANNEL님이 Game making class videos 창작 중 | Patreon

WER's GAME DEVELOP CHANNEL의 후원자가 되어보세요. 아티스트와 크리에이터를 위한 세계 최대의 멤버십 플랫폼에서 멤버십 전용 콘텐츠와 체험을 즐길 수 있습니다.

www.patreon.com

[디스코드 채널]

 

Join the 베르의 게임 개발 채널 Discord Server!

Check out the 베르의 게임 개발 채널 community on Discord - hang out with 399 other members and enjoy free voice and text chat.

discord.com

 

반응형

C++ / UENUM 사용자정의 열거형 만들기

 

작성 기준 버전 :: 4.21.1

 

C++ enum class 문서에서 확인할 수 있듯이, 열거형은 정수형 상수를 사람이 알아보기 쉽게 만들어준다. 이러한 열거형도 언리얼 구조체에서의 문제와 같이 표준 열거형은 코드 내부에서만 사용이 가능하고, 언리얼 에디터의 디테일 패널이나, 블루프린트에서 사용이 불가능하다는 문제가 있다.

 

이 열거형 역시 언리얼 구조체와 마찬가지로 언리얼 에디터에서 사용하고자 한다면 언리얼 열거형으로 만들어야만 한다.

 

언리얼 열거형 만들기

 

언리얼 전용의 열거형을 만드는 방법은 다음과 같다. 예시 코드와 같이 새로 만드는 열거형 앞에 UENUM() 매크로를 붙여주면 언리얼 에디터에서도 사용 가능한 언리얼 열거형이 만들어진다.

 

// Fill out your copyright notice in the Description page of Project Settings.

#pragma once

#include "CoreMinimal.h"
#include "GameFramework/Actor.h"
#include "EnumTestActor.generated.h"

UENUM(BlueprintType)
enum class ETestEnum : uint8
{
    TE_OptionA UMETA(DisplayName = "Option A"),
    TE_OptionB UMETA(DisplayName = "Option B"),
};

UCLASS()
class ENUMTEST_API AEnumTestActor : public AActor
{
    GENERATED_BODY()
   
public:   
    // Sets default values for this actor's properties
    AEnumTestActor();

protected:
    // Called when the game starts or when spawned
    virtual void BeginPlay() override;

public:   
    // Called every frame
    virtual void Tick(float DeltaTime) override;

    UPROPERTY(EditAnywhere)
    ETestEnum TestEnum;
};

 

단, 여기서 주의해야할 점이 있는데, 언리얼 열거형을 만들때 반드시 일반적인 enum이 아닌 enum class로 만들어야 한다는 점이다. 만약 enum class로 만들지 않고 일반적인 enum으로 만들어서 UENUM() 매크로를 붙이고 컴파일을 하면 에러가 발생해서 컴파일에 실패한다. 그리고 UENUM은 uint8만을 지원하기 때문에 이 부분도 빠뜨리지 않고 넣어주어야 한다.

 

코드를 작성하고 컴파일한 후 레벨에 EnumTestActor를 배치하고 디테일 패널을 살펴보면 추가한 열거형이 보이는 것을 확인할 수 있다.

 

 

UENUM을 "BlueprintType"으로 선언하면 블루프린트에서도 사용할 수 있게 된다.

 

 

만약 새롭게 정의한 UENUM이 한 클래스에서 사용되는 것이 아니라 다른 코드 전반에서 사용되기를 원한다면, 언리얼 구조체 문서에서 설명한 것과 같이 열거형을 정의하기 위한 빈 클래스를 하나 추가해서 그 헤더에 UENUM을 선언하고 사용하고자 하는 곳에 그 헤더를 포함시키는 방법을 쓸 수 있다.

 

[투네이션]

 

-

 

toon.at

[Patreon]

 

WER's GAME DEVELOP CHANNEL님이 Game making class videos 창작 중 | Patreon

WER's GAME DEVELOP CHANNEL의 후원자가 되어보세요. 아티스트와 크리에이터를 위한 세계 최대의 멤버십 플랫폼에서 멤버십 전용 콘텐츠와 체험을 즐길 수 있습니다.

www.patreon.com

[디스코드 채널]

 

Join the 베르의 게임 개발 채널 Discord Server!

Check out the 베르의 게임 개발 채널 community on Discord - hang out with 399 other members and enjoy free voice and text chat.

discord.com

 

 

반응형

Inspector 뷰에서 공개된 enum의 값을 여러 개 선택 가능하게 하기

 

게임이나 프로그램을 제작할 때, 유닛이나 캐릭터, 객체의 상태를 표현하기 위한 방법 중 하나로 enum을 많이 사용한다. 정수나 문자열을 이용해서도 객체의 상태를 나타낼 수 있지만, 정수의 경우는 이 상태가 어떤 상태인지 직관적으로 알아보기 어려운 문제가 있고, 문자열의 경우에는 어떤 상태인지 알아보기 쉽지만, 정수형에 비해서 비교 연산 속도가 느리고, 비교하는 부분에서 오타가 발생할 경우 찾기 어려운 버그를 발생시킬 수도 있다.

 

public class Character : MonoBehaviour
{
    int state;
    // 주석이 없으면 캐릭터가 어떤 상태인지 알기 어렵다.
    public void CheckState()
    {
        switch (state)
        {
            case 0: // Jump
                break;

            case 1: // Attack
                break;

            case 2: // Move
                break;

            default:
                break;
        }
    }
}

비직관적인 정수형 상태 표현

 

public class Character : MonoBehaviour
{
    string state;

    // 정수형보다 비교가 느릴 수 밖에 없다.
    public void CheckState()
    {
        switch (state)
        {
            case "Jump": // Jump
                break;

            case "Attcak": // Attack 오타가 발생하면 버그가 발생하고 찾기 어려울 수 있다.
                break;

            case "Move": // Move
                break;

            default:
                break;
        }
    }
}

보기는 편하지만 느리고 오타에 의한 버그 발생 가능성이 높은 문자열 상태 표현

 

 

 

 

 

그에 비해서 enum 타입의 변수를 이용하면 정수를 사용한 것과 같은 비교 연산 속도와 문자열을 사용한 것과 같은 직관성을 가질 수 있다. 오타가 발생하면 그 즉시 신텍스 에러가 뜨는 것은 덤이다.

 

public enum ECharacterState
{
    Jump,
    Attack,
    Move,
}

public class Character : MonoBehaviour
{
    public ECharacterState state;
    // 알아보기 쉬우며 오타가 발생할 가능성을 차단해준다.
    public void CheckState()
    {
        switch (state)
        {
            case ECharacterState.Jump: // Jump
                break;

            case ECharacterState.Attack: // Attack
                break;

            case ECharacterState.Move: // Move
                break;

            default:
                break;
        }
    }
}

 

객체의 상태를 표시하는데 enum 타입을 사용하면 이렇게 여러가지 이점이 있다. 그리고 이런 enum 타입의 변수는 public이나 [SerializeField]로 설정하면 유니티 에디터의 Inspector 뷰에서 볼 수 있게 된다.

 

 

일반적인 경우라면 이것으로 충분하겠지만, 캐릭터의 상태의 경우에는 기획에 따라 다르겠지만, 여러 가지의 상태가 중첩되는 경우도 있을 수 있다. 예를 들자면, 점프하면서 공격한다는 상태도 있을 수 있고 점프하면서 이동한다는 상태도 있을 수 있다. 그 외의 경우 역시 가능하다. 중첩된 상태를 표현하기 위해서는 각 비트에 상태를 매핑해서 비트 연산을 하는 방법을 주로 사용한다. 즉, 각 상태의 값을 2의 n승으로 하여 해당 비트의 값이 1이면 그 캐릭터는 해당 상태인 것이다.

 

public enum ECharacterState
{
    Jump    = 0x00000001,   // 0001
    Attack  = 0x00000002,   // 0010
    Move    = 0x00000004,   // 0100
}

public class Character : MonoBehaviour
{
    public ECharacterState state;

    private void Start()
    {

        // or 연산을 통해 캐릭터의 state는 이동 중이면서 점프 중인 상태가 된다.

        state = ECharacterState.Move | ECharacterState.Jump;
    }

    public void CheckState()
    {

        // State에 Attack 상태를 and 연산하면 Attack 상태에 속하는 비트의 값만 검출할 수 있다.

        if ((state & ECharacterState.Attack) == ECharacterState.Attack)
        {
            // Attack 상태 처리
        }

        if ((state & ECharacterState.Jump) == ECharacterState.Jump)
        {
            // Jump 상태 처리
        }

        if ((state & ECharacterState.Move) == ECharacterState.Move)
        {
            // Move 상태 처리
        }
    }
}

 

 

 

 

이렇게 중첩이 가능한 상태의 경우에는 여러 개의 상태를 동시에 선택할 수 있어야 하는데 public이나 [SerializeField]로 공개된 enum 타입의 변수의 경우에 유니티 에디터에서 기본적으로는 하나의 값만을 선택할 수 있게 되어있다. 이런 기본적인 상태에서 중첩된 상태를 한 번에 선택하기 위해서는 단순한 방법으로는 중첩상태의 열거형을 일일이 만들어 주는 것이 있다.

 

public enum ECharacterState
{
    Jump                  = 0x00000001,   // 0001
    JumpAndAttack   = 0x00000003,   // 0011
    Attack                = 0x00000002,   // 0010
    AttackAndJump   = 0x00000006,   // 0110
    Move                  = 0x00000004,   // 0100
    MoveAndJump     = 0x00000005,   // 0101
}

 

 

이렇게 중첩된 상태를 일일이 열거형에 추가해서 선택가능하게 만드는 방법이 있지만, 이것은 상태가 지금처럼 3가지 밖에 없는 간단한 상황에서만 가능한 방법일 것이다. 상태가 한 가지 한 가지 추가될 때마다 추가해야되는 중간 값이 엄청나게 많아져서 결국에는 드롭다운의 길이가 끝없이 늘어나는 것이 뻔히 예측될 것이다. 그리고 그렇게 중첩된 상태에 대한 상태가 늘어나면 어떤 상태를 넣었는지 확인하기 힘들어져서 이상하게 입력하게 될 수도 있다. 바로 위의 예시에서 보듯이 Jump And Attack과 Attack And Jump를 넣어버리게 되는 것처럼 말이다.(그리고 Attack And Jump의 값은 또 Attack And Move의 값이 입력되었다.)

 

이런 상황을 막기 위해서는 Inspector에서 enum 타입의 드롭다운에서 여러 개의 값을 선택 가능하게 만들어줘야 한다. 이런 방식의 예시로는 Inspector 뷰에 공개된 Light 컴포넌트의 Culling Mask 변수가 있다.

 

Light 컴포넌트의 Culling Mask는 빛을 받을 레이어를 골라서 선택할 수 있게 해준다.

 

 

 

 

위의 Culling Mask처럼 Inspector 뷰에서 원하는 상태를 여러 가지를 동시에 선택할 수 있다면 열거형에 끝없이 중첩된 상태를 추가할 필요는 없어질 것이다. 이러한 기능을 넣기 위해서는 에디터 기능을 약간 수정할 필요가 있다. 다음과 같이 EnumFlagsAttributeDrawer.cs와 EnumFlagsAttribute.cs 코드를 추가해보자. EnumFlagsAttributeDrawer의 경우, 에디터의 기능을 수정하는 코드기 때문에 Editor 폴더에 넣어주어야 한다.

 

 

using UnityEngine;
using UnityEditor;

[CustomPropertyDrawer(typeof(EnumFlagsAttribute))]
public class EnumFlagsAttributeDrawer : PropertyDrawer
{
    public override void OnGUI(Rect _position, SerializedProperty _property, GUIContent _label)
    {
        _property.intValue = EditorGUI.MaskField(_position, _label, _property.intValue, _property.enumNames);
    }
}

EnumFlagsAttributeDrawer.cs

 

using UnityEngine;

public class EnumFlagsAttribute : PropertyAttribute
{
    public EnumFlagsAttribute() { }
}

EnumFlagsAttribute.cs

 

public class Character : MonoBehaviour
{
    [EnumFlags]
    public ECharacterState state;
}

 

 

 

 

 

그리고 난 이후에 Inspector 뷰에서 여러 개의 값을 선택하고자 하는 enum 타입의 변수의 경우에 새롭게 추가해준 [EnumFlags] 어트리뷰트를 추가해주면아래의 이미지와 같이 우리가 추가한 enum 타입의 변수 역시 여러 개의 값을 선택할 수 있게 된다.

 

 

이렇게 여러 개의 값을 선택할 수 있게 사용하는 경우 Nothing은 0이고 Everything은 -1이다. 열거형에 값을 추가할 때는 각 열거형이 2의 n승이 되게 값을 정해줘야만 한다. 중간에 그 외의 값이 있으면 Inspector 뷰에서 선택한 값과 스크립트 상에서의 값이 일치하지 않는 버그가 발생할 수 있다.

 

public enum ECharacterState
{
    Jump    = 0x00000001,   // 0001
    Attack  = 0x00000002,   // 0010
    Move    = 0x00000004,   // 0100
}

EnumFlags를 사용해서 여러 값을 선택할 수 있게 하려면 중첩 상태를 제외하고 기본 상태만 2의 n승 값을 가지게 정의해줘야 한다.

 

 


참고 :

 

Default Editor : Enum as flags ? - Unity Answers

 

answers.unity.com

 

 

[유니티 어필리에이트 프로그램]

아래의 링크를 통해 에셋을 구매하시거나 유니티를 구독하시면 수익의 일부가 베르에게 수수료로 지급되어 채널의 운영에 도움이 됩니다.

 

에셋스토어

여러분의 작업에 필요한 베스트 에셋을 찾아보세요. 유니티 에셋스토어가 2D, 3D 모델, SDK, 템플릿, 툴 등 여러분의 콘텐츠 제작에 날개를 달아줄 다양한 에셋을 제공합니다.

assetstore.unity.com

 

Easy 2D, 3D, VR, & AR software for cross-platform development of games and mobile apps. - Unity Store

Have a 2D, 3D, VR, or AR project that needs cross-platform functionality? We can help. Take a look at the easy-to-use Unity Plus real-time dev platform!

store.unity.com

 

Create 2D & 3D Experiences With Unity's Game Engine | Unity Pro - Unity Store

Unity Pro software is a real-time 3D platform for teams who want to design cross-platform, 2D, 3D, VR, AR & mobile experiences with a full suite of advanced tools.

store.unity.com

[투네이션]

 

-

 

toon.at

[Patreon]

 

WER's GAME DEVELOP CHANNEL님이 Game making class videos 창작 중 | Patreon

WER's GAME DEVELOP CHANNEL의 후원자가 되어보세요. 아티스트와 크리에이터를 위한 세계 최대의 멤버십 플랫폼에서 멤버십 전용 콘텐츠와 체험을 즐길 수 있습니다.

www.patreon.com

[디스코드 채널]

 

Join the 베르의 게임 개발 채널 Discord Server!

Check out the 베르의 게임 개발 채널 community on Discord - hang out with 399 other members and enjoy free voice and text chat.

discord.com

 

반응형

enum class

 

인간은 문자와 기호 그리고 숫자를 이용하고 컴퓨터는 모든 것을 숫자로 받아들인다. 그렇기 때문에 인간이 알아보기 쉽게 문자열로 만들면 프로그램이 느려지고 컴퓨터가 알아보기 쉽게 숫자로 만들면 인간이 알아보기가 어려워진다. 이것을 해결하기 위한 방법의 하나가 바로 enum(열거형)이다.

 

이 enum은 일반적으로 이름을 가지는 정수형의 상수를 정의해서 알아보기 쉽게 해주는데, 이 기존의 enum은 몇가지의 문제점이 존재한다.

 

 

1. 열거형에 존재하는 이름과 같은 이름의 클래스를 선언할 수 없다.

일반적인 enum 내에 선언된 열거자의 이름은 전역적이다. 그렇기 때문에 enum 내부에 선언된 이름과 같은 이름을 가진 클래스를 선언하고 사용하려고 하면 컴파일 에러가 발생한다. 다음의 코드는 이것에 대한 예시이다.

 

#include <iostream>
using namespace std;

enum EColor
{
    Red,
    Green,
    Blue,
};

class Red { };

int main()
{
    Red r;    // 컴파일 에러가 발생한다.
    EColor color = Red;

    return 0;
}

 

위와 같은 일이 발생하는 이유는 MSDN에 다음과 같이 설명되어 있다.

 

enum EColor
{
    Red,
    Green,
    Blue,
};

 

위와 같이 정의된 enum의 의미 체계는 다음과 같다고 한다.

 

static const int Red = 0;
static const int Green = 1;
static const int Blue = 2;

 

다시 말하자면 이미 전역 변수에 같은 이름의 변수가 선언되어 있기 때문에 같은 이름의 클래스를 선언할 수 없는 것이다. 하지만 enum class로 정의된 열거형의 경우에는 위와 같은 문제가 발생하지 않는다.

 

#include <iostream>
using namespace std;

enum class EColor
{
    Red,
    Green,
    Blue,
};

class Red { };

int main()
{
    Red r;    // 컴파일 에러가 발생하지 않는다.
    EColor color = EColor::Red;    // 대신 접근지정자를 이용해 스코프를 지정해주어야 한다.

    return 0;
}

 

열거형을 표준 열거형이 아닌 enum class로 선언하면 열거형 내부에 존재하는 이름으로 클래스를 선언해도 문제가 발생하지 않는다. 하지만 표준 열거형에서는 Red라는 이름만으로 열거형 변수에 값을 넣어줄 수 있었지만 enum class 열거형에서는 열거형 변수에 값을 넣어주기 위해서는 반드시 접근지정자를 이용해서 스코프를 지정해주어야만 컴파일 에러 없이 값을 대입할 수 있게 된다. 이러한 형태의 이유 역시 MSDN에 설명되어 있는데 그것을 보면 왜 이런 형태를 가지는지 충분히 이해할 수 있게 된다.

 

enum class EColor
{
    Red,
    Green,
    Blue,
};

 

enum class로 선언된 EColor의 경우에는 다음과 같은 의미 체계를 가지게 된다.

 

class EColor
{
public:
    static const int Red = 0;
    static const int Green = 1;
    static const int Blue = 2;
};

 

위와 같은 형태를 가지게 된다는 것을 생각해보면 왜 enum class 열거형 변수에 스코프를 지정해 주어야하는지 명확하게 이해할 수 있다.

 

 

 

 

 

2. 표준 열거형은 타입 세이프(Type safe)하지 않다.

일반적으로 프로그래머들은 언어의 동작에서 프로그래머가 무의식적으로 실수를 유도하게 되는 동작을 좋아하지 않는다. 만약 프로그래머가 명시적으로 한 행동에서 문제가 발생하면 명백한 프로그래머의 실수이고 그 문제점을 찾아내기도 쉽지만, 프로그래머가 명시하지 않았는데 언어가 묵시적으로 처리해서 발생하는 문제는 찾아내기 어렵기 때문이다.

 

이러한 측면에서 표준 열거형이 발생시키는 문제가 몇 가지 있다.

 

첫 번째 문제로는 정수형의 변수에 곧바로 대입이 가능하다는 것이다(하지만 정수형에서 열거형으로의 대입은 명시적인 형 변환이 필요하다). 이것으로 인해서 발생하는 문제점에 대해서 경험이 많지 않아서 언급하지는 못하겠지만, 이런 묵시적인 동작으로 인해서 프로그래머가 실수를 할 가능성이 커지는 것은 부인할 수 없는 문제이다.

 

#include <iostream>
using namespace std;

enum EColor
{
    Red,
    Green,
    Blue,
};

int main()
{
    EColor color = Red;
    int i = color;    // 바로 대입이 가능하다.

    return 0;
}

 

하지만 열거형을 enum class로 선언할 경우, 다음과 같이 더 이상 명시적으로 형 변환을 거치지 않는 이상 열거형 변수나 값은 정수형에 대입할 수 없게 된다.

 

#include <iostream>
using namespace std;

enum class EColor
{
    Red,
    Green,
    Blue,
};

int main()
{
    EColor color = EColor::Red;
    int i = static_cast<int>(color);    // 명시적인 형 변환을 거쳐야만 대입이 가능하다.

    return 0;
}

 

두 번째 문제는 명시적인 형 변환 없이도 다른 열거형 간의 비교 연산이 가능하다는 것이다.

 

#include <iostream>
using namespace std;

enum EColor
{
    Red,
    Green,
    Blue,
};

enum EDirection
{
    Forward,
    Backward,
    Right,
    Left,
    Up,
    Down,
};

int main()
{
    EColor color = Red;
    EDirection dir = Up;
   
    if (color == dir)    // 문제없이 비교되고 컴파일 된다.
    {
        cout << "같다" << endl;
    }

    return 0;
}

 

이것이 무슨 문제가 되는지 이해하지 못할 수도 있겠지만, 위의 코드를 살펴보면 EColor 열거형과 EDirection 열거형의 종류와 내용, 그 의미는 명백하게 다르다. 이러한 상황을 프로그래머가 의도한 것이라면 모르겠지만, 이런 상황을 의도하지 않았고 실수로 전혀 다른 열거형을 비교하게 된 것이라면 문제가 될 것이고, 이러한 문제는 컴파일러가 프로그래머에게 알려주지 않기 때문에 찾아내기도 쉽지 않을 것이다.

 

하지만 열거형을 아래와 같이 enum class로 선언하면 명시적인 형 변환을 거치지 않는 이상 다른 열거형에 대한 비교 연산은 불가능해진다.

 

#include <iostream>
using namespace std;

enum class EColor
{
    Red,
    Green,
    Blue,
};

enum class EDirection
{
    Forward,
    Backward,
    Right,
    Left,
    Up,
    Down,
};

int main()
{
    EColor color = EColor::Red;
    EDirection dir = EDirection::Forward;
   
    if (color == (EColor)dir)    // 명시적으로 형 변환을 거친 후에야 비교 연산이 가능해진다.
    {
        cout << "같다" << endl;
    }

    return 0;
}

 

이러한 동작은 프로그래머의 무의식적인 실수로 인한 버그를 막아주는 것이고, 문제를 발생시킬 수 있는 동작의 경우에는 프로그래머가 의도적으로 코드를 작성해야 하고 그로인해 발생할 문제에 대한 대처와 책임을 충분히 해야한다는 것을 의미한다.

 

 

 

[유니티 어필리에이트 프로그램]

아래의 링크를 통해 에셋을 구매하시거나 유니티를 구독하시면 수익의 일부가 베르에게 수수료로 지급되어 채널의 운영에 도움이 됩니다.

 

에셋스토어

여러분의 작업에 필요한 베스트 에셋을 찾아보세요. 유니티 에셋스토어가 2D, 3D 모델, SDK, 템플릿, 툴 등 여러분의 콘텐츠 제작에 날개를 달아줄 다양한 에셋을 제공합니다.

assetstore.unity.com

 

Easy 2D, 3D, VR, & AR software for cross-platform development of games and mobile apps. - Unity Store

Have a 2D, 3D, VR, or AR project that needs cross-platform functionality? We can help. Take a look at the easy-to-use Unity Plus real-time dev platform!

store.unity.com

 

Create 2D & 3D Experiences With Unity's Game Engine | Unity Pro - Unity Store

Unity Pro software is a real-time 3D platform for teams who want to design cross-platform, 2D, 3D, VR, AR & mobile experiences with a full suite of advanced tools.

store.unity.com

[투네이션]

 

-

 

toon.at

[Patreon]

 

WER's GAME DEVELOP CHANNEL님이 Game making class videos 창작 중 | Patreon

WER's GAME DEVELOP CHANNEL의 후원자가 되어보세요. 아티스트와 크리에이터를 위한 세계 최대의 멤버십 플랫폼에서 멤버십 전용 콘텐츠와 체험을 즐길 수 있습니다.

www.patreon.com

[디스코드 채널]

 

Join the 베르의 게임 개발 채널 Discord Server!

Check out the 베르의 게임 개발 채널 community on Discord - hang out with 399 other members and enjoy free voice and text chat.

discord.com

 

반응형

'C++' 카테고리의 다른 글

[C++ 11] static_assert  (0) 2017.05.23
[C++ 11] Auto Vectorization  (1) 2016.11.01
[C++ 11] Range-Based For  (0) 2016.11.01
[C++ 11] Scoped Lock  (0) 2016.11.01

+ Recent posts