몇가지 고민이 있습니다.
제가 캐릭터라는 클래스를 생성했습니다.
그런데 캐릭터에는 MotionType라는 것으로 캐릭터의 상태를 지정할 수 있습니다.
이 MotionType을 캐릭터 클래스 내부에 넣어야 하는 것인지, 아니면 다음과 같이 class로 따로 빼줘야 하는지 모르겠습니다.
무엇이 좋을까요? 다들 어떻게 하시는지요?
1. 캐릭터 클래스 내부에 넣어준다.
class Charater
{
typedef enum
{
STANDING = 0,
RUNNING,
JUMPING,
DIED,
MAX_MOTION_TYPE
} MotionType;
}
}
이러면 처음에 작성할 때 편하긴 한데, class가 지저분 하지 않을까 고민을 하고요.
2. 따로 class로 빼준다음 사용한다.
class Charater
{
CharaterState::MotionType m_motionType;
}
class CharaterState
{
public:
typedef enum
{
// 캐릭터의 동작 종류 : 캐릭터 동작 로직이 아닌 순수 캐릭터 애니메이션만 담당한다.
// 주로 캐릭터의 현재 동작 상태를 표시하는데 쓰인다.
STANDING = 0,
RUNNING,
JUMPING,
DIED,
MAX_MOTION_TYPE
} MotionType;
}
이러면 Charater class가 깔금해서 좋긴한데, 캐릭터 내부에 종속되는 데이터를 따로 빼놔도 되는 건지 모르겠네요. 파일 양도 많아지고요.
다들 어떻게 해서 어떤 이점을 얻으셨는지 알려주시면 감사하겠습니다.
그렇군요. 별도의 클래스로 빼놓을 필요는 없는 거네요.
클래스 내부에 넣었다가 나중에 필요하면 빼야겠네요. 감사합니다.
위의 2번 예에서는 열거형의 인스턴스가 1개를 초과하게 되어 있습니다.
각각의 열거형 멤버는 상수나 마찮가지입니다. 열거형의 쓰임을 보면 각 멤버의 값이 중요한 것이지 instance의 주소가 중요한 것이 아니므로
열거형이 메모리상에서 사본을 갖도록 프로그래밍하는 것은 메모리의 낭비입니다.
그러므로 열거형은 C언어의 외부변수 영역(C++의 static memory)을 차지 하도록 하고 유일한 것이 좋습니다.
그리고 답변을 하자면 저는 빼냅니다.
클래스와 객체의 차이점 떄문에 static영역에 저장을 하라는 이야긴거 같네요.
클래스를 객체화 할떄마다 열거형 상수 영역도 각 객체마다 할당 되죠.
static 영역에 설정을 하면 각 객체마다 할당 되는게 아니고 static에 해당하는
영역에 할당되고 그 하나의 할당된 영역을 각각 객체가 사용을 하게 되던걸로 기억하네요.
예를들어 저 클래스를 객체화 시킨게 100번이면 2번째 예시대로 한다면 열거형 저장 크기 100배 의 메모리가
열거형을 저장하기위해서 사용되지만 static을 사용하면 한번의 메모리 사용만으로 100개의 객체에서 사용할수 있는거죠.
그럼 지금 Character란 클래스가 MotionType형의 변수를 멤버로 갖는 게 아닌가보군요. 단순히 MotionType의 멤버들의 이름을 Character 클래스의 이름공간으로 끌어오는 방법에 대한 것이었나 보네요...
그렇다면 2번의 예라면 저 enum 멤버를 어떻게 사용하는 건가요?
다람쥐v//
그럼 지금 Character란 클래스가 MotionType형의 변수를 멤버로 갖는 게 아닌가보군요. -> 멤버로 갖고 있습니다. 인스턴스 마다 하나 씩 가지니 문제가 되죠.
단순히 MotionType의 멤버들의 이름을 Character 클래스의 이름공간으로 끌어오는 방법에 대한 것이었나 보네요.-> 이건 뭐가 그렇다는 것인지 모르겠네요.
그렇다면 2번의 예라면 저 enum 멤버를 어떻게 사용하는 건가요?-> m_motionType 을 클래스 멤버로 생성하는 것은 권해 드리지 않습니다. 저라면 외부 변수로 선언하겠습니다.
계속 이해가 안되서 코드로 만들어봤습니다. 이게 맞는 것인지요?
enum 자체는 오직 1개만 생성해도 되기 때문에 static으로 만들어 준다는 것으로 이해했습니다.
static class CharaterState
{
public:
typedef enum
{
// 캐릭터의 동작 종류 : 캐릭터 동작 로직이 아닌 순수 캐릭터 애니메이션만 담당한다.
// 주로 캐릭터의 현재 동작 상태를 표시하는데 쓰인다.
STANDING = 0,
RUNNING,
JUMPING,
DIED,
MAX_MOTION_TYPE
} MotionType;
}
enum MotionType를 밖으로 빼던가
아니면 static enum으로 만들던가 하라는것 아닌가요?;;
CharacterState자체를 Static으로 만들면 인스턴스 하나밖에 없으므로 모든 캐릭터가 상태를 공유 하게 되겠죠.
그게 아니라
CharacterState는 캐릭터 마다 달라져야 하지만 MotionType같은경우 하나만 선언해주면 되므로 메모리 낭비를 하지 않기위해 빼라고 말씀하시는것 같네요;;
아님말고...
제생각에는 Motion이라는게 이름만 봐서는 케릭터에서만 쓰일 용도는 아닌거 같아서 전역변수로 빼버리는게 좋아보이네요.
케릭터 클래스에서 애니메이션까지 구현하지 않는다면 최소한 애니메이션 관련 클래스에서는 쓸거 같군요
static enum은 말이 안되지요. class를 정의한다고 해서 그게 정의자체로 인스턴스화 돼서 메모리를 먹는 건 아니듯이, enum을 정의한다고 해서 그 자체로 메모리를 점유하지 않습니다.
enum types {k_Foo, k_Bar, ...};
이 자체로는 아무 일도 일어나지 않습니다. enum types라는 자료형을 정의한 것이고,
types type_for_something;
이렇게 변수로 선언을 해주어야 메모리에 할당이 되는 것이지요.
잘 못 알고 있는 것 같습니다.
//RaceManager.h
...
enum GameMode {TRIAL_MODE, VS_MODE};//TRIAL_MODE, VS_MODE 같은 이름에는 이 문장 하나로 메모리가 할당되고 값이 대입됩니다.
...
-------------------------------------------------------------
//RaceManager.cpp
#include"RaceManger.h"
...
GameMode RaceManager::m_GameMode = TRIAL_MODE;//OK!
...
아닙니다. 게임초보님께서 선언과 정의의 차이를 헷갈려하시는 것 같습니다.
예로 들어주신 코드로 얘기해보자면,
enum GameMode {...}; 이 문장은 정의입니다. 이 문장으로 어떠한 것도 인스턴스화 되지 않습니다.
RaceManager에는 m_GameMode란 이름을 가진 GameMode형의 변수가 선언되어있는 것이지요. RaceManager가 인스턴스화 될 때 같이 인스턴스화 되어서 메모리를 차지하게 됩니다. 그런데 초기화하는 코드를 보아하니 정적 멤버 변수인가 봅니다. 이 경우에는 프로그램 실행 초기에 초기화가 되겠지요. 왜 정적 멤버 변수인지는 모르겠지만...
아래는 이해를 돕기 위한 코드입니다.
http://codepad.org/TNzk38Ty 제가 enum을 하나 더 복사해 놓았는 데 이 경우 메모리가 할당되네요.
C++명세상 선언문의 선언은 대부분 정의의 성격을 가지게 됩니다.
선언이 메모리를 할당받지 않는다는 것은 오류입니다.
예)
struct User; //선언이지만 정의는 아닌 경우-이 경우 메모리 할당은 없습니다. --첫번째 경우
struct Date { int d, m, y; }; // 선언이면서 정의인 경우- 이 경우 메모리가 할당됩니다. --두번째 경우
http://codepad.org/TNzk38Ty 에서 제가 더한 enum의 경우 두 번째 경우에 해당됩니다.
확실히 잘못 알고 계신 것 같습니다.
예로 올려주신 코드에서 추가로 작성해주신 부분은 enum 멤버가 각각 메모리 영역을 차지한다는 의미가 되지 않습니다.
말씀대로라면 sizeof(MotionType)은 20이 되어야겠네요? 4바이트의 멤버가 5개씩 있으니. 근데 아니지요;
이거하고 같은 경우입니다. sizeof 연산자는 자료형의 크기이지, 메모리에 할당된 상태에서의 크기를 말하는 것이 아닙니다.
메모리 할당은 인스턴스화가 이루어질 때 이뤄집니다.
struct Date { int d, m, y; }; 이 문장으로는 인스턴스화가 이뤄지지 않기 때문에 메모리 할당도 없습니다. 할당되지 않습니다.
이렇게 정의를 하고나서, struct Date date; 또는 Date date;와 같이 인스턴스화를 해야만 메모리 할당이 이루어지는 것이고요.
또한 말씀대로 enum 멤버마다 메모리에 할당이 된다면 그 주소는 어떻게 참조할 수 있는지요. &TRIAL_MODE로 참조할 수 있나요?
자바식으로 보자면 static final 키워드면 되는 문제인거 같긴한대요.
c++에서는 어떤 idiom이 있는지는 모르겠네요..
헐... 댓글이 많아졌네요!
enum은 C/C++의 type system에 영향을 받는 define이라고 생각하시면 됩니다.
어디에다 놔두던 용량적인 문제는 없고, 코딩시 혼돈이 없게 스코프만 잘 정해주면 됩니다.
즉 1번 케이스나 2번 케이스나 메모리의 footprint는 같다고 생각하셔도 무방합니다.
단지 설계시 어떤 스타일을 선호하느냐의 문제이지요.
참고로
CASE1:
#define STAT_IDLE 0
#define STAT_RUN 1
#define STAT_DEAD 2
--
CASE2:
const int STAT_IDLE = 0;
const int STAT_RUN = 1;
const int STAT_DEAD = 2;
--
CASE3:
typedef enum {
STAT_IDLE = 0,
STAT_RUN,
STAT_DEAD
} Status;
---
이 세개 모두 우리가 흔히 아는 상수 선언 방법이고, 셋다 저 문장들로만은 실행시점에서 메모리의 사용은 없습니다.
CASE1의 경우 C/C++컴파일러가 아닌 프리프로세서가 매크로 확장을 하며 치환하게 되므로, 그냥 상수치환 됩니다.
CASE2의 경우는 C/C++ 컴파일러가 치환을 담당하게 되고, 덕분에 타입 체크를 합니다. 단순한 매크로 확장이 아닌 타입 일치여부나 정밀도 손상등을 체크해 줄 수 있으므로 CASE1보다 더 선호되는 방법입니다.
CASE3은 CASE2와 같이 컴파일러가 처리하며, 단순 타입에 더불어 열거형 상수가 아닌 값에 대한 체크까지 해 줄 수 있습니다. 이 역시 사용시에는 실질적으로 컴파일러에 의해 상수값으로 치환됩니다.
따라서 뭘 쓰건 메모리 사용량이나 퍼포먼스에서는 차이가 없습니다.
스타일1번이냐 2번이냐는 개인의 성향에 따라 호불호가 갈리는 편이고, 저 같은경우에는 첨에 말씀드렸듯.. 1번을 선호합니다. :)
저라면 1번
외부에서 참조될 것이 아니라면, 궂이 별도의 클래스로 분리할 필요는 없지 않나 싶어요.
근데 프로그램을 한 20년넘게 짜다보니.. 그냥 손가는데로 작성하고, 나중에 필요하면 수정하는게 최고더라눈.. -_-