변환 생성자는 매개변수가 기본 자료형 하나인 생성자를 말한다. 이 변환 생성자의 문제점은 사용자와 의도와 별개로 컴파일러가 암시적으로 호출할 수 있다는 점이다.
class Test {
private:
int m_num;
public:
Test() {}
Test(int num) : m_num(num) {} // 변환 생성자
Test(const Test& t) : m_num(t.m_num) {}
int PrintNum() const { return m_num; }
};
void Func(Test t) { cout << t.PrintNum() << endl; }
int main() {
Func(5);
}
위의 Func(5);
에서 Func()
는 매개변수가 Test
사용자 정의 타입이지만, 암시적으로 변환 생성자가 호출이 되어 아래와 같이 변환되어 컴파일된다.
Func(Test(5));
때문에 의도치 않은 인자를 전달했을 때도 컴파일러가 암시적 변환을 하여 컴파일 에러가 발생하지 않아 잘못된 부분을 찾기 힘들 수 있다.
이러한 현상을 막기 위해 존재하는 키워드가 explicit
이다. explicit
키워드를 사용하면 원하지 않는 암시적 변환을 명시할 수 있다.
class Test {
private:
int m_num;
public:
Test() {}
explicit Test(int num) : m_num(num) {} // 변환 생성자
Test(const Test& t) : m_num(t.m_num) {}
int PrintNum() const { return m_num; }
};
void Func(Test t) { cout << t.PrintNum() << endl; }
int main() {
Func(5); // 컴파일 에러
}
Test
클래스의 Test(int num)
를 explicit
으로 선언하여 기본 자료형인 int
가 Test
로 변환하는 것을 막을 수 있다.
또한 해당 기본 자료형의 생성자가 복사 생성자로 호출되는 것을 막을 수 있다.
Test t = 5; // 컴파일 에러
Test t(5); // 가능
첫 번째의 경우는 5를 대입하는 것으로 받아들이기 때문에 복사 생성자가 호출되어 컴파일 에러가 발생하지만 두 번째의 경우와 같이 명시적으로 생성자를 호출하는 것은 가능하다.