
절차지향 프로그래밍에서 벗어나 처음으로 C++ 객체 지향 프로그래밍(OOP)의 세계에 발을 들였다. 🐾 Player라는 부모 클래스를 만들고, 이를 상속받는 전사, 마법사 등 다양한 직업 클래스를 구현했다. 특히 부모 클래스의 포인터 하나로 모든 자식 객체를 다루는 다형성(Polymorphism)의 강력함을 체험할 수 있었다. 순수 가상 함수를 통해 자식 클래스가 반드시 특정 기능을 구현하도록 강제하는 멋진 설계도 경험했다.
new/delete를 이용한 동적 메모리 관리 익히기// main.cpp: 프로그램의 전체 흐름을 제어합니다.
#include <iostream>
#include "player.h"
#include "warrior.h"
#include "magician.h"
#include "thief.h"
#include "archer.h"
using namespace std;
int main() {
// Player* 타입의 포인터 변수.
// 이 포인터 하나로 Warrior, Magician 등 모든 자식 객체를 가리킬 수 있습니다. (다형성)
Player* player = nullptr;
string nickname;
int job_choice;
cout << "* 닉네임을 입력해주세요: ";
cin >> nickname;
// ... (직업 선택 UI) ...
cin >> job_choice;
// 사용자의 선택에 따라 해당하는 자식 클래스의 객체를 동적으로 생성합니다.
switch (job_choice) {
case 1: player = new Warrior(nickname); break;
case 2: player = new Magician(nickname); break;
case 3: player = new Thief(nickname); break;
case 4: player = new Archer(nickname); break;
default:
cout << "잘못된 입력입니다." << endl;
return 1;
}
// player 포인터는 Player 타입이지만, 실제로는 선택된 직업 객체를 가리키고 있습니다.
// 따라서 실제 객체에서 재정의(오버라이딩)된 attack() 함수가 호출됩니다.
player->attack();
player->printPlayerStatus();
// 'new'로 동적 할당한 메모리는 반드시 'delete'로 해제해야 메모리 누수를 막을 수 있습니다.
delete player;
return 0;
}
// player.h: 모든 직업의 기반이 되는 부모 클래스의 설계도입니다.
#pragma once // 헤더 파일의 중복 포함을 방지하는 지시어입니다.
#include <string>
using namespace std;
class Player {
public:
Player(string nickname); // 생성자: 객체가 생성될 때 호출됩니다.
// 순수 가상 함수: "= 0"은 이 함수가 본체가 없음을 의미합니다.
// 이 함수를 가진 Player 클래스는 '추상 클래스'가 되어 직접 객체를 만들 수 없습니다.
// 자식 클래스는 반드시 attack() 함수를 자신만의 방식으로 구현(오버라이딩)해야 합니다.
virtual void attack() = 0;
void printPlayerStatus();
protected: // protected 멤버는 자식 클래스에서만 접근이 가능합니다.
string job_name;
string nickname;
int HP, MP, power, defence;
};
// warrior.cpp: Warrior 클래스의 실제 동작을 구현합니다.
#include "warrior.h"
#include <iostream>
// Warrior 생성자
// ': Player(nickname)' 문법은 '초기화 리스트'라고 합니다.
// 자식 객체가 생성될 때, 먼저 부모 클래스의 생성자를 호출하여 기본 정보를 초기화합니다.
Warrior::Warrior(string nickname) : Player(nickname) {
// 부모로부터 물려받은 멤버 변수들을 전사 직업에 맞게 재설정합니다.
this->job_name = "전사";
this->HP = 150;
this->power = 20;
this->defence = 15;
}
// 부모 클래스의 순수 가상 함수 attack()을 재정의(오버라이딩)합니다.
void Warrior::attack() {
cout << "\n" << job_name << " '" << nickname << "' (이)가 검으로 강하게 내려칩니다! 휙!" << endl;
}
| 개념 | 설명 | 비고 |
|---|---|---|
| 클래스 | 객체를 만들기 위한 '설계도'. 데이터와 기능을 하나로 묶어 관리한다. | Player, Warrior |
| 상속 | 부모 클래스의 특징을 자식 클래스가 물려받아 코드를 재사용하는 기술. | class Warrior : public Player |
| 다형성 | 하나의 포인터가 여러 다른 타입의 객체를 가리키고, 상황에 맞게 동작하는 성질. | Player* p = new Warrior(); |
| 가상 함수 | virtual 키워드가 붙은 함수. 포인터 타입이 아닌 실제 객체 타입에 따라 호출될 함수가 결정된다. | virtual void attack() |
| 추상 클래스 | 순수 가상 함수를 하나 이상 가진 클래스. 객체 생성이 불가능하며 오직 상속을 위한 '미완성 설계도'로 쓰인다. | Player 클래스가 해당된다. |