C++ 초급 - 8. 객체지향 프로그래밍 (6 - explicit 생성자 (C++11))

2025. 2. 22. 16:53프로그래밍 언어/C++

📌 8.6 explicit 생성자 (C++11)

C++에서는 암시적 변환(Implicit Conversion)으로 인해 예기치 않은 객체 변환이 발생할 수 있다.
이를 방지하기 위해 explicit 키워드를 생성자 앞에 붙이면, 암시적 변환을 금지하고 명시적 변환만 허용할 수 있다.
이러한 기능을 활용하면 코드의 안전성을 높이고, 예측하지 못한 동작을 방지할 수 있다.


📌 1. 암시적 변환(Implicit Conversion)의 문제점

🔹 (1) 암시적 변환이란?

  • C++에서는 단일 인자를 받는 생성자가 있을 경우, 해당 타입의 값을 자동 변환하여 객체를 생성할 수 있음.
  • 즉, 클래스 객체가 명시적으로 생성되지 않아도 암시적으로 변환되어 객체가 만들어지는 문제가 발생할 수 있음.

💡 예제: 암시적 변환으로 발생하는 문제

#include <iostream>

class Distance {
private:
    int meters;

public:
    Distance(int m) {  // ❌ explicit 미사용 → 암시적 변환 허용
        meters = m;
        std::cout << "Distance 객체 생성됨! (" << meters << "m)" << std::endl;
    }

    void show() { std::cout << "거리: " << meters << "m" << std::endl; }
};

int main() {
    Distance d1 = 10;  // ✅ int → Distance 변환 (암시적 변환 발생)
    d1.show();

    return 0;
}

🔹 출력 결과

Distance 객체 생성됨! (10m)
거리: 10m

💡 설명

  • Distance d1 = 10; → ✅ int 값이 Distance 객체로 변환됨 (암시적 변환 발생).
  • 그러나, 개발자가 명확하게 Distance d1(10);로 작성하지 않았음에도 객체가 생성됨.
  • 이로 인해 의도하지 않은 변환이 발생할 위험이 있음.

📌 2. explicit 키워드를 사용하여 변환 방지

🔹 (1) explicit 키워드란?

  • 암시적 변환을 막고, 명시적 변환만 허용하는 키워드.
  • 생성자 앞에 explicit을 붙이면, 암시적 변환이 금지되고, 명시적 변환만 가능해짐.

💡 예제: explicit 키워드 적용

#include <iostream>

class Distance {
private:
    int meters;

public:
    explicit Distance(int m) {  // ✅ explicit 사용 → 암시적 변환 방지
        meters = m;
        std::cout << "Distance 객체 생성됨! (" << meters << "m)" << std::endl;
    }

    void show() { std::cout << "거리: " << meters << "m" << std::endl; }
};

int main() {
    // Distance d1 = 10;  // ❌ 컴파일 오류 발생! (암시적 변환 금지됨)
    Distance d2(10);  // ✅ 명시적 변환은 가능
    d2.show();

    return 0;
}

🔹 출력 결과

Distance 객체 생성됨! (10m)
거리: 10m

🔹 컴파일 오류 메시지 (만약 Distance d1 = 10;을 실행했다면)

error: conversion from ‘int’ to non-scalar type ‘Distance’ requested

💡 설명

  • explicit 키워드를 추가하면 Distance d1 = 10; 같은 암시적 변환이 금지됨.
  • 대신, 명시적으로 Distance d2(10);와 같이 작성해야만 객체를 생성할 수 있음.

📌 3. 예제 및 활용법

🔹 (1) 단일 인자 생성자에서 explicit 적용 여부에 따른 차이점

  • 단일 인자 생성자는 암시적 변환이 가능하므로, explicit 키워드를 사용하면 안전성이 증가함.
  • 암시적 변환을 허용해야 하는 경우, explicit을 제거할 수 있음.

💡 예제: explicit 유무에 따른 차이점

#include <iostream>

class A {
public:
    explicit A(int x) { std::cout << "A 생성자 호출! 값: " << x << std::endl; }
};

class B {
public:
    B(int x) { std::cout << "B 생성자 호출! 값: " << x << std::endl; }
};

int main() {
    // A a1 = 5;  // ❌ 컴파일 오류 (explicit이 적용되어 암시적 변환 불가)
    A a2(5);  // ✅ 명시적 변환만 가능

    B b1 = 5;  // ✅ 암시적 변환 허용됨 (explicit 없음)
    B b2(5);   // ✅ 명시적 변환 가능

    return 0;
}

🔹 출력 결과

A 생성자 호출! 값: 5
B 생성자 호출! 값: 5
B 생성자 호출! 값: 5

💡 설명

  • A 클래스는 explicit 생성자를 사용했으므로 암시적 변환이 금지됨 (A a1 = 5; 컴파일 오류).
  • B 클래스는 explicit이 없으므로 암시적 변환(B b1 = 5;)이 가능.

🔹 (2) explicit을 사용해야 하는 경우

상황  explicit 필요 여부
암시적 변환이 원치 않는 경우 ✅ explicit을 사용하여 강제 변환 방지
단일 인자 생성자가 여러 개 있는 경우 ✅ explicit을 사용하여 혼란 방지
객체를 특정 연산에서만 명시적으로 생성해야 하는 경우 ✅ explicit을 활용하여 제어

💡 예제: explicit을 사용해야 하는 경우

class Time {
public:
    explicit Time(int minutes) {  // ✅ 암시적 변환 방지
        std::cout << "시간: " << minutes << "분" << std::endl;
    }
};

int main() {
    // Time t = 30;  // ❌ 오류! (암시적 변환 금지)
    Time t(30);  // ✅ 명시적 변환 가능
}

🔹 출력 결과

시간: 30분

📌 4. 정리

개념 설명
암시적 변환(Implicit Conversion) 단일 인자 생성자가 있을 경우, 해당 타입의 값이 객체로 변환될 수 있음
암시적 변환의 문제점 의도하지 않은 객체 변환 발생 가능 (Class obj = 10;)
explicit 키워드의 역할 암시적 변환을 방지하고, 명시적 변환만 허용
explicit 적용 시 특징 Class obj(10);만 허용, Class obj = 10;은 허용되지 않음
사용해야 하는 경우 변환이 명확해야 하거나, 불필요한 자동 변환을 방지할 때