• 카테고리

    질문 & 답변
  • 세부 분야

    게임 프로그래밍

  • 해결 여부

    미해결

포인터 멤버 변수

22.03.08 21:20 작성 조회수 404

0

class Game
{
public:

private:
	Player _player;
	Player* _player;
};

 

클래스 멤버 변수로 포인터가 아닌 일반 객체를 선언해서 들고 있을 경우 발생하는 문제점(?) 혹은 한계에 대해 질문이 있습니다.

 

첫째, 일반 객체에 추후 knight, archer 등등 다른 캐릭터 타입을 _player에 할당할 경우 자식 클래스의 데이터가 더 크기 때문에 데이터 소실이 발생할거라고 설명을 해주셨습니다.
그런데 이 문제는 포인터로 선언해서 들고 있는 클래스 변수에도 동일하게 나타나는 문제가 아닌가요?
강의를 듣고 이해하기로는 포인터가 아닌 일반 클래스 타입 객체를 사용할때만 이 문제가 발생하는 것으로 이해가 되는데 제가 잘못 이해한 부분이 있을까요?

 

둘째, 포인터 변수와 일반 클래스 변수와의 명백한 차이는 Game 클래스 자체적으로 들고 있어야 하는 데이터 양이 크기인데 포인터의 경우(4 or 8 byte)로 국한되지만 일반 클래스 변수의 경우 해당 멤버 클래스의 크기만큼 Game 클래스에서 복사되어 들고 있어야 한다.

멤버 변수로 포인터가 아닌 일반 클래스 변수를 들고 있을 경우 발생하는 한계점에 대해 '두번째'로 언급한 내용에 대해서는 이해가 됩니다. 하지만 첫번째 내용이 명확히 이해가 되지 않습니다.

답변 3

·

답변을 작성해보세요.

0

1)  첫 번째 질문한 내용처럼 Player* 형태로 Knight를 받아도 해당 객체에서 Knight의 _atk와 _def에 접근이 가능할까요? 만약 클래스 포인터가 아닌 일반 클래스 Player형태로 Knight를 받게되면 _atk와 _def에 대한 데이터 소실이 발생하게 되나요?

Player* 형태로 받으면 _atk, _def에 '당장은' 접근할 수 없습니다.
그렇다고 _atk, _def가 소실된 것은 아니구요.
Player*를 다시 Knight* 형태로 캐스팅을 해서 사용하면 됩니다.

2) 만약에 1번 질문이 YES인 경우, Player*는 이름만 Player클래스이고 실제로 해당 주소로 가면 Knight를 구성하는(_hp, _atk, _def) 객체의 주소가 있다는 의미일까요? 단지 Player*는 이름만 빌려주고 다른 주소를 사용하도록 되어있다는 개념으로 이해해도 문제 없는지 궁금합니다.

진실은 해당 주소에 Knight 가 있다는 것은 변함이 없구요.
하지만 Knight도 Player + _atk, _def가 추가된 형태라서,
Knight*가 아닌 Player*로 간주한다면 _atk,_def를 제외한 나머지에만 접근할 수 있게 됩니다.

3) 2번 질문도 YES인 경우, Player* 형태로 다른 캐릭터 타입(Knight, Archer, etc...)를 받아주도록 코드를 구성한 이유는 부모클래스라는 구조적 특성을 이용해 코드 관리의 편의성(?)이나 객체지향 스탠스(?)를 유지하기 위해 사용된다고 봐도 무방할까요?

네 그게 맞습니다. 가령 인게임에 접속한 유저를 관리하는 PlayerManager가 있다면,
세부적으로 Knight, Archer, ... 직업별로 따로 관리하기보단
Player로 관리하는게 편리한 경우가 많기 때문에
부모클래스인 Player*로 데이터를 관리하고,
추후 필요하면 (타입 체크 후에 캐스팅 or dynamic_cast 등 이용) 다시 Knight*, Archer*
등으로 본래 타입으로 복원해서 데이터를 사용하면 됩니다.

 

0

Moderich님의 프로필

Moderich

질문자

2022.03.09

답변 감사합니다 :)

답변해주신 내용이 무엇을 의미하는지는 알겠습니다만 잘 정리가 되지 않아 구체적인 예시로 다시 질문을드려볼까 합니다.

 

class Player
{
public:
    int _hp;
}

class Knight : public Player
{
public:
    int _atk;
    int _def;
}

 

만약 위와 같이 Player 클래스는 _hp 변수 하나만 들고 있고 Knight는 Player를 상속받고 _atk, _def가 있다고 가정하겠습니다.

 

1)  첫 번째 질문한 내용처럼 Player* 형태로 Knight를 받아도 해당 객체에서 Knight의 _atk와 _def에 접근이 가능할까요? 만약 클래스 포인터가 아닌 일반 클래스 Player형태로 Knight를 받게되면 _atk와 _def에 대한 데이터 소실이 발생하게 되나요?

 

2) 만약에 1번 질문이 YES인 경우, Player*는 이름만 Player클래스이고 실제로 해당 주소로 가면 Knight를 구성하는(_hp, _atk, _def) 객체의 주소가 있다는 의미일까요? 단지 Player*는 이름만 빌려주고 다른 주소를 사용하도록 되어있다는 개념으로 이해해도 문제 없는지 궁금합니다.

 

3) 2번 질문도 YES인 경우, Player* 형태로 다른 캐릭터 타입(Knight, Archer, etc...)를 받아주도록 코드를 구성한 이유는 부모클래스라는 구조적 특성을 이용해 코드 관리의 편의성(?)이나 객체지향 스탠스(?)를 유지하기 위해 사용된다고 봐도 무방할까요?

 

 

0

그런데 이 문제는 포인터로 선언해서 들고 있는 클래스 변수에도 동일하게 나타나는 문제가 아닌가요?

아닙니다. 포인터는 단순히 주소를 들고 있고,
본체는 따로 힙 메모리에 올라가 있기 때문에
아무런 손실이 없습니다.


Player*로 저장하건 Archer*로 자정하건 Knight*로 저장하건,
메모리 주소에는 아무 변화가 없습니다.
다만 해당 주소를 타고 갔을 때, '무엇'이 있느냐에 대한 관점(인식?)만 달라질 뿐입니다.