26.05.08
C++ 객체지향 프로그래밍에서 자주 사용하는 개념들을 정리
게임 캐릭터 시스템을 예시로 이해해보자.
멤버 변수는 클래스 안에 들어있는 변수이다.
객체가 가지는 고유한 데이터를 저장한다.
예를 들어 RPG 캐릭터라면:
멤버 변수는 캐릭터의 "상태창" 같은 느낌이다.
닉네임 : 철수
HP : 100
MP : 50
공격력 : 30
이 데이터들이 전부 멤버 변수이다.
#include
using namespace std;
class Player
{
public:
string name;
int hp;
int attack;
};
int main()
{
Player player;
player.name = "철수";
player.hp = 100;
player.attack = 30;
cout << player.name << endl;
cout << player.hp << endl;
}
생성자는 객체가 만들어질 때 자동으로 호출되는 특별한 함수이다.
주로 초기값 설정에 사용한다.
게임에서 새 캐릭터를 생성하면 자동으로:
같은 기본값이 들어간다.
그 자동 세팅 담당이 생성자이다.
클래스 이름과 동일하다.
반환형이 없다.
객체 생성 시 자동 호출된다.
#include
using namespace std;
class Player
{
public:
string name;
int hp;
// 생성자
Player()
{
name = "초보자";
hp = 100;
cout << "캐릭터 생성 완료!" << endl;
}
};
int main()
{
Player player;
cout << player.name << endl;
cout << player.hp << endl;
}
클래스 내부 데이터를 안전하게 접근하기 위한 함수이다.
멤버 변수를 public으로 열어두면 어디서든 수정 가능하다.
이런 이상한 값도 들어갈 수 있다.
그래서 private으로 보호하고 Getter / Setter로 관리한다.
은행 금고와 비슷하다.
Getter → 잔액 조회
Setter → 입금/출금
직접 금고를 열게 하지 않는다.
#include
using namespace std;
class Player
{
private:
int hp;
public:
void SetHP(int value)
{
if (value >= 0)
{
hp = value;
}
}
int GetHP()
{
return hp;
}
};
int main()
{
Player player;
player.SetHP(100);
cout << player.GetHP() << endl;
}
기존 클래스를 물려받아 새로운 클래스를 만드는 기능이다.
공통 기능을 재사용할 수 있다.
"몬스터"라는 기본 틀이 있다고 생각해보자.
모두 몬스터라는 공통 특징을 가진다.
그래서 공통 기능을 부모 클래스에 만들고,
세부 특징만 자식 클래스에서 추가한다.
#include
using namespace std;
class Monster
{
public:
int hp;
void Attack()
{
cout << "몬스터 공격!" << endl;
}
};
class Goblin : public Monster
{
public:
void Skill()
{
cout << "독 공격!" << endl;
}
};
int main()
{
Goblin goblin;
goblin.hp = 50;
goblin.Attack();
goblin.Skill();
}
자식 클래스에서 반드시 재정의해야 하는 함수이다.
부모 클래스에서는 "형태만" 제공한다.
공통 규칙을 강제하기 위해 사용한다.
전사는 공격 방식이 다르고
마법사는 공격 방식이 다르고
궁수도 다르다
하지만 모두 "공격 함수" 는 반드시 있어야 한다.
virtual void Attack() = 0;
= 0 이 붙으면 순수 가상 함수이다.
#include
using namespace std;
class Character
{
public:
virtual void Attack() = 0;
};
class Warrior : public Character
{
public:
void Attack() override
{
cout << "검으로 공격!" << endl;
}
};
class Mage : public Character
{
public:
void Attack() override
{
cout << "파이어볼!" << endl;
}
};
int main()
{
Warrior warrior;
Mage mage;
warrior.Attack();
mage.Attack();
}
부모 클래스 포인터로 자식 객체를 삭제할 때
자식 소멸자까지 제대로 호출되게 만드는 소멸자이다.
동적 할당 사용 시 메모리 누수를 방지한다.
부모가 자식의 방 청소까지 같이 처리해주는 느낌이다.
가상 소멸자가 없으면 자식 쪽 정리가 누락될 수 있다.
###예시 코드
#include
using namespace std;
class Character
{
public:
virtual ~Character()
{
cout << "Character 소멸자 호출" << endl;
}
};
class Mage : public Character
{
public:
~Mage()
{
cout << "Mage 소멸자 호출" << endl;
}
};
int main()
{
Character* character = new Mage();
delete character;
}
##정리
개념과 역할
멤버 변수 : 객체의 데이터 저장
생성자 : 객체 생성 시 초기화
Getter / Setter : 데이터 보호 및 접근
상속 : 기존 클래스 기능 재사용
순수 가상 함수 : 자식 클래스 구현 강제
가상 소멸자 : 안전한 메모리 해제
객체지향은 처음에는 복잡해 보이지만,
"역할을 나누는 구조"라고 생각하면 이해하기 쉬웠다.
특히 게임 캐릭터 시스템에 적용해보니:
공통 기능은 부모 클래스
직업별 특징은 자식 클래스
처럼 구조를 나누는 이유를 이해할 수 있었다.
추가로 Getter / Setter를 통해
데이터를 안전하게 관리하는 이유도 알게 되었다.