[6-2 ~ 6-3]
- 시작(탄생) -> 생성자 (여러 개 존재 가능)
- 끝(소멸) -> 소멸자 (오직 1개만)
생성자의 종류 3가지
(1) 기본 생성자 (인자 없음)
(2) 복사 생성자 (자기 자신의 클래스 참조 타입(&)을 인자로 받음)
: 일반적으로 "똑같은" 데이터를 지닌 개체가 생성되길 기대한다
(3) 기타 생성자 (1, 2 외의 생성자들)
암시적(Implicit) 생성자
: 생성자를 명시적으로 만들지 않으면, 아무 인자도 받지 않는 "기본 생성자"가 컴파일러에 의해 자동으로 만들어짐.
→ 그러나 우리가 명시적(Explicit)으로 복사 또는 기타 생성자 중 아무거나 하나를 만들면, 자동으로 만들어지던 "기본 생성자"는 더 이상 만들어지지 않음 !
그래서 인자가 없는 기본 인스턴스를 만들게 되면 컴파일 오류가 남
반면에 생성자가 아무것도 없을 경우 컴파일러가 기본 생성자를 자동으로 만들어줘서 컴파일 가능
→ 아무것도 안만들었다면 하나를 기본적으로 만들어 주지만, 하나라도 만드는 순간 관리책임은 "프로그래머"에게로 넘어간다 !
암시적(Implicit) 복사 생성자도 존재한다
이 경우, 모든 멤버변수를 복사해줌
일반 데이터는 그냥 기본 방식(암시적 복사 생성자)로 사용해도 상관없지만, 여기서 포인터라거나 참조값이 들어가기 시작하면 문제가 복잡해지기 때문에 나중에 동적할당을 배우고 다시 알아보겠음 (깊은복사, 얕은복사 관련)
1) Knight k2(k1); 또는 Knight k3 = k1; (둘 다 같은 것임.)
이것과
2) Knight k4;
k4 = k1;
이것은 호출되는 생성자가 다르다.
1번은 한 번에 "복사 생성자"가, 2번은 "기본 생성자 + 복사"가 일어남
기타 생성자 중에서 인자를 1개만 받는 기타 생성자를 "타입 변환 생성자"라고도 함 (또는 변환 생성자)
암시적 형변환 : 암시적으로 컴파일러가 알아서 바꿔치기
int num = 1;
float f = num;
명시적 형 변환 : 우리가 코드로 num을 float 바구니에 넣으라고 주문
int num = 1;
float f = (float)num;
ex)
Knight(int hp)
{
// do something
}
인자를 1개만 받는 타입 변환 생성자가 하나 있다고 가정하자.
Knight k5;
k5 = 1; ←
위 코드는 대개 k5에 다른 Knight형 변수를 대입해서 복사될 때 사용되므로 불가능하다고 생각될 수 있지만,
인자를 1개만 받는 타입 변환 생성자가 호출되어 프로그래머의 의도와 다르게 값이 들어간다.
게다가,
void HelloKknight(Knight k)
{
// do something
}
위 같은 "일반 함수"가 있고, 여기에
HelloKnight(5);
처럼 인자로 5같은 숫자가 하나만 들어간다면, 인자 Knight k에 5가 들어가므로 타입 변환 생성자가 실행되어 의도치 않게 실행된다.
어떻게 해야할까?
암시적으로 사용하지 말아달라, 명시적인 용도로만 사용할 것 !
explicit Knight(int hp)
{
// do something
}
이제 k5 = 1; 같은 코드는 암시적으로 실행되지 않도록 컴파일러가 막아주고, 명시적으로 형변환을 해줘야 들어가게 된다.
이런 상황이 발생하는 이유는 Knight k2(k1)와 Knight k2 = k1가 C++ 특성상 문법적으로 동일하게 취급되기 때문에 모호하게 동작하기 때문일 것이다.
결국 어떻게 써야하나?
일반적으로 타입 변환 생성자를 암시적 형변환으로 인해 호출되게끔 하는 경우는 거의 없으므로
인자가 1개인 생성자는 무조건 explicit를 붙여두고 그 다음 고민하자.
실제로 언리얼 엔진 내부 코드에서도 인자가 1개인 생성자는 거의 대부분 explicit가 붙어있다.
'컴퓨터공학 > C++' 카테고리의 다른 글
[Modern C++] std::forward (0) | 2024.09.14 |
---|---|
[Modern C++] Lambda (0) | 2024.09.11 |
[C++] 동적할당 (0) | 2024.08.23 |
[C++] 초기화 리스트 (0) | 2024.08.22 |
[C++] 상속성 (0) | 2024.08.21 |