TIL 2026-03-17
TIL 2026-03-17
2026.03.17 | C++ 과제 1~3 정리
📗 과제 1 — 상태창 구현 (C++ 기초)
핵심 개념
| 개념 | 내용 |
|---|---|
| 배열 | int stat[4] → stat[0]=HP, stat[1]=MP, stat[2]=공격력, stat[3]=방어력 |
| 포인터 매개변수 | void setPotion(int count, int* p_HPPotion, int* p_MPPotion) |
| while + switch | 0번 입력 전까지 메뉴 반복 출력 |
| 입력 유효성 검사 | HP·MP > 50, 공격력·방어력 > 0 강제 |
핵심 코드
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
// 포인터로 값 직접 수정
void setPotion(int count, int* p_HPPotion, int* p_MPPotion) {
*p_HPPotion = count;
*p_MPPotion = count;
}
// 무한루프 메뉴
while (1) {
cin >> choice;
if (choice == 0) break;
switch (choice) {
case 1:
if (HPPotion <= 0) { cout << "포션이 부족합니다." << endl; continue; }
stat[0] += 20;
HPPotion--;
break;
}
}
배운 점
*역참조로 포인터가 가리키는 값을 직접 변경하는 방식 이해const int SIZE = 4;—const키워드로 상수 선언- 포션이 0개일 때
continue로 루프 재시작하는 흐름 제어
📗 과제 2 — 전직 시스템 & 전투 시스템 (OOP)
핵심 개념
| 개념 | 설명 |
|---|---|
| 추상 클래스 | virtual void attack() = 0 → 순수 가상 함수로 자식 구현 강제 |
| 상속 | class Warrior : public Player |
| 다형성 | Player* player = new Warrior(nick) → 부모 포인터로 자식 동작 |
| 가상 소멸자 | virtual ~Player() → 자식 객체 안전 소멸 |
| 오버로딩 | attack() / attack(Monster*) 두 버전 공존 |
파일 구조
1
2
3
4
5
6
7
assignment-2/
├── player.h / player.cpp # 추상 기반 클래스
├── warrior.h / warrior.cpp # 전사 (HP 150, 검 공격)
├── magician.h / magician.cpp # 마법사 (MP 150, 마법 화살)
├── thief.h / thief.cpp # 도적 (5회 연속 공격)
├── archer.h / archer.cpp # 궁수 (3회 연속 공격)
└── monster.h / monster.cpp # 몬스터 (HP 10, 공격력 30)
핵심 코드
1
2
3
4
5
6
7
8
9
10
11
12
// 다형성 활용
Player* player = nullptr;
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;
}
player->attack(); // 직업에 맞는 attack() 자동 호출
player->attack(monster); // 오버로딩된 버전 호출
if (player != nullptr) delete player; // 메모리 해제
배운 점
- 순수 가상 함수 :
= 0으로 자식이 반드시 구현하도록 강제 — 추상 클래스로 만듦 - 전방 선언(Forward Declaration) :
class Monster;헤더에서 순환 참조 방지 - LNK2019 오류 :
cl.exe빌드 시.cpp파일을 하나만 넣으면 다른 심볼을 찾지 못함 → 모든.cpp를 함께 전달해야 함
📗 과제 3 — 인벤토리 시스템 (템플릿 & 메모리 관리)
핵심 개념
| 개념 | 설명 |
|---|---|
| 템플릿 | template <typename T> — 타입에 무관한 범용 클래스 |
| 동적 배열 | T* pItems_ = new T[capacity_] |
| 깊은 복사 | 복사 생성자에서 new T[]로 새 메모리 할당 후 데이터 복사 |
| 자동 확장(Resize) | 꽉 차면 capacity_ * 2 크기로 재할당 |
| std::sort | sort(pItems_, pItems_ + size_, compareItemsByPrice) |
핵심 코드
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
template <typename T>
class Inventory {
public:
Inventory(int capacity = 5); // Default Argument
Inventory(const Inventory<T>& other); // 복사 생성자 (깊은 복사)
~Inventory() { delete[] pItems_; pItems_ = nullptr; }
bool AddItem(const T& item); // 꽉 차면 Resize() 자동 호출
bool RemoveLastItem(); // size_-- 만으로 논리적 제거
void SortItems(); // std::sort 활용
Inventory<T>& Assign(const Inventory<T>& other); // 대입 깊은 복사
private:
void Resize(int newCapacity);
T* pItems_;
int capacity_, size_;
};
Resize 내부 동작 흐름
1
2
3
4
5
1. new T[newCapacity] → 새 메모리 할당
2. 기존 데이터 복사 → for (i < size_) newItems[i] = pItems_[i]
3. delete[] pItems_ → 기존 메모리 해제
4. pItems_ = newItems → 포인터 교체
5. capacity_ 갱신
배운 점
- 얕은 복사 vs 깊은 복사 : 기본 복사는 포인터 주소만 복사 → 소멸 시 double free 발생.
new로 새 공간을 만들어야 안전 - Default Argument : 생성자를 여러 개 만들지 않고
Inventory(int capacity = 5)하나로 통합 std::vector의 원리 : 이번Inventory<T>가 바로vector의 핵심 동작 방식 (push_back,resize, 깊은 복사)- Unreal의
TArray도 같은 원리로 동작
오늘 해결한 트러블슈팅
| 문제 | 원인 | 해결 |
|---|---|---|
한글 깨짐 (?꾩궗) | 파일이 EUC-KR 인코딩, VS가 BOM 없이 CP949로 읽음 | UTF-8 BOM 추가 + /utf-8 컴파일 플래그 |
| LNK2019 링커 오류 | cl.exe에 Main.cpp만 전달 | 모든 .cpp 파일을 함께 컴파일 |
| 솔루션 용량 과다 | .vs/, Debug/, .obj 등 빌드 산출물 추적됨 | .gitignore에 패턴 기반 규칙 추가, 캐시 삭제 |
언리얼 엔진과의 연결고리
- 과제 1 → 게임 오브젝트 상태 관리의 기초 (HP바, 버프 시스템)
- 과제 2 →
AActor/APawn상속 구조,UFUNCTION오버라이딩 - 과제 3 →
TArray<T>내부 원리 이해, 메모리 관리 역량
이 기사는 저작권자의 CC BY 4.0 라이센스를 따릅니다.