오늘의 목표

  • 아침 코드카타
  • 챕터 2-5 숙제
  • 챕터 2 과제 2번
  • 3-1 강의 수강
  • 3-1 복습

 

추가 목표:

3-2 강의 수강

3-2 강의 복습


 

1. C++ 문법 2주차 숙제

영화 데이터를 관리하는 프로그램

 

문제

rating값에 따라서 영화를 정렬하는 RatingSorter class 작성 중 

class RatingSorter : public MovieProcessor{
public:

	bool compareMovies(Movie& a, Movie& b) {
		return a.rating > b.rating;
	}

	void process(vector<Movie>& movies) {
		//벡터 내림차순 정렬
		sort(movies.begin(), movies.end(), compareMovies);
		
		for (auto m : movies) {
			cout << "제목: " << m.title << ", 평점: " << m.rating << '\n';
		}
		
	}

	
};

 

오류

'RatingSorter::compareMovies': 비표준 구문입니다. '&'를 사용하여 멤버 포인터를 만드세요.

'sort': 일치하는 오버로드된 함수가 없습니다.

 

해결 과정

이는 함수 compareMovies가 class 내에서 정적 멤버 변수가 아닌 일반 멤버 변수로 선언되었기 때문에 발생한다.

일반 멤버 변수의 경우 숨겨진 this 포인터를 반환하기 때문에 인수 (Movie a, Movie b) 두 가지를 받고자 하는 sort 함수에 맞지 않다. this까지 합쳐서 3개의 인수를 가지게 되기 때문이다.

 

이 경우 함수를 static(정적)으로 선언하면 해결된다. 정적 멤버 함수의 경우 특정 객체에 종속되지 않으므로 this 포인터를 필요로 하지 않기 때문이다.

class RatingSorter : public MovieProcessor{
public:

	static bool compareMovies(const Movie& a, const Movie& b) {
		return a.rating > b.rating;
	}

	void process(vector<Movie>& movies) {
		//벡터 내림차순 정렬
		sort(movies.begin(), movies.end(), compareMovies);
		
		for (const auto& m : movies) {
			cout << "제목: " << m.title << ", 평점: " << m.rating << '\n';
		}
	}
	
};

 

 

<출력 결과>

1. 영화 목록 출력
영화 목록:
제목: Inception, 평점: 9
제목: Interstellar, 평점: 8.6
제목: The Dark Knight, 평점: 9.1
제목: Memento, 평점: 8.4

2. 영화 검색 (예: Interstellar)
영화 제목: Interstellar, 평점: 8.6

3. 평점 기준 정렬 및 출력
제목: The Dark Knight, 평점: 9.1
제목: Inception, 평점: 9
제목: Interstellar, 평점: 8.6
제목: Memento, 평점: 8.4

4. 평점 8.5 이상인 영화 필터링 및 출력
평점 8.5 이상인 영화 목록:
제목: The Dark Knight, 평점: 9.1
제목: Inception, 평점: 9
제목: Interstellar, 평점: 8.6

정상적으로 정렬되고 연산됨을 확인할 수 있다. 

 


2. 챕터 2 과제 2번

 

작성한 코드

#include <iostream>

using namespace std;


class Player {
public:
	virtual void attack() = 0;
};

class Warrior : public Player {
	void attack() override {
		cout << "검을 휘두릅니다!" << "\n";
	}
};

class Magician : public Player {
	void attack() override {
		cout << "마법 화살을 쏩니다!" << "\n";
	}
};

class Thief : public Player {
	void attack() override {
		cout << "기습 공격을 합니다!" << "\n";
	}
};

class Archer : public Player {
	void attack() override {
		cout << "독 화살을 쏩니다!" << "\n";
	}
};



int main() {
	Player* player = nullptr;
	int choice;

	cout << "            <직업 메뉴>" << "\n";
	cout << "-----------------------------------" << "\n";
	cout << "1. 전사" << "\n";
	cout << "2. 마법사" << "\n";
	cout << "3. 도적" << "\n";
	cout << "4. 궁수" << "\n";

	cout << "\n번호를 입력하세요: \n";
	cin >> choice;

	// 존재하지 않는 선택지를 입력하면 다시 입력하게 하는 로직 추가하면 좋을 듯

	switch (choice) {
	case 1:
		player = new Warrior();
		break;
	case 2:
		player = new Magician();
		break;
	case 3:
		player = new Thief();
		break;
	case 4:
		player = new Archer();
		break;
	default:
		player = new Warrior(); // 오류를 방지하여 default값을 전사로 선택하게 한다.
		break;
	}

	player->attack(); // 다형성: 재정의된 함수 호출
}

 

[출력 결과]

            <직업 메뉴>
-----------------------------------
1. 전사
2. 마법사
3. 도적
4. 궁수

번호를 입력하세요:
1
검을 휘두릅니다!

 

정상 작동 확인.

 

++

존재하지 않는 번호 입력 시 다시 입력하게 하는 코드를 추가로 구현

 

1. 가장 간단한 로직

가장 간단하게 이것을 코딩하는 방법은 사용자가 입력한 choice가 1, 2, 3, 4에 해당하는지 직접 확인하는 방식이다.

/ 가장 간단한 로직 (1~4에 해당하지 않으면 재입력)
	while (choice != 1 && choice != 2 && choice != 3 && choice != 4) {
		cout << "존재하지 않는 번호입니다. 다시 입력해주세요: ";
		cin >> choice;
	}

 

2. 변화하는 선택지에 따라 유동적으로 수용 가능한 로직

vector에 직업들을 저장해놓고 0미만 혹은 vector.size() 초과에 해당하는 선택지가 입력될 경우 재입력시키기

직업 추가 및 제거 시에도 수정하지 않아도 되어서 편하다.

// 선택지가 추가/삭제될 경우 유동적으로 반영되는 로직 
// 직업을 저장하는 vector 따로 선언
vector<string> classes;
classes.push_back("전사");
classes.push_back("마법사");
classes.push_back("도적");
classes.push_back("궁수");

while (choice < 1 || choice > classes.size()) {
	cout << "존재하지 않는 번호입니다. 다시 입력해주세요: ";
	cin >> choice;
}

 

<출력 결과>

            <직업 메뉴>
-----------------------------------
1. 전사
2. 마법사
3. 도적
4. 궁수

번호를 입력하세요:
5
존재하지 않는 번호입니다. 다시 입력해주세요: -1
존재하지 않는 번호입니다. 다시 입력해주세요: 0
존재하지 않는 번호입니다. 다시 입력해주세요: 4
독 화살을 쏩니다!

 

답안 확인, 고칠 점

Player* player = new Archer(); 등으로 선언한 Player 포인터의 메모리를 해제해주지 않았다.

항상 new로 선언한 뒤 delete를 바로 작성하는 습관을 들일 것.

 

 

지금까지는 최소한의 기능만 맞춰 구현했다.

 

과제에서 제공해준 코드 스니펫과 함께 도전 기능을 구현해보겠다.

 

코드 스니펫에 맞춰 지금까지 구현한 기능 + 다양한 스탯 초기화를 구현해준다.

출력 결과는 다음과 같다.

* 닉네임을 입력해주세요: jay
<전직 시스템>
jay님, 환영합니다!
* 원하시는 직업을 선택해주세요.
1. 전사
2. 마법사
3. 도적
4. 궁수
선택: 3
기습 공격을 합니다!
------------------------------------
* 현재 능력치
닉네임: jay
Lv. 1
HP: 10
MP: 10
공격력: 5
방어력: 5
정확도: 5
속도: 5
------------------------------------

 

 

 


 

오늘의 배운 점

 

코딩 TIP

1. 파생 클래스의 생성자에서 인수를 받아 기본 클래스의 생성자에게 전달할 때, 기본 생성자를 소환하면 된다.

// class A 기본 생성자, class B 파생 생성자
class A{
	A(int n) : num(n){}
protected: // 파생 클래스에서 접근 가능 
	int num;
};

class B : public A{
public:
	B(int n) : A(n){} 
    /*
    그대로 기본 클래스의 생성자를 소환해주면 자동으로 num에 저장이 된다.
    따로 변수를 선언할 필요 x
    */ 
};

 

 

2. 헤더 작성

헤더 두 개가 서로를 #include 하게 될 경우 순환 참조가 이루어져 문제가 생길 수 있다.

이 경우 필요한 함수를 전방 선언하여 문제가 없도록 해야한다.

 

전방 선언

클래스나 함수의 전체 정의를 제공하지 않고, 그 존재를 컴파일러에게 알려주는 것.

헤더 파일에서 불필요한 #include를 없앨 수 있다.

헤더 파일끼리 서로를 참조해서 생기는 순환 의존성을 해결할 수 있다.

'Unreal5 공부 > TIL' 카테고리의 다른 글

2026/03/25 TIL  (0) 2026.03.25
2026/03/24 TIL  (0) 2026.03.24
2026/03/20 TIL  (0) 2026.03.20
2026/03/19 TIL  (0) 2026.03.19
2026/03/18 TIL  (0) 2026.03.18

+ Recent posts