~클래스의 이름();
소멸자는 생성자와 달리 인자를 아무것도 가지지 않음 -> 즉, 오버로딩이 되지 않음
Marine::~Marine()
{
std::cout << name << " 의 소멸자 호출 ! " << std::endl;
// 동적으로 값이 할당된 경우 제거
if (name != NULL)
{
delete[] name;
}
}
T(const T& a);
다른 T의 객체 a를 상수 레퍼런스로 받음
a는 cont 이므로 복사 생성자 내부에서 a의 데이터를 변경할 수 없고,
오직 새롭게 초기화되는 인스턴스 변수들에게 '복사'만 할 수 있게 됨
#include <string.h>
#include <iostream>
class Photon_Cannon
{
int hp, shield;
int coord_x, coord_y;
int damage;
public:
Photon_Cannon(int x, int y);
Photon_Cannon(const Photon_Cannon& pc);
void show_status();
};
Photon_Cannon::Photon_Cannon(const Photon_Cannon& pc)
{
std::cout << "복사 생성자 호출 !" << std::endl;
hp = pc.hp;
shield = pc.shield;
coord_x = pc.coord_x;
coord_y = pc.coord_y;
damage = pc.damage;
}
Photon_Cannon::Photon_Cannon(int x, int y)
{
std::cout << "생성자 호출 !" << std::endl;
hp = shield = 100;
coord_x = x;
coord_y = y;
damage = 20;
}
void Photon_Cannon::show_status()
{
std::cout << "Photon Cannon " << std::endl;
std::cout << " Location : ( " << coord_x << " , " << coord_y << " ) "
<< std::endl;
std::cout << " HP : " << hp << std::endl;
}
int main()
{
Photon_Cannon pc1(3, 3);
Photon_Cannon pc2(pc1);
Photon_Cannon pc3 = pc2;
pc1.show_status();
pc2.show_status();
}
실행 결과
생성자 호출 !
복사 생성자 호출 !
복사 생성자 호출 !
Photon Cannon
Location : ( 3 , 3 )
HP : 100
Photon Cannon
Location : ( 3 , 3 )
HP : 100
// 인자 2개 받는 생성자 호출
Photon_Cannon pc1(3, 3);
// 복사 생성자 호출
Photon_Cannon pc2(pc1);
Photon_Cannon pc3 = pc2; // 컴파일러는 해당 문장을 Photon_Cannon pc3(pc2); 이렇게 해석함
// 주의
Photon_Cannon pc3;
pc3 = pc2; // 이건 복사 생성자가 호출된 케이스가 아님 -> 복사 생성자는 오직 '생성' 시에만 호출됨
위 내용에서 복사 생성자를 지우고 실행해도 이전과 같은 결과가 나옴
-> 디폴트 복사 생성자는 기존의 디폴트 생성자, 소멸자와 달리 실제로 '복사'를 해 줌
Photon_Cannon의 복사 생성자의 내용을 추정해 본다면 아래와 같을 거임
Photon_Cannon::Photon_Cannon(const Photon_Cannon& pc)
{
hp = pc.hp;
shield = pc.shield;
coord_x = pc.coord_x;
coord_y = pc.coord_y;
damage = pc.damage;
}
// 디폴트 복사 생성자의 한계
#include <string.h>
#include <iostream>
class Photon_Cannon
{
int hp, shield;
int coord_x, coord_y;
int damage;
char *name;
public:
Photon_Cannon(int x, int y);
Photon_Cannon(int x, int y, const char *cannon_name);
~Photon_Cannon();
void show_status();
};
Photon_Cannon::Photon_Cannon(int x, int y)
{
hp = shield = 100;
coord_x = x;
coord_y = y;
damage = 20;
name = NULL;
}
Photon_Cannon::Photon_Cannon(int x, int y, const char *cannon_name)
{
hp = shield = 100;
coord_x = x;
coord_y = y;
damage = 20;
name = new char[strlen(cannon_name) + 1];
strcpy(name, cannon_name);
}
Photon_Cannon::~Photon_Cannon()
{
// 0 이 아닌 값은 if 문에서 true 로 처리되므로
// 0 인가 아닌가를 비교할 때 그냥 if(name) 하면
// if(name != 0) 과 동일한 의미를 가질 수 있다.
// 참고로 if 문 다음에 문장이 1 개만 온다면
// 중괄호를 생략 가능하다.
if (name) delete[] name;
}
void Photon_Cannon::show_status()
{
std::cout << "Photon Cannon :: " << name << std::endl;
std::cout << " Location : ( " << coord_x << " , " << coord_y << " ) "
<< std::endl;
std::cout << " HP : " << hp << std::endl;
}
int main()
{
Photon_Cannon pc1(3, 3, "Cannon");
Photon_Cannon pc2 = pc1;
pc1.show_status();
pc2.show_status();
}
pc1과 pc2는 모두 같은 변수를 가지게 됨
name이란 두 개의 포인터가 같은 값을 가짐 -> 같은 주소를 가리킴
이 경우 하나가 소멸되면서 name이 삭제되면 다른 하나는 댕글링 포인터를 가지게 됨
-> 한 번 해제된 메모리는 다시 해제될 수 없음 (접근한 것 자체만으로도 해도 오류)
위와 같은 경우를 얕은 복사라고 함
컴파일러가 생성하는 디폴트 복사 생성자는 얕은 복사만 할 수 있으므로
깊은 복사(name을 그대로 복사하지 말고 따로 다른 메모리에 동적 할당을 해서 내용만 복사하는 것)가 필요한 경우 사용자가 직접 복사 생성자를 만들어야 함
// 깊은 복사 예제
#include <string.h>
#include <iostream>
class Photon_Cannon
{
int hp, shield;
int coord_x, coord_y;
int damage;
char *name;
public:
Photon_Cannon(int x, int y);
Photon_Cannon(int x, int y, const char *cannon_name);
Photon_Cannon(const Photon_Cannon &pc);
~Photon_Cannon();
void show_status();
};
Photon_Cannon::Photon_Cannon(int x, int y)
{
hp = shield = 100;
coord_x = x;
coord_y = y;
damage = 20;
name = NULL;
}
Photon_Cannon::Photon_Cannon(const Photon_Cannon &pc)
{
std::cout << "복사 생성자 호출! " << std::endl;
hp = pc.hp;
shield = pc.shield;
coord_x = pc.coord_x;
coord_y = pc.coord_y;
damage = pc.damage;
name = new char[strlen(pc.name) + 1];
strcpy(name, pc.name);
}
Photon_Cannon::Photon_Cannon(int x, int y, const char *cannon_name)
{
hp = shield = 100;
coord_x = x;
coord_y = y;
damage = 20;
name = new char[strlen(cannon_name) + 1];
strcpy(name, cannon_name);
}
Photon_Cannon::~Photon_Cannon()
{
if (name) delete[] name;
}
void Photon_Cannon::show_status()
{
std::cout << "Photon Cannon :: " << name << std::endl;
std::cout << " Location : ( " << coord_x << " , " << coord_y << " ) "
<< std::endl;
std::cout << " HP : " << hp << std::endl;
}
int main()
{
Photon_Cannon pc1(3, 3, "Cannon");
Photon_Cannon pc2 = pc1;
pc1.show_status();
pc2.show_status();
}
실행 결과
복사 생성자 호출!
Photon Cannon :: Cannon
Location : ( 3 , 3 )
HP : 100
Photon Cannon :: Cannon
Location : ( 3 , 3 )
HP : 100