생성자 초기화 리스트
Coddy C++ 여정의 객체 지향 프로그래밍 섹션에 포함된 레슨 — 104개 중 22번째.
이전 레슨에서 Player(std::string n, int h) : name(n), health(h) {}와 같은 콜론 구문을 보았습니다. 이것은 멤버 초기화 리스트라고 불리며, C++에서 멤버를 초기화하는 권장되는 방법입니다.
초기화 리스트는 생성자의 매개변수 목록 뒤에 콜론(:)으로 시작하여 나타납니다. 각 멤버는 쉼표로 구분되어 해당 값으로 직접 초기화됩니다:
class Rectangle {
int width;
int height;
const int id;
int& reference;
public:
Rectangle(int w, int h, int i, int& r)
: width(w), height(h), id(i), reference(r) {
// 생성자 본문 (비어 있을 수 있음)
}
};왜 생성자 본문에서의 대입 대신 초기화 리스트를 사용해야 할까요? 대입을 사용하면 멤버들이 먼저 기본 생성자로 생성된 후, 새로운 값이 대입됩니다. 초기화 리스트를 사용하면 멤버들이 올바른 값으로 직접 생성되므로, 더 효율적이며 때로는 필수적이기도 합니다.
특정 멤버들은 반드시 리스트를 사용하여 초기화되어야 합니다:
const멤버 - 생성 후에는 할당할 수 없습니다.
- 참조 멤버 - 초기화 시 반드시 바인딩되어야 합니다
- 기본 생성자가 없는 멤버
class Player {
const int maxHealth; // 반드시 초기화 리스트를 사용해야 함
std::string name;
public:
// 이 방식은 작동합니다
Player(int max, std::string n) : maxHealth(max), name(n) {}
// 이 방식은 컴파일되지 않습니다:
// Player(int max) { maxHealth = max; } // 오류!
};멤버는 초기화 리스트에 적힌 순서가 아니라 클래스에 선언된 순서대로 초기화됩니다. 혼동을 피하기 위해 항상 초기화 리스트를 선언 순서대로 작성하세요.
챌린지
쉬움멤버 초기화 리스트(member initializer list)가 언제, 왜 필수적인지 보여주는 게임 엔진용 설정 시스템을 구축해 보겠습니다. 초기화 리스트 구문을 사용하여 반드시 초기화해야 하는 멤버들을 가진 GameConfig 클래스를 만들 것입니다.
코드를 정리하기 위해 두 개의 파일을 생성합니다:
GameConfig.h: 게임 설정을 저장하는GameConfig클래스를 정의합니다. 클래스에는 다음이 포함되어야 합니다:const std::string gameName— 생성 후 변경할 수 없는 게임 제목const int maxPlayers— 생성 시 고정되는 최대 플레이어 수int& difficultyRef— 외부 난이도 설정에 대한 참조int screenWidth및int screenHeight— 디스플레이 설정을 위한 일반 멤버- 필요한 모든 매개변수를 받아 모든 멤버를 초기화 리스트를 사용하여 초기화하는 생성자. 초기화 리스트는 클래스에 멤버가 선언된 순서를 따라야 합니다.
- 다음 형식으로 설정을 출력하는
display()메서드:Game: <gameName> Max Players: <maxPlayers> Difficulty: <difficultyRef value> Resolution: <screenWidth>x<screenHeight>
main.cpp: 입력에서 설정 값을 읽고 GameConfig 객체를 생성합니다. 다음 작업이 필요합니다:- 입력에서 게임 이름(string), 최대 플레이어 수(int), 난이도(int), 너비(int), 높이(int)를 읽습니다. 각 값은 별도의 줄에 있습니다.
- 설정 객체가 참조할 난이도용 로컬
int변수를 생성합니다. - 초기화 리스트 생성자를 사용하여
GameConfig객체를 생성합니다. display()를 호출하여 초기 설정을 보여줍니다.- 난이도 변수를 직접 수정합니다 (2를 곱함).
"After difficulty change:"를 출력합니다.display()를 다시 호출하여 참조 멤버가 업데이트된 값을 반영하는지 확인합니다.
이 챌린지는 초기화 리스트가 왜 중요한지 강조합니다. const 멤버와 참조 멤버는 생성자 본문에서 할당될 수 없으며, 반드시 초기화 리스트에서 초기화되어야 합니다. 또한 참조 멤버는 원본 변수의 변경 사항이 설정 객체를 통해 어떻게 반영되는지 보여줍니다.
main.cpp에 #include "GameConfig.h"를 사용하여 헤더 파일을 포함하세요.
치트 시트
멤버 초기화 리스트(member initializer list)는 C++에서 클래스 멤버를 초기화하는 권장되는 방법입니다. 이는 생성자의 매개변수 목록 뒤에 콜론으로 시작하며, 각 멤버가 직접 초기화됩니다:
class Rectangle {
int width;
int height;
public:
Rectangle(int w, int h) : width(w), height(h) {
// 생성자 본문
}
};왜 초기화 리스트를 사용해야 할까요? 멤버가 기본 생성된 후 대입되는 대신 올바른 값으로 직접 생성되므로 더 효율적입니다.
특정 멤버의 경우 필수 사항입니다:
const멤버 - 생성 후에는 값을 대입할 수 없습니다- 참조(Reference) 멤버 - 초기화 시 반드시 바인딩되어야 합니다
- 기본 생성자가 없는 멤버
class Player {
const int maxHealth;
int& reference;
public:
// 올바름 - 초기화 리스트 사용
Player(int max, int& r) : maxHealth(max), reference(r) {}
// 오류 - 본문에서 const 또는 참조 멤버에 대입할 수 없음
// Player(int max) { maxHealth = max; }
};중요: 멤버는 초기화 리스트에 나열된 순서가 아니라 클래스에 선언된 순서대로 초기화됩니다. 항상 초기화 리스트를 선언 순서대로 작성하세요.
직접 해보기
#include <iostream>
#include <string>
#include "GameConfig.h"
using namespace std;
int main() {
// 입력값 읽기
string gameName;
getline(cin, gameName);
int maxPlayers;
cin >> maxPlayers;
int difficulty;
cin >> difficulty;
int width;
cin >> width;
int height;
cin >> height;
// TODO: 초기화 리스트 생성자를 사용하여 GameConfig 객체 생성
// 생성자는 gameName, maxPlayers, difficulty (참조로 전달), width, height를 전달받아야 함
// TODO: display()를 호출하여 초기 설정 표시
// TODO: difficulty 변수를 직접 수정 (2를 곱함)
// TODO: "After difficulty change:" 출력
// TODO: display()를 다시 호출하여 업데이트된 설정 표시
return 0;
}
이 레슨에는 짧은 퀴즈가 포함되어 있습니다. 레슨을 시작해 문제를 풀고 진행 상황을 기록하세요.