티스토리 툴바


C++ 에서 사용하는 Explicit 키워드에 대해 알아봅니다.

먼저 이를 설명하기 전에 C++에서의 implicit type conversion에 대해 알아보고 넘어가는 게 먼저일 듯 합니다. 우리말로는 묵시적 형변환이라는 용어로 익숙할텐데요. 가령 아래와 같은 코드가 있다고 해보죠.

    1 short a = 2000;

    2 int b;

    3 b = a;

위 코드는 아무 문제가 없습니다. short 형을 int 형으로 변환해 준 거라, 반대의 경우에서 발생할 수 있는 데이터의 손실도 없습니다. 많은 프로그래머들이 종종 사용하는 방법입니다. 다만 여기서 알아두어야 할 것은 이런 묵시적 형 변환은 C++ 언어 차원에서 구현해 둔 것이기 때문에, short 나 int 같은 primitive type 뿐만 아니라, 생성자나 연산자 함수에서도 이런 현상이 동일하게 적용될 수 있다는 것입니다. 

잠깐 눈을 돌려, 이번에는 명시적인 형 변환을 살펴봅시다. 명시적으로 형 변환을 하는 방법에는 두 가지가 있습니다.  하나는 C 스타일로 하는 것. 다른 하나는 함수 타입으로 하는 것입니다. 

아래 코드를 보시죠. 

    1 short a = 2000;

    2 int b;

    3 b = (int)a;  //C-like cast notation

    4 b = int(a);  //functional notation


위의 3, 4번째 라인은 같은 효과를 가지고 있습니다. 함수타입으로 형변환하는 것은 C++에서 새롭게 지원되는 기능입니다. 두 라인 모두 short 형의 변수 a를 integer 형의 변수 b로 명시적으로 형 변환 하는 것입니다. 이 두 가지 방법도 앞에서 언급한 것처럼 primitive 타입 뿐 아니라 클래스 객체에도 동일하게 적용될 수 있습니다. 

가령 예를 들어, 아래와 같은 코드가 있다고 해봅시다.

    1 class A

    2 {

    3     public:

    4         A(int);

    5 };

    6 void f(A) {}

    7 void g()

    8 {

    9     A a1 = 37;

   10     A a2 = A(47);

   11     A a3(57);

   12     a1 = 67;

   13     f(77);

   14 }

   15 

   16 


놀랍게도 위 코드는 모두 정상적으로 컴파일되고 실행됩니다. 

라인 9을 보면 좀 이상합니다. 저렇게 생성자를 호출하면 안될 것 같지만, 어떤 컴파일러 에러 없이도 실행이 됩니다. 이렇게 실행이 되는 이유는 C++ 컴파일러가 우선 A(int)라는 생성자를 호출한 뒤, 넘겨 받은 정수 값인 37로부터 A 객체인 a1을 만들어내도록 묵시적인 형 변환이 발생하기 때문입니다.

라인 10와 11은 아무 문제가 없죠. A의 생성자 형태로 불러준 것일 뿐이니까요.

라인 12와 13도 이상합니다. 저렇게 하면 안될 것 같은데, 이 역시 묵시적 형 변환이 발생하여 가능한 일입니다.  이런 생성자를 보통의 생성자와 구분하여 부르기 위해 converting constructor라고 말합니다. 

하지만, 저런 식으로 사용자 코드에서 묵시적인 형 변환이 일어나도록 사용하는 것은 애당초 A라는 클래스를 디자인 했던 클래스 디자이너가 원했던 것이 아닐겁니다. 그러나 저런 식으로 A 클래스의 생성자를  호출하는 프로그래머가 없으리라는 법도 없죠. 

다른 개발자와 협업 개발 시 항상 염두에 두어야 할 것이 있습니다. 그것은 클래스 사용자가 가능한 한 에러를 일으키지 않도록 올바른 클래스 프로토타입을 제공해주는 것이 언제나 미덕이라는 것이죠. 에러를 런타임에 잡아내는 것보다 컴파일 타임에 잡아내는 것이 언제나 훨씬 더 수월하기 때문입니다.


이를 위해 C++ 에서는 explicit라는 키워드를 생성자 선언 시 사용할 수 있습니다.

    1 class A

    2 {

    3     public:

    4         explicit A(int);

    5 };

    6 void f(A) {}

    7 void g()

    8 {

    9     A a1 = 37;      // illegal

   10     A a2 = A(47);   // OK

   11     A a3(57);       // OK

   12     a1 = 67;        // illegal

   13     f(77);          // illegal

   14 }

   15 

   16 


explicit 키워드를 사용하면 생성자는 묵시적 (implicit) 형변환을 하지 않도록 강제됩니다. 따라서 이렇게 변경된 코드에서는, 만약 사용자가 g() 함수를 고치지 않았다면, 라인 9, 12, 13 에서는 illegal 이기 때문에 컴파일러는 에러를 뿜어내게 됩니다. 생성자가 명시적 형변환만 강제하기 때문입니다. 위의 코드를 실행 가능하도록 하려면 g() 함수를 아래와 같이 수정해야 합니다.


    1 class A

    2 {

    3     public:

    4         explicit A(int);

    5 };

    6 void f(A) {}

    7 void g()

    8 {

    9     A a1 = A(37);

   10     A a2 = A(47);

   11     A a3(57);

   12     a1 = A(67);

   13     f(A(77));

   14 }


이제야 코드가 제대로 의도했던 바대로 돌아갈 수 있습니다. 이렇게 함으로써 클래스 디자이너는 사용자 프로그래머가 실수하는 것을 방지할 수 있습니다. 

하나 더. explicit 키워드는 파라미터가 하나인 생성자의 경우에만 유효합니다. 

파라미터를 두 개 이상 가진 생성자의 경우 explicit 키워드를 사용할 필요가 없습니다. 사용할 필요가 없다고 한 대목에 주목하세요. 당연히 expliciti 키워드를 쓸 수 있고, 그로 인해 에러도 발생하지 않습니다. 말하려는 것은 explicit의 효력이 발생하지 않는다는 것입니다. 왜냐하면 그런 생성자는 묵시적 형 변환을 실행 하지 않기 때문이죠. 기억해야 할 것은 파라미터가 하나인 생성자만 묵시적 형 변환을 수행한다는 것입니다. 

다만 주의해야 할 것은, 파라미터가 여러 개인 생성자라 할 지라도, 파라미터 가운데 하나를 제외한 나머지가 디폴트 값을 가지고 있도록 선언되어 있고, 생성자를 호출하는 코드 쪽에서 파라미터를 하나만 제공하여 호출한다면 묵시적 형 변환이 발생할 수 있다는 것입니다. 이때도 역시 explicit 키워드를 써줌으로써 묵시적 형 변환이 발생하는 것을 방지할 수 있습니다.

저작자 표시 비영리 변경 금지
Posted by In search of dream 꿈찾아고고씽
TAG