[C/C++] 멤버 초기화 리스트(Member Initializer List), 위임 생성자(Delegating Constructor)

할랑말랑·2026년 3월 9일

C/C++

목록 보기
11/45

1. 멤버 초기화 리스트(Member Initializer List)

멤버 초기화 리스트는 생성자의 본문 { }이 실행되기전에 클래스의 멤버 변수들을 초기화 하기 위해 사용하는 특별한 문법이다.
생성자 정의에서 매개변수 목록 () 뒤에 : 콜론을 붙여 시작하며, 초기화할 멤버들을 쉼표 , 로 구분하여 나열한다.

  • 멤버 초기화 리스트 : 변수가 선언됨과 동시에 초기화
    ex) int a = 10;
  • 생성자 본문 : 변수가 선언되고 새로운 값으로 대입한다.
    ex) a = 10;

생성자 본문에 변수를 대입하지 않고, 멤버 초기화 리스트를 쓰는이유

  • 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 대입 연산자(=) 호출

2. 위임 생성자(Delegating Constructor)

한 생성자가 다른 생성자의 구현을 재사용할 수 있게 해주는 문법이다.
자신의 초기화 작업을 같은 클래스의 다른 생성자에게 맡기는 것

  • 생성자들 사이에 중복되는 코드를 제거하고, 초기화 로직을 한 곳으로 모아 유지보수성을 높이기 위함
  • 위임 생성자는 멤버 초기화 리스트를 사용하는 위치에, 자기 자신의 다른 생성자를 호출하는 구문을 넣습니다
#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;
    }
};

0개의 댓글