요약

생성자(Constructor): 객체를 초기화 하는 멤버함수. 클래스 스스로 자신을 초기화하는 방법을 정의한다.

기본 생성자(Default Constructor): 인수를 가지지 않는 생성자

소멸자(Destructor): 객체가 소멸될 때 실행되는 멤버함수. 동적으로 할당된 객체의 메모리를 해제할 때 사용한다.

생성자

  1. 생성자(초기자, 구성자, Constructor, ctor) - 객체를 초기화 하는 멤버함수. 클래스 스스로 자신을 초기화하는 방법을 정의한다.

  2. 사용 이유
    • 선언문이 초기화를 겸하면 코드가 간결해질 것
    • C++은 클래스 객체에 대해 단순 타입에 적용되는 선언 및 초기화 문법을 제공하지 않음. 왜냐하면 멤버의 수와 타입이 가변적이기 때문.
    • 이에 초기화를 전담하는 별도의 함수 필요
  3. 역할 - 객체 초기화

  4. 자동 호출 주체 - 컴파일러

  5. 형태 - “클래스이름”
#include <iostream>
using namespace std;

class unit
{
protected:
	int hp;
	int atk;

public:
	unit()
	{
		cout << "기본생성자 호출" << '\n';
		cout << "hp: " << hp << '\n';
		cout << "atk: " << atk << "\n\n";
	}

	unit(int _hp, int _atk) :
		hp(_hp), atk(_atk) 
	{
		cout << "오버로딩 생성자 호출\n";
		cout << "hp: " << hp << '\n';
		cout << "atk: " << atk << "\n\n";
	}
};

int main()
{
	unit player;
	unit monster(100, 10);	// 암시적인 호출
}
기본생성자 호출
hp: -858993460
atk: -858993460

오버로딩 생성자 호출
hp: 100
atk: 10

위처럼 특징은

  1. 생성과 동시에 호출됨
  2. 오버로딩 가능
  3. 미초기화 시 쓰레기값으로 초기화
  4. 리턴값이 없음

기본 생성자

  1. 기본 생성자(디폴트 생성자, Default Constructor) - 인수를 가지지 않는 생성자

  2. 사용 이유
    • 호출부에서 특정 값으로 초기화하고 싶지 않을 때
    • 어떤 값인지 알지도 못하는 쓰레기값보다는 0 or -1 or NULL or “” 와 같이 초기화되지 않았음을 명시할 때
  3. 자동 호출:
    • 클래스에 생성자가 정의되어 있지 않으면 컴파일러가 자동으로 디폴트 생성자를 만든다.
    • 기본, 혹은 오버로딩한 생성자가 하나라도 있다면 컴파일러는 디폴트 생성자를 만들지 않는다.
  4. 객체의 초기화 방식 == 일반 변수와 같은 규칙 적용
    • 전역 or 정적 객체 => 모든 멤버가 0으로 초기화
    • 지역 객체 => 초기화되지 않은 쓰레기값
#include <iostream>
using namespace std;

class unit
{
protected:
	char* name;
	int hp;
	int atk;

public:
	unit(int _hp)	
	{
		hp = _hp;
	}
};

int main()
{
	unit monster;	// 생성자가 하나 이상 정의되어 있어 컴파일러가 기본 생성자를 자동 호출하지 않아 에러
}
// Error

default 키워드

기본 생성자는 컴파일러가 자동으로 호출하고 싶고, 별도 오버로딩한 생성자를 만들고 싶다?

default 키워드 - C++11 부터 명시적으로 default 생성자를 선언할 수 있다.

#include <iostream>
using namespace std;

class unit
{
protected:
	int hp;
	int atk;

public:
	unit() = default;	// default 키워드

public:
	void PrintInfo()
	{
		cout << "hp: " << hp << '\n';
		cout << "atk: " << atk << '\n';
	}
};

int main()
{
	unit monster;
	monster.PrintInfo();
}
hp: -858993460
atk: -858993460

소멸자

  1. 소멸자(파괴자, Destructor, dtor) - 객체가 소멸될 때 실행되는 멤버함수. 동적으로 할당된 객체의 메모리를 해제할 때 사용한다.

  2. 형태 - “~클래스이름”

  3. 사용 이유 - 객체, 메모리는 항상 자신이 생성되기 전의 상태로 돌려놓아야 함

  4. 역할 - 동적 할당된 메모리 해제

  5. 자동 호출 주체 - 컴파일러

#include <iostream>
using namespace std;

class unit
{
protected:
	char* name;
	int hp;
	int atk;

public:
	unit() = default;
	unit(const char* _name, int _hp, int _atk)
	{
		int length = strlen(_name);
		name = new char[length + 1];	// 동적 할당
		strcpy_s(name, length + 1, _name);
		hp = _hp;
		atk = _atk;

		cout << "생성자 오버로딩\n";
		cout << "name: " << name << '\n';
		cout << "hp: " << hp << '\n';
		cout << "atk: " << atk << "\n\n";
	}
	~unit()
	{
		delete[] name;	// 해제

		cout << "소멸자 호출\n";
		cout << "name: " << name << '\n';
		cout << "hp: " << hp << '\n';
		cout << "atk: " << atk << "\n\n";
	}
};

int main()
{
	unit monster("슬라임", 100, 10);
}
생성자 오버로딩
name: 슬라임
hp: 100
atk: 10

소멸자 호출
name: 硼硼硼硼硼硼硼硼硼硼硼硼:FzZ?
hp: 100
atk: 10

위처럼 특징은

  • 동적 할당한 멤버 변수를 해제할 때 사용


위 경우 파괴자가 정의되어 있지 않다면 메모리 누수 발생 !


생성자와 소멸자의 공통 특징

  1. 이름이 정해져 있다.
  2. 리턴값이 없다.
  3. 반드시 public 액세스 속성을 가져야 한다. (특수 목적 제외. ex. 싱글톤 패턴)
  4. friend가 될 수 없다. => 둘 다 클래스 내부의 함수이므로 friend 지정이 없어도 멤버를 마음대로 액세스 할 수 있다.
  5. static이 될 수 없다. => 초기화와 정리의 대상이 클래스가 아니라 개별 객체이므로.
  6. 둘 다 컴파일러가 호출하는 디폴트가 있다. 인수를 취하지 않고 아무런 동작을 하지 않는다.

생성자와 소멸자의 차이

  1. 생성자는 인수가 있지만 파괴자는 인수가 없다.
  2. 생성자는 가상 함수로 정의될 수 없지만 파괴자는 가상 함수로 선언될 수 있다.
    • 아직 만들어지지도 않은 객체에 대해 다형적인 특징을 사용할 수 없다.


그 외..

  • 멤버 변수 초기화, 이니셜라이저 리스트는 초기화 파트에서 정리
  • 상속 시 생성자, 소멸자 호출 순서는 상속 파트에서 정리
  • virtual 소멸자는 가상 함수 파트에서 정리
  • 복사 생성자, 복사 대입 연산자, 이동 생성자, 이동 대입 연산자는 별도 파트에서 정리

태그:

카테고리:

업데이트:

댓글남기기