CEntity 클래스 설계중 (2)

Yama·2024년 1월 19일
0

어소트락 수업

목록 보기
50/55

CEntity 클래스의 맴버

//CEntity.h의 CEntity클래스 내부.
private:
	// 1
	const UINT	m_ID;
  • 객체별 고유 ID를 나타내는 맴버함수다.
  • 한번부여한 객체의 ID값이 바뀌면 안되니 const를 사용해서 상수화 시켜 수정을 방지했다.

CEntity 클래스의 생성자.

// 2
UINT g_NextID = 0;


// 1
CEntity::CEntity()
	: m_ID(0)
{}
// 3
CEntity::CEntity()
	: m_ID(g_NextID++)
{}
  • 1번처럼 0으로 기본 생성자를 초기화해버리면 객체가 만들어질떄마다 ID값이 0으로 항상 초기화되므로 이렇게 하면 안된다.

  • 2번 CEntity.cpp에서만 작동하는 전역변수 0으로 초기화해서 해둔다.

    • 43억개까지의 객체까지는 고유한 ID값을 줄수 있다.

    • 43억개의 객체를 언젠간 게임을 계속 켜두면 ID값을 초과 할수도 있다.(전나 오래걸린다.)

    • 이걸 방지하고 싶다면 특정 ID를 가지고 있는 오브젝트가 삭제될때마다 비었다는걸 어디다 기록을 해야 한다.

      • 객체가 메모리에서 삭제되는 경우에는 다음 경우를 받아가는게 아니라 삭제된 값 비어있는 ID값을 관리하는 담담장 객체가 있었어야 하지만 우리는 이렇게 포폴로 게임을 오래 구동 시킬게 아니라 ID값을 unsigned int로 선언했다.
  • 3번에 아이디값이 들어올때마다 전역변수 선언해준거에 후위연산을 해주면 된다.

    • CEntity객체가 하나 생기면 ID값으로 0이 들어가고 후위연산해서 1로 증가하고 CEntity객체 또생기면 1들어가고 2로 증가하고 CEntity객체마다 ID값을 다르게 설정 가능하다.
  • 2번처럼 선언을 해두면 보안에 취약함이 있다.

    • 전역변수는 다른곳에서 선언할수있다.
	static UINT g_NextID = 0;
  • 철저하게 CEntity클래스 전용 전역 변수로 사용할려고 static를 사용해서 사용했다.
// CEntity.h의 CEntity 클래스 내부,
private:
	// 1
	static UINT g_NextID;
  • 1번은 정적 맴버 선언이라고 한다.

  • 특정 클래스 내에 맴버로 정적변수를 선언

    • 함수 안에서 static를 붙이면 함수 안에 소속되어 있는게 아니라 데이터 영역에 있고 함수 내부에서만 접근 하는것처럼

    • 클래스 내부에 static로 선언을 한다면 데이터 영역에 존재하고 클래스 영역에서만 사용 가능하다.

// CEntity.h의 CEntity 클래스 내부,
public:
	// 1
	static UINT g_NextID;
  • private을 public로 공개 처리를 해버린다면 외부에서도 사용가능하다.
// CEntity.cpp
UINT CEntity::g_NextID = 0;
  • 오류가 안나게할려면 클래스는 선언과 구현을 분리해야되기때문에 선언은 저 위의 헤더에서 했고 구현은 .cpp파일 내부에 구현을 해놔야한다.
    • 정적 맴버를 사용할때는 선언과 구현을 분리해야한다.
// main.cpp의 메인함수 내부다.
    CEntity::g_NextID = 100;

  • 선언과 구현을 해놨고 public로 변경한다면 외부에서도 접근이 가능하다.
    • namespace로 범위지정연산자를 통해 접근하는것처럼 접근이 가능해진다.
  • private으로 다시 바꾼다면 당연히 외부에서 접근 불가능해진다.

static의 선언위치에 따른 케이스를 다뤘다.

  • 언제나 static이란 키워드가 정적이다라는 의미여서 선언된 곳에서 접근하는 그곳의 전용이 된다.

    1. 함수 내

    2. 파일

    3. 클래스

  • 암기할 필요없다. static키워드의 핵심 동작만 알면 된다.

CEntity클래스의 함수

	// 1
	// void SetID(UINT _id) { m_ID = _id; }
    // 2
	UINT GetID() { return m_ID; }
  • 1번처럼 아이디 새로 세팅할려는 함수는 불가능하다 const로 아이디를 막아두었기 떄문이다.

  • 2번처럼 아이디의 값을 보는것은 가능하다.

미리컴파일된 헤더에 string 추가.

// pch.h(미리컴파일된 헤더파일)
#include <string> // 문자열 전용 관리

// 1
vector<char>
string;
// 2
vector<wchar_t>
wstring;

// 3
using std::string;
using std::wstring;
  • 1번과 2번 둘다 자료형이 지정된 벡터 클래스다.

    • 템플릿이 아닌 둘다 자료형이 정해져있다.
  • vector의 문자열 전용 담당 클래스라 벡터에서 제공안해주는 문자열 operator을 추가로 더 제공해준다.

    • size()대신 length()를 사용한다 등등

CEntity 클래스의 맴버 추가.

	const UINT	m_ID; // 객체별 고유 ID 
	// 1
	wstring		m_strName;
  • ID는 고유해야하지만 이름은 똑같을수 있다.
  • 객체에 이름을 걸어주면 디버깅할떄 빠르게 정체 파악가능하다.
    • ID값본다고 확인이 바로 안되서
    • 특별해서 이름을 넣어두면 중단점 걸고 맴버 빠르게 확인할수 있고 비교 기준도 만들수 있다.
	void SetName(const wstring& _Name) { m_strName = _Name; }
	const wstring& GetName() { return m_strName; }
  • CEntity 클래스의 2번째 맴버는 이름 변경과 가져오는것 둘다 가능하다.
    • 인라인 함수로 처리했다.
      • 라인함수를 생성해제비용을 아끼면서 복사붙여넣기를한다.
        - 함수 호출비용의 이점이 있지만 거대한 함수를 인라인처리하면 너무 코드 용량이 올라가서 컴파일 속도가 저하되므로 간단한 함수에 인라인 함수로 많이 사용한다.
// main.cpp
    CEntity entity1;
    entity1.SetName(L"Entity 1");

    CEntity entity2;
    entity2.SetName(L"Entity 2");

    CEntity entity3;
    entity3.SetName(L"Entity 3");



  • 이름은 다르게줘도 되공 아이디는 순서대로 잘 나왔공 소멸자가 가상함수라 버츄얼 포인터 가상함수 포인터가 생성되었다.
// main.cpp
    int size = sizeof(CEntity);
  • CEntity클래스의 크기를 확인한다면
// CEntity.h 파일 내부
private:
	// 1
	static UINT g_NextID; // 특정 클래스 내에 맴버로 정적변수를 선언
private:		
	// 2
	const UINT	m_ID; // 객체별 고유 ID 
    // 3
	wstring		m_strName;
  • 1번의 크기는 데이터 영역이라 크기로 안나올것이고 2번 + 3번 + 가상함수테이블의 크기까지 합산해서 크기가 나온다.

간단한 크기 문제

class TestClass
{
public:
	int a;
};

class TestClassChild
	:public TestClass
{
public:
	int b;
};
  • 공부를 대충한 애들은 가상함수를 안붙이고 상속을 해놓으면 가상 함수 포인터의 크기까지 계산해버린짐난 실제 로는 계산하면 안된다,
    • TestClass 4바이트고 TestClassChild 8바이트다.
  • 가상함수가 포인터가 한개 이상 존재해야 가상함수 테이블의 크기를 계산한다.
class TestClass
{
public:
	int a;
public:
	TestClass()
	{

	}

	virtual ~TestClass()
	{

	}
};
  • 64비트 시스템: int a; (4바이트) + vtable 포인터 (8바이트) = 12바이트
  • 소멸자에 virtual키워드가 만약 없다면 vtable포인터가 없는 그냥 4바이트다.

CEntity는 최상위 클래스이므로 객체를 실제로는 생성했으면 안됐당.(추상화)

  • 순수 가상함수로 만들어야함으로써 이점 2가지
    1. 자식 클래스들에 구현할 목록을 제시한다
    2. 클래스 객체를 못 만들게 한다.
// CEntity.h의 순수 가상함수 제시.
public:
	virtual CEntity* Clone() = 0; 
  • Clone함수를 제시할것이다.

  • CEntity 클래스는 추상클래스이다.

    • CEntity를 상속받는 클래스들은 반드시 클론함수를 구현해야한다.
  • Clone함수 사용처

    • 자기자신을 복제해서 돌려주는 함수다.
    • 몬스터 클래스는 클론이 구현이 되었을것이다.(추상클래스를 상속받아서)
    • Clone함수는 생성된 객체.Clone하면 반환값으로 몬스터의 본인이랑 똑같은 복제본이 나오게한다.
    • 몬스터 클래스로 객체를 만들고 나면 세팅값을 만들어줘야하는데 이걸 객체를 만들어 줄떄마다 세팅값을 적어주는게 아니라 Clone함수를 통해 이미 세팅해둔 프로트타입으로 복제본을 만들면 된다.
      • 프로트타입(시제품) 패턴이다.
    • 오크 견본(프로트타입)을 만들어두고 오크 3마리 필요다고 하면 Clone함수를 3번 사용해서 필요한 곳에 뿌려주면 된다.

1차 24.01.19
2차 24.01.22
3차 24.01.23
4차 24.01.24
5차 24.01.25

0개의 댓글