converting_constructor — 변환 생성자

converting_constructor — 변환 생성자

explicit 지정자 없이 선언되고, 단일 매개변수로 호출될 수 있는 생성자를 **변환 생성자(converting constructor)**라고 불러요. 이 생성자는 인자 타입에서 클래스 타입으로의 암시적 변환을 정의해요.

객체를 만들 때 A a = 1;처럼 대입 형태로 초기화하면, 컴파일러가 암시적으로 intA라는 타입으로 바꿔줄 수 있는지 살펴봐요. 변환 생성자가 있으면 이런 변환이 자연스럽게 일어나요. 단, explicit 생성자는 이런 암시적 변환에 쓰이지 않아요.

출처: cppreference

본문

explicit으로 선언되지 않고 단일 매개변수로 호출될 수 있는 생성자를 변환 생성자라고 불러요.

explicit 생성자는 직접 초기화(direct initialization)에서만 고려돼요. 여기에는 static_cast 같은 명시적 변환이 포함돼요. 반면 변환 생성자는 복사 초기화(copy initialization)에서도 고려되는데, 이는 사용자 정의 변환 시퀀스(user-defined conversion sequence)의 일부로 동작하기 때문이에요.

변환 생성자는 인자 타입(있다면)에서 클래스 타입으로의 암시적 변환을 지정한다고 말해요. explicit이 아닌 사용자 정의 변환 함수도 마찬가지로 암시적 변환을 지정한다는 점을 기억하세요.

암시적으로 선언되거나 사용자 정의된 비-explicit 복사 생성자와 이동 생성자도 변환 생성자예요.

예제 (Example)

struct A
{
    A() { }         // 변환 생성자 (C++11 이후)
    A(int) { }      // 변환 생성자
    A(int, int) { } // 변환 생성자 (C++11 이후)
};

struct B
{
    explicit B() { }
    explicit B(int) { }
    explicit B(int, int) { }
};

int main()
{
    A a1 = 1;      // OK: 복사 초기화가 A::A(int) 선택
    A a2(2);       // OK: 직접 초기화가 A::A(int) 선택
    A a3{4, 5};    // OK: 직접 목록 초기화가 A::A(int, int) 선택
    A a4 = {4, 5}; // OK: 복사 목록 초기화가 A::A(int, int) 선택
    A a5 = (A)1;   // OK: 명시적 캐스트가 static_cast 수행, 직접 초기화

//  B b1 = 1;      // 오류: 복사 초기화는 B::B(int) 를 고려하지 않음
    B b2(2);       // OK: 직접 초기화가 B::B(int) 선택
    B b3{4, 5};    // OK: 직접 목록 초기화가 B::B(int, int) 선택
//  B b4 = {4, 5}; // 오류: 복사 목록 초기화가 explicit 생성자를 선택함
                   //        B::B(int, int)
    B b5 = (B)1;   // OK: 명시적 캐스트가 static_cast 수행, 직접 초기화
    B b6;          // OK, 기본 초기화
    B b7{};        // OK, 직접 목록 초기화
//  B b8 = {};     // 오류: 복사 목록 초기화가 explicit 생성자를 선택함
                   //        B::B()

    [](...){}(a1, a4, a4, a5, b5); // "unused variable" 경고 억제
}

핵심 차이를 보여주는 예제예요. A처럼 explicit이 없는 생성자는 = 1이나 = {4, 5} 같은 복사 초기화에서도 암시적으로 선택돼요. 반면 B처럼 explicit 생성자를 쓰면 복사 초기화에서 오류가 나고, 직접 초기화(B b2(2)이나 B b3{4,5})에서만 쓸 수 있어요. 이렇게 하면 의도치 않은 암시적 변환을 막을 수 있어요.

더 알아보기 (Learn more)

cppreference