본문 바로가기

C++

C++ 배우기 23(생성자, 소멸자)

생성자

우리가 평소에 사용하던 class에서 사용할 수 있는 것으로, 해당 클래스를 가지고 객체를 생성됨과 동시에 자동으로

호출되는 함수라고 할 수 있다.

보통 class의 멤버 변수는 private의 접근 제한을 기본으로 두고 있어서 외부에서 직접 접근하여 초기화하기 힘들다.

만약 초기화를 하려면 getter와 setter를 이용해 하는 방법을 배웠었는데, 또 다른 방법으로 바로 이 생성자를

사용하는 것이다.

 

class Exam
{
private :
	int a;
	int b;

public:
	Exam(); //생성자
};

int main()
{
	//exam 객체 생성과 동시에 Exam()생성자 호출
	Exam exam;

	return 0;
}

지금까지 class를 사용하면서 생성자를 사용하지 않았었지만, 사실 C++에서는 별도로 생성자를 구현하지 않아도

알아서 기본 생성자(Default Constructor)를 사용해준다.

여기서 기본 생성자는 매개 변수가 없어서 해당 객체의 멤버변수를 0, NULL 등으로 자동 초기화해버린다.


class Exam2
{
private:
	int a;
	int b;
public:
	Exam2() //생성자1
	{
		a = 1;
		b = 2;
	}
    
	Exam2(int num1, int num2) //생성자2
    	{
    		a = num1;
        	b = num2;
    	}
};

위의 예시처럼 클래스의 멤버 변수가 private일 때, 우리는 외부에서 멤버변수로 접근할 수 없다.

하지만 생성자를 통해서 객체 생성과 동시에 멤버변수 초기화를 할 수 있게 되었다.

 

보면 알겠지만, 생성자는 해당 클래스의 객체가 만들어질 때 자동으로 호출되는 특수한 종류의 멤버 함수라고 할 수 있다.

때문에 일반적인 멤버 함수와는 다르게 생성자만의 정의하는 방법이 있다.

  • 생성자 이름은 클래스 이름과 항상 같아야 한다.
  • 생성자는 return 타입이 없다. 하지만 반환값은 존재한다.

 

생성자도 함수이다 보니 함수 오버 로딩처럼 생성자 오버 로딩이 가능하다. 위 예시처럼 class 안에 Exam2() 생성자가 2개

존재하는 것을 볼 수 있다. 생성자 오버 로딩은 보통 오버 로딩처럼 매개변수에 차이를 두며 사용할 수 있다.

//오버로딩된 생성자 사용법
Exam2 exam1;
Exam2 exam2(5, 4);

생성자 오버 로딩의 사용법 또한 일반적인 함수 오버 로딩과 비슷하다. 객체를 생성하면서 해당하는 매개변수에 맞게

초기화를 시켜주면 알맞은 생성자로 실행이 된다.

 

 

임시 변수(객체)

exam2();

위 예시처럼 생성자만 선언하는 것을 임시 변수(객체)라고 부른다.

이렇게 생성자만 선언을 하면, 생성과 동시에 바로 소멸된다.

 

 

생성자도 5가지의 종류가 있다.

  • 기본생성자
  • 복사생성자
  • 이동생성자
  • 복사대입생성자
  • 이동대입생성자

이러한 종류가 있다는 것을 알아두고, 추후에 알아보도록 하겠다.


소멸자

생성자와는 반대되며, 객체가 소멸될 때에 자동으로 실행되는 클래스의 멤버 함수이다.

말하자면 생성자는 클래스의 초기화에 사용되지만, 소멸자는 클래스의 소멸에 사용이 된다.

class Exam
{
private:
    int a;
    int b;
public:
    Exam(); //생성자
    ~Exam(); //소멸자
};

생성했던 객체가 메모리에서 삭제되기 전에 필요한 정리를 위해서 클래스의 소멸자를 호출한다.

보통 클래스의 멤버 변수가 동적 메모리라면 객체가 소멸되기 전에 미리 할당 해제를 해주는 등의 역할을 해줄 수 있다.

 

위의 예시를 보면, 생성자와 비슷하지만 앞에 ~가 붙어 있는 것을 볼 수 있다. 이처럼 소멸자도 사용 시에 규칙이 있다.

  • 소멸자의 이름은 클래스 이름과 같아야 하고, 앞에 ~ 가 있어야 한다.
  • 소멸자는 매개변수가 없다.
  • 소멸자는 return값이 없다.
  • 소멸자는 하나만 존재해야 한다.

이처럼 생성자와 조금 다른 규칙이 있다. 하지만 생성자와는 다르게 소멸자는 클래스 당 하나만 존재해야 한다.

그리고 소멸자는 명시적으로 호출하는 경우가 없다.

 

class Exam2
{
private:
    int a;
    int b;
public:
    Exam2(); //생성자
    ~Exam2(); //소멸자
};

int main()
{
    Exam2 exam;
    .
    .
    .
    return 0;
} //exam 객체는 여기서 삭제가 되므로 ~Exam2()소멸자는 여기서 호출이 됨

위 예시처럼 소멸자는 객체가 삭제될 때 자동으로 호출이 되는 것을 알 수 있다.

소멸자로 소멸되는 객체의 순서는 스택프레임의 LIFO(Last In First Out)방식으로 소멸되는 것을 알아두자.