Program Language/C & C++

[C++] 클래스 explicit 생성자

야곰야곰+책벌레 2022. 1. 14. 10:09
728x90
반응형

기본적으로 단일 인수에 의해 호출된 생성자는 인수 유형에서 해당 유형으로 암시적 변환으로 작동한다.

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

목록 초기화를 위해 직접 초기화와 복사 초기화의 구분이 유지된다.

728x90
반응형

'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