기본적으로 단일 인수에 의해 호출된 생성자는 인수 유형에서 해당 유형으로 암시적 변환으로 작동한다.
complex<double> d {1}; // d=={1,0} (§5.6.2)
이러한 암시적 변환은 매우 유용할 수 있다. complex는 한 예다. 허수부를 생략하면 실수 축에 복소수가 표시된다. 그것이 바로 수학적 요구다. 그러나 많은 경우 이러한 변환은 혼란과 오류의 중요한 원인이 될 수 있다. Date를 예로 보자.
void my_fct(Date d);
void f()
{
Date d {15}; // plausible: x becomes {15,today.m,today.y}
// ...
my_fct(15); // obscure
d = 15; // obscure
// ...
}
이것은 모호하다. 코드의 복잡성과는 별개로 숫자 15와 날짜 사이에는 명확한 논리적 연결이 없다.
다행히도 생성자가 암시적 변환으로 사용되지 않도록 저장할 수 있다. 명시적 키워드로 선언된 생성자는 초기화 및 명시적 변환에만 사용할 수 있다.
class Date {
int d, m, y;
public:
explicit Date(int dd =0, int mm =0, int yy =0);
// ...
};
Date d1 {15}; // OK: considered explicit
Date d2 = Date{15}; // OK: explicit
Date d3 = {15}; // error : = initialization does not do implicit conversions
Date d4 = 15; // error : = initialization does not do implicit conversions
void f()
{
my_fct(15); // error : argument passing does not do implicit conversions
my_fct({15}); // error : argument passing does not do implicit conversions
my_fct(Date{15}); // OK: explicit
// ...
}
= 를 사용한 초기화는 복사 초기화로 간주된다. 원칙적으로 initializer의 복사본은 초기화된 객체에 배치된다. 그러나 이러한 복사본은 최적화(생략)될 수 있으며 초기화가 rvalue인 경우 이동 작업이 사용될 수 있다. =를 생략하면 초기화가 명시적으로 된다. 명시적 초기화를 직접 초기화라고 하기도 한다.
기본적으로 explicit 하나의 인자로 호출할 수 있는 생성자를 선언한다. 그렇게 하지 않는 합당한 이유가 필요하다 (complex의 경우). 암시적 생성자를 정의하는 경우 이유를 문서화하는 것이 가장 좋다.
생성자가 explicit으로 선언되고 클래스 외부에서 정의된 경우 explicit을 반복할 수 없다.
class Date {
int d, m, y;
public:
explicit Date(int dd);
// ...
};
Date::Date(int dd) { /* ... */ } // OK
explicit Date::Date(int dd) { /* ... */ } // error
explicit이 중요한 대부분의 예는 단일 생성자 인수를 포함한다. 그러나 explicit은 인수가 0개 또는 둘 이상인 생성자에도 유용할 수 있다.
struct X {
explicit X();
explicit X(int,int);
};
X x1 = {}; // error : implicit
X x2 = {1,2}; // error : implicit
X x3 {}; // OK: explicit
X x4 {1,2}; // OK: explicit
int f(X);
int i1 = f({}); // error : implicit
int i2 = f({1,2}); // error : implicit
int i3 = f(X{}); // OK: explicit
int i4 = f(X{1,2}); // OK: explicit
목록 초기화를 위해 직접 초기화와 복사 초기화의 구분이 유지된다.
'Program Language > C & C++' 카테고리의 다른 글
[C++] 클래스 static 멤버 (0) | 2022.01.14 |
---|---|
[C++] 클래스 가변성(mutability) (0) | 2022.01.14 |
[C++] namespace를 이용한 version 관리 (0) | 2022.01.14 |
[C++] Catching Exception (0) | 2022.01.13 |
[C++] throwing exception (0) | 2022.01.13 |