'게임'에 해당되는 글 5건

  1. 2007.06.13 C++ 추상 클래스와 포인터 캐스팅, 다중상속 ㅅㅂㄹㅁ (11)
  2. 2007.05.03 또다른 지식의 성전 리메이크된다
  3. 2007.04.24 Win32API 자작게임 배포
  4. 2007.04.02 게임지와 정품부록, 게임시장
  5. 2007.03.29 블록버스터 게임과 Independancy

C++ 추상 클래스와 포인터 캐스팅, 다중상속 ㅅㅂㄹㅁ

프로그래밍 2007. 6. 13. 22:41
상황설명

A라는 부모 클래스를 만들고, 이 A라는 클래스의 포인터인 A* pA 를 인자로 하는 foo(A* pA)를 정의해서 사용중이었다. 이 함수의 인자로는 A를 상속한 B나 C클래스를 예상할 수 있으며, 이 B와 C클래스는 I라는 순수 가상함수를 상속한 다중상속 객체들이었다. I는 순수가상함수인 Vfoo()를 가지고 있었다. C는 생성자에서 A의 함수(가상함수가 아니다)를 호출한다.

사용자 삽입 이미지

이런 상속관계 (수정)


vector<I*> vt;

...

C* pC = new C;
I* pI = (I*)pC; // C* -> I*
vt.push_back(pI);

...

A* pA = (A*)vt[0]; // C* -> I* -> A*
foo(pA);

...

foo(A* p_pA)
{
    I* pI = (I*)p_pA; // C* -> I* -> A* -> I*
    pI->Vfoo(); // 여기서 문제발생
}

문제발생

문제는 C형 인스턴스를 가리키는 A형 포인터 pA_dir_C를 foo(A* pA)의 인자로 넘겨주면서 일어났다. foo(A* pA)함수 내부에서는 인자로 받은 pA를 (I*)pA 로 형변환하여 Vfoo()를 호출하는 루틴이 들어있었는데, 여기서 에러가 발생한 것이다. (6025 pure virtual function call)

Watch를 통하여 살펴보니 vftable의 문제였는지, Vfoo()가 아닌 엉뚱한 함수가 불려오더라. (다른 추상 클래스 I2에서 오버라이딩 된 가상함수였다.) 포인터 형변환에서 가상함수 테이블에 변화가 오는 것일까?

해결책

결국 C* -> I* -> A* -> I* 와 같은 여러 번의 형변환을 거치지 않고 C* -> I* 상태에서 pI->Vfoo() 식으로 형변환 단계를 줄여서 사용하였다. 정확히 말하면 문제를 해결한 것이 아니라 회피한 것이나 마찬가지다. 하지만 적당한 레퍼런스도 없고, 도와줄만한 사람도 없고 해서. 코드 길이는 좀 길어질지 몰라도 저런 식으로 함수를 통하는 단계를 줄여버렸다.

감상

쩐의 전쟁이 너무 재밌다.


Trackbacks 1 : Comments 11
  1. ProgC 2007.06.14 02:24 Modify/Delete Reply

    음... 추상화 인터페이스를 이용한 설계를 하시는거 같은데
    그림이 좀 잘못된 것 같습니다. 그림상으로 보면 I인터페이스가 B, C를 구현하는걸로 되어 있네요. 그 반대가 되어야 할 것 같습니다.

  2. 동숙이 2007.06.14 12:23 Modify/Delete Reply

    정확한 소스를 어떻게 되나요?
    궁금해서 코드를 만들어 봤는데..

    제가 한봐로는 문제가 없는거 같은데요.

    • Favicon of https://axnoah.tistory.com BlogIcon AxNoah 2007.06.14 18:54 신고 Modify/Delete

      그럼 저 자체로는 문제가 없다는 걸까요.
      6025 pvfc 문제는 생성자에서 가상함수 테이블 관련해서 일어나는 문제라고 하던데, 형 변환 과정에서 가상 테이블의 변화가 있는지 없는지를 몰라서요.

  3. Favicon of http://dcple.com BlogIcon chadr 2007.06.14 14:59 Modify/Delete Reply

    제가 봐도 코드상에 이상한점은 안보이는군요..

    저기 안보이는 "...."부분에서 뭔가 잘못된 일을 하지 않는가 싶군요.

    • Favicon of https://axnoah.tistory.com BlogIcon AxNoah 2007.06.14 18:55 신고 Modify/Delete

      ㅠㅠ 대체 어떤 게 문제인지 모르겠습니다.
      회피하고 말았네요.

  4. Nagne 2007.07.31 11:44 Modify/Delete Reply

    검색으로 지나가다가 소스를 보고 발목잡혀 글남깁니다...
    일단 소스는 좀 오류가 심각하네요....당연히 않됩니다...
    I* pI = (I*)pC; 이부분과
    vt.push_back(pI); 이부분과
    A* pA = (A*)vt[0]; 이부분이 잘못됐습니다..

    이부분이 문제 입니다.... 인터페이스 I와 단순한 부모클래스 A를 다중상속받아서 사용하고 있습니다...
    벡터에 저장할 때는 (I*) 형으로 변환하고 있군요..
    자 일단 다중상속 받는 순서가 I 가 먼저오고, A가 다음에 온다고 가정하겠습니다...
    pC 의 주소값이 0x1000 이라고 가정하구요....
    I* pI = (I*)pC;
    A* pA = (A*)pC;

    이렇게 했을때 pI의 값은 0x1000입니다..
    그리고 pA의 값은 0x1000+alpa 입니다...
    왜 그러냐구요...클래스 포인터의 형변환은 주소값을 바꾸는
    기능을 합니다....(short*) 를 (int*)로 형변환 하는것하고
    클래스의 포인터를 형변환 하는것은 아주 큰 차이가 있습니다.
    (short*)를 (int*)로 형변환 하는것은 reinterpret 캐스팅이라고합니다. 형변환한 주소값에 아무런 변화가 없습니다. 형변환 하지 않을 경우 컴파일러가 이부분 문제가 있어보인다며 확인할것을 강요하고 프로그래머가 형변환 코딩을 넣도록 강요하는 역할을 가집니다.

    그러나 클래스 포인터의 형변환은 완전히 다른 의미입니다...즉 해당 클래스로 형변환 하면서 주소를 계산을 하는것이죠....이때에 룰이 있습니다..
    두 클래스간에 상속관계가 전혀 없을때는 주소계산을 하지 않습니다. 이것도 reinterpret 캐스팅이라고 합니다.. 그리고 상속관계에 있을때는 포인터 형변환시에 static 캐스팅이 발생합니다..주소값을 계산해 버리죠,....

    I* pI = (I*)pC; // 여기서 static 캐스팅 됐습니다..

    C는 I를 먼저 상속받았다고 가정했으니..static 캐스팅했지만 값의 변화는 없을겁니다...
    만약 (A*)pC 하였다면 값의 변화가 옵니다.

    그런데...
    (A*)vt[0]; 요 부분에서 vt[0]의 형은 (I*) 형입니다. 그리고 I와 A는 아무런 연관성이 없습니다..
    때문에 여기서는 reinterpret 캐스팅이 발생합니다...
    즉, A* pA = (A*)vt[0]; 요 부분에서 pA가 정상적인 동작을 할려면 0x1000+alpa 로 저장이 되어야 하는데, reinterpret 캐스팅 되어서 pA에 저장된 주소값은 0x1000이 되어버린것입니다...그러면 pA를 이용해서 Vfoo()를 호출하면 I의 영역을 A의 영역처럼 사용하겠죠..숨은 버그입니다... 그리고 c++에서는 static_cast<> 연산자와 reinterpret_cast<> 연산자가 있어서 위와 같은 버그를 컴파일 타임에 잡아줄수 있게끔 하고 있습니다.. (I*) 와 (A*)는 C 타입의 형변환입니다..reinterpret 캐스팅과 static캐스팅의 구분이 엄격하게 따지고 들어야만 제대로된 코딩이 가능하죠....
    아 그리고
    foo() 함수 내부에서
    * pI = (I*)p_pA; 요부분도 reinterpret 캐스팅이죠...아무연관성 없는 포인터형으로 변환한 것이니깐요..

  5. Nagne 2007.07.31 12:07 Modify/Delete Reply

    위 코드를 수정한다면 다음과 같이 하면 될겁니다..

    vector<I*> vt;

    ...

    C* pC = new C;
    I* pI = static_cast<I*>pC; // C* -> I*
    vt.push_back(pI);

    ...

    A* pA = static_cast<A*>static_cast<C*>vt[0]; // C* -> I* -> C*-> A*
    //I와 C는 연관성이 있지만 I와 A는 연관성이 없기에 연관성 있는것으로 중간에 연결가능한 C를 거쳤다가 변환합니다..당연히 static_cast이어야 합니다..

    foo(pA);

    ...

    foo(A* p_pA)
    {
    I* pI = static_cast<I*>static_cast<C*>p_pA; // C* -> I* -> C* -> A* -> C* -> I*
    //마찮가지로 A* 에서 I*로 형변환 하는 사이에 C*로 정적 캐스팅합니다..
    pI->Vfoo(); // 이제는 정상동작
    }


    static_cast가 하는일은 베이스클래스로 형변환 할때는 차일드 클래스의 주소공간 중에서 베이스클래스의 주소를 찾아서 주소값을 바꿔주고, 차일드 클래스로 형변환 할때는 베이스클래스주소가 그 차일드 클래스로부터 정적 캐스팅하였을때 획득한 주소라고 가정하고 차일드의 주소를 계산하여줍니다...
    따라서 사실 위 소스코드는 정상 동작하지만...
    vector<I*> vt 가 B 클래스의 인스턴스의 주소도 같이 저장하는 벡터라면 여전히 버그가 존재한다는것 잊지마세요...
    일단 버그 상관 없이 동작시킬라면 B 하고 C가 I하고 A를 상속받는 순서를 똑같이 하여야만 하고, B저장했던것인지 C저장했던것인지 확실히 구분 가능하여야만 위 코드가 정상 동작할 겁니다...

    class I{}; class A{}; class X{}; class Y{};
    class B : public I,public A ,public X{};
    class C : public A,public I ,public Y{};

    만약 클래스 구조가 이딴식으로 된다면....위에 수정해 드린 코드로도 정상동작은 않됩니다...단 vt[0]가 B의 인스턴스로부터 저장된 것인지. C의 인스턴스로부터 저장된것인지 확실히 알수 있다면 위와 같은 방식의 형변환으로 충분할 것입니다...
    그럼 이만...

    그리고 더 궁금한거 있으면 yilove78@fme.co.kr 로 문의하세요....

  6. Favicon of http://wafe.kr/ BlogIcon wafe 2007.08.28 15:42 Modify/Delete Reply

    다중 상속에 대해서 검색하다 우연히 들렀는데, 이미 다른 분께서 해결책을 남기셨군요. ^^

    C++에서는 타입 캐스팅을 할 때 C 스타일의 캐스팅보다는 C++ 스타일의 static_cast, dynamic_cast, reinterpret_cast 를 쓰는 것을 추천하고 있습니다.

    C의 캐스팅에 비해 여러가지 의미가 첨가되어 있는 것이 C++의 캐스팅이기 때문에 캐스팅의 내용을 좀 더 명확하게 알고 구분해서 쓰라는 의미가 있고요, 또 글에 쓰신 것과 같이 부적절한 캐스팅에 대해서 컴파일러가 힌트를 줄 수 있기 때문입니다.

    • Favicon of https://axnoah.tistory.com BlogIcon AxNoah 2007.09.15 12:50 신고 Modify/Delete

      관련 글 들은 몇 번 읽은 적이 있는데, 아무래도 습관 탓인지 아직 익숙하지 않네요. 경험부족이 이런데서 나오나 ㅠㅠ 음. 컴파일러가 알려 줄 수 있으면 적극 활용해야겠네요.

Write a comment


또다른 지식의 성전 리메이크된다

생각하다 2007. 5. 3. 12:10

오래 전부터 만날 운명이었던 당신에게.

나는 시공의 여행자인 타임워커 알비레오라고 하오...

안영기님의 명작. 또다른 지식의 성전이 리메이크된다고 합니다. 개발사는 GBA용 게임 아이언키드로 유명한 비트메이지입니다. 수소핵융합의 추억이 되살아나는군요. 플랫폼은 미정이랍니다. 개발자 분들이 게임에 대한 애착이 대단하여, 게임의 퀄리티가 기대되는 작품입니다.

NDS로 나오면 좋지 말입니다.


네이버 카페 http://cafe.naver.com/anotherlore

tags : 게임
Trackbacks 0 : Comments 0

Write a comment


Win32API 자작게임 배포

프로젝트 2007. 4. 24. 00:36
친구와 함께 공동제작하기로 하고서 제작착수한 것이 1월 12일이었습니다.
이거 하나 만든다고 한 게 깨작깨작 거리다보니 3개월 걸렸네요.


허허 이것 참…….

너 뭐하는 놈이야?

아, 저기 저도 열심히 하고 싶었다구요.


ㅠㅠ

파일 첨부합니다. 실행하기 전에 동봉된 리드미 파일을 꼭 읽어보시기 바랍니다.
프로젝트는 계속됩니다! Peace!!

※ 다운로드 : shot.rar

혹시나 소스 필요하시면 메일로 연락주세요.


known bugs가 너무 많군요 ㅠㅠ

Trackbacks 0 : Comments 0

Write a comment


게임지와 정품부록, 게임시장

생각하다 2007. 4. 2. 21:14


초등학교 시절. 컴퓨터 게임에 푹 빠져있던 나는 우연찮은 계기로 게임지를 사서 모으게 되었다. 1998 년 8월호 PC CHAMP에서부터 시작해서 2003년까지 햇수로만 6년 정도를 꾸준히 게임지를 모았었다. (6 * 12 면 72권 정도, 실제로는 용돈 수급이 좋지 않아 건너뛴 달도 있어서 실제로는 60여 권 정도가 지금 책꽂이에 모셔져 있다.)

  초창기 게임지를 사던 이유는 뭐니뭐니해도 정품 번들 게임이었다. 처음 PC CHAMP를 구매하던 1998년 8월호에는 로드 오브 렐름 2 가 정품 번들로 제공되었고, 머지 않아 아미맨등의 인기 타이틀이 번들로 제공되었던 적이 있다. 이 정품번들이라는 게 당시 패키지를 구매할 만한 돈이 안되던 나로서는 정말이지쏠쏠한(?) 구매경로가 아닐 수 없었다. (물론 조금 철지난 게임들만 제공되었지만 말이다. 그리고 아쉽게도 소프트맥스의 게임은 절대 번들로 제공되지 않았었다.)

물론 번들에 혹해서 산 게임지지만 기사 역시도 꾸준하게 읽었다. 하드웨어 강좌나 TRPG, 게임계 뉴스 같은 코너는 상당히유익했고, Tip&Hacks(게임의 공략/치트키 등이 실리는 코너)는 매월호마다 스크랩까지 해놓을 정도로, 정말이지빼먹은 적이 없었다.

물론 구매를 결정짓는 것은 번들이 약 40%, 게임 기사가 20%, 애독자로서의 사명감(?) 40% 정도였다.
사실 몇 년 잡지를 구독하면서 정품 번들의 제공에 대해 당연하게 생각했던 것이 사실이다. 당시 잘 나가던 PC 게임 잡지들(PCPlayer, PC CHAMP, V챔프 등등)은 모두 정품 번들을 제공하고 있었고, 친구들은 어떤 타이틀이 번들로 제공되는 가를잡지 구매의 중요한 요소로 평가하고 있었다. 어쩌면 이때부터 속물근성에 눈을 뜬 건지도 모르겠다.

그러던 중, PC CHAMP에서 아미맨2가 국내 정식 발매와 동시에 번들로 제공되는 일이 있었다.상당히 신기한 일이었다. 보통 몇 달, 혹은 몇 년 정도 묵어서 잘 팔리지 않는 게임들을 제공하던 것이 번들이었는데 나온지일주일도 안된 게임을 끼워주다니, 뭐 나야 좋은 노릇이지만. (사실 이때쯤해서 게임지의 번들 제공 경쟁이 과열되었던 것으로기억한다.)

그리고 화이트 데이 번들. '국산 게임은 번들로 제공할 계획이 없다'라는 프로포설을 깨버리고 발매한지(비교적) 얼마 지나지 않은 국산 타이틀을 번들로 제공하는 사태를 맞고 나니. "이거 뭔가 좀 이상한데?" 하는 생각을 조금씩갖게 되었다.

본디 번들CD는 데모 버전, 동영상, 평가판 유틸리티, 세이브 파일 등을 끼워넣어 주는 것이관행이었다고 하던데. 언제부터인가 어느 잡지사에서 정품 게임을 번들로 제공하면서부터 치열한 정품 번들 경쟁이 시작되었다고하더라. 결국 이 피 튀기는 전쟁은 제 살을 깎아먹는 것으로 끝나고 만다. 수많은 게임잡지들이 폐간했고 그시절 잡지사들 중에서그나마 현재 명맥을 유지하고 있는 것은 PC Player 하나뿐이다. (그나마 이것도 잡지 두께가 꽤나 얇아졌더라, PCCHAMP = PC PowerZine은 NetPower에 통합되어버리고.)

정품 번들 경쟁은 결국 게임 잡지들의수준 저하를 유발하고, (솔직히 어느 시기부터였던지, 기사들의 수준이 부쩍 수준 미달로 치닫는 것을 느낄 수 있었다. 아마도2001년 전후였을 것이다.) 게임 잡지의 본질을 변질시켜 버렸다. 잡지를 위한 번들이 아닌 번들을 위한 잡지로 은연 중에바뀌어가고 있던 것이다.

초고속 통신망의 보급에 따라 게임을 더욱 쉽게 (그리고 저렴하고 파렴치하게) 구할 수 있는루트가 생기자 염가에 질 좋은 게임을 모토로 내세웠던 게임지(이미 이 시점에서 글러먹은 것)들은 하나 둘 씩 재정적 압박에시달리게 되고, 결국 폐간을 결정하고 만다.

게임지의 번들 제공은 결과적으로 게이머들의 소비 심리를 위축시키고, ( 게임 = 제 돈 쓰고 살 필요 없는 것 ) 게임지의 저널리즘으로의 가능성을 원천적으로 봉쇄해버렸으며, 올바른 비평을 수행할 미디어 저변 부족으로 국내 게임계의 일보후퇴를 불러오지 않았나 싶다. 작금의 사태 -공장제 판박이 같은 게임들이 쏟아져 나오는 사태- 역시 올바른 비평 문화나 게임 언론의 질타와 타박이 부족해서는 아닐까.

언뜻 책장의 낡은 잡지를 보고 고개를 끄덕여본다.

Trackbacks 0 : Comments 0

Write a comment


블록버스터 게임과 Independancy

생각하다 2007. 3. 29. 16:55

스페이스 워 (1962)

그 오래전 스페이스워(spacewar, 1962년 MIT공과대학)에서부터 지금의 WoW(2004, 블리자드 엔터테인먼트) 근 40여 년에 걸쳐 PC게임은 엄청난 변화를 겪어왔습니다. 기술적 혁신은 물론이며 게임 이론의 수립 및 대규모 제작 공정의 출현. 정말이지 하나의 산업 분야가 되어버렸지요.

사실 게임 개발은 엄청난 노동집약형 산업입니다. 코드 한 줄, 그래픽 리소스 하나 하나 심지어 미세한 효과음 하나 하나까지 사람 손을 거쳐야 하는 정말이지 사람들의 땀과 노력의 현장이라 할 수 있죠. 이 과정에서는 막대한 자금과 많은 사람들의 노동력이 소비됩니다. 하지만 이렇게 심혈을 기울여 만든 게임들이 모두 성공하는 것은 아니죠. 어떤 게임은 잊혀지고 또 어떤 게임은 출시 당일부터 여러 사람들의 입에 오르내리며 출세가도를 달리게 됩니다. 물론 만들어지는 게임의 대다수는 후자에 속해있습니다.

게임 산업이 노동집약형 산업이면서도 그 결과물로 창출할 수 있는 가치의 산정이 불분명한 특성이 있기 때문에, 이것은 흡사 영화 산업과도 유사해 보입니다. 영화계처럼 그들중에는 블록버스터 게임도 있고, 소수만이 즐기는 마이너 게임도 있죠. 그리고 블록버스터 게임들은 필시 제작과정에서부터 엄청난 규모의 인력, 자본이 투입됩니다. (물론 리니지, 뮤 등의 초기 온라인 블록버스터 게임들은 소규모 공정의 산물이라 볼 수 있겠지만, 현 시장의 판도는 그때와는 상당한 차이가 있지요.)

블록버스터 게임들은 블록버스터 영화와 마찬가지로 대규모의 자본이 투입됩니다. 개발인력(자본의 블랙홀)은 물론이며 대규모의 프로모션, 유저들을 끌어들이기 위한 다양한 마케팅 비용 등등. 어지간한 영화 한 편 만드는 비용 못지 않죠. 이렇게 기회비용이 커지게 되면서 출시되는 게임들은 다들 흥행을 위한 보증수표, 영화 산업에서는 유명 배우나 뻔한 스토리 등으로 통하게 되는 몇몇 클리셰(cliche)를 첨가하게 됩니다. (사실 이 클리셰가 요즘 게임들에선 너무 과하죠?) 익숙한 UI, 혹은 게임진행방식과 같은 형태의 것들 말이죠. 이런 것들은 유저들의 진입장벽을 완화하고, 사용자 증
가로 인한 안정적인 수익창출을 가능케합니다. 이것이 바로 '대안게임'의 이점입니다.

WoW

월드 오브 워크래프트 (2004)

그러나 그게 전부일 뿐. 결국 과도한 클리셰의 남용으로 인하여 모든 게임들은 서로의 개성을 잃어가고 맙니다. 대안게임은 대안게임에 충실해야지 다른 모습을 가졌다간 수익을 보장할 수 없을 테니까요. 결국 대안게임은 영리를 목적으로 한다는 그 오버그라운드적 특성때문에 자신의 목을 죄고 있는 것이나 다름이 없어요. 그렇기 때문에 수많은 게임들이 서로 엇비슷한 눈, 코, 입, 목소리를 가지게 되는 것이고 게임계에 발전이 없다는 소리가 나오는 것이겠지요.

하지만 솔직히, 그러니까 까놓고 말해서 진보와 혁명은 오버그라운드의 것이 아니죠. 자본의 물을 먹고 몸집이 비대해진 개발사들은 쉽사리 변혁을 시도할 수 없습니다. 시장의 개혁과 혁신이라면 모를까 시대의 개혁과 혁신은 젊은 층. 즉 언더그라운드에서 행해지는 것이 지금까지의 역사였습니다.

그렇다면 게임계의 언더그라운드. 그들은 지금 어디 있는 걸까요?

Trackbacks 0 : Comments 0

Write a comment