컴퓨터공학/C++

[C++] 생성자와 소멸자

Pyxis 2024. 8. 20. 08:34

[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