멤버 초기화 리스트는 생성자의 본문 { }이 실행되기전에 클래스의 멤버 변수들을 초기화 하기 위해 사용하는 특별한 문법이다.
생성자 정의에서 매개변수 목록 () 뒤에 : 콜론을 붙여 시작하며, 초기화할 멤버들을 쉼표 , 로 구분하여 나열한다.
- Const 멤버 변수 : Const 변수는 선언과 동시에 초기화를 해야 사용할 수 있기 때문에 멤버 초기화 리스트에서만 초기화할 수 있다.
- 참조(&) 변수 : 참조 변수 역시 const와 마찬가지로 선언과 동시에 특정 대상을 가리켜야한다.(참조자는 가리키는 변수의 또 다른 이름이기 때문 - 같은 메모리 주소를 가리킨다.)
#include <string> #include <iostream> using namespace std; class Person { private: const int id; // 1. const 멤버 string& name; // 2. 참조 멤버 int age; public: // 멤버 초기화 리스트를 사용한 올바르고 효율적인 방법 Person(int personId, string& personName, int personAge) : id(personId), name(personName), age(personAge) // 'id'와 'name'은 여기서만 초기화 가능 { cout << "Person 객체가 '초기화' 되었습니다." << endl; } };
- 기본 생성자가 없는 클래스 타입의 멤버 변수 : 멤버 변수가 다른 클래스의 객체인데, 그 클래스의 기본 생성자가 없다면 생성자 본문에 진입하기 전에 컴파일러가 해당 멤버를 자동으로 생성할 방법이없다. 그래서 멤버 초기화 리스트로 명시적으로 인자를 전달하여 생성자를 호출해줘야 한다.
#include <iostream> #include <string> using namespace std; class Player { private: string name; public: Player(string p_name) : name(p_name) { cout << name << " 선수 객체 생성!" << endl; } }; class Team { private: Player captain; string teamName; public: Team(string t_name, string c_name) : captain(c_name), teamName(t_name) { } };
- 일반적인 클래스 타입 멤버의 경우, 초기화 리스트를 사용하면 생성자가 한 번만 호출됩니다(원하는 값으로). 하지만 생성자 본문에서 대입하면, 기본 생성자가 먼저 호출된 후 대입 연산자(operator=)가 또 호출되어 비효율적일 수 있습니다.
#include <iostream> #include <string> using namespace std; class Log { public: Log() { std::cout << "Log 기본 생성자 호출" << std::endl; } Log(const std::string& s) { std::cout << "Log(string) 생성자 호출" << std::endl; } Log& operator=(const Log& other) { std::cout << "Log 대입 연산자(=) 호출" << std::endl; return *this; } }; class Message { private: Log log; public: Message() { std::cout << "Message 생성 (본문 대입 방식):" << std::endl; log = Log("some_log_message"); } }; int main() { Message msg; } // Log 기본 생성자 호출 // Message 생성 (본문 대입 방식) // Log(string) 생성자 호출 // Log 대입 연산자(=) 호출
한 생성자가 다른 생성자의 구현을 재사용할 수 있게 해주는 문법이다.
자신의 초기화 작업을 같은 클래스의 다른 생성자에게 맡기는 것
#include <iostream>
#include <string>
using namespace std;
class Rectangle
{
private:
int x, y, width, height;
public:
// 모든 초기화를 책임지는 생성자
Rectangle(int x_val, int y_val, int w, int h)
: x(x_val), y(y_val), width(w), height(h) // 멤버 초기화 리스트 사용
{
// 복잡한 유효성 검사나 초기화 로직이 여기에 모여있다고 가정
if (w <= 0 || h <= 0)
{
// 유효성 검사 실패 시의 처리
}
}
// 위치 정보 없이 크기만 받는 생성자
Rectangle(int w, int h)
: Rectangle(0, 0, w, h) // <-- 위임 생성자!
{
cout << "크기만 받는 생성자 호출됨." << endl;
}
// 기본 생성자
Rectangle()
: Rectangle(0, 0, 1, 1) // <-- 위임 생성자!
{
cout << "기본 생성자 호출됨." << endl;
}
};