Computer >> 컴퓨터 >  >> 프로그래밍 >> C++

C++ 생성자·소멸자 호출 순서, 예제로 쉽게 이해하기

이 글에서는 C++에서 생성자(Constructor)와 소멸자(Destructor)가 호출되는 순서를 예제 코드와 함께 자세히 살펴보겠습니다.

여기서 말하는 호출 순서란, 클래스 간 상속(Inheritance) 관계가 있을 때 각 클래스의 생성자와 소멸자가 어떤 패턴으로 실행되는지를 의미합니다. 핵심 규칙은 다음과 같습니다.

  • 생성자: 기반(부모) 클래스의 생성자가 먼저 호출된 후, 파생(자식) 클래스의 생성자가 호출됩니다.
  • 소멸자: 생성자와 정반대로, 파생 클래스의 소멸자가 먼저 실행되고 기반 클래스의 소멸자가 마지막에 호출됩니다.

이러한 순서가 보장되는 이유는, 자식 클래스 객체가 만들어지기 전에 부모 클래스의 부분이 먼저 초기화되어야 하고, 객체가 소멸할 때는 반대로 자식 클래스의 리소스를 먼저 정리한 뒤 부모 클래스를 정리해야 안전하기 때문입니다.

예제 코드: 생성자 호출 순서

#include <iostream>
using namespace std;

// 부모(기반) 클래스
class Parent {
public:
    Parent() {
        cout << "기반(base) 클래스 생성자 호출" << endl;
    }
};

// 자식(파생) 클래스
class Child : public Parent {
public:
    Child() {
        cout << "파생(sub) 클래스 생성자 호출" << endl;
    }
};

int main() {
    Child obj;
    return 0;
}

Child 타입의 객체를 하나만 생성했을 뿐인데, 컴파일러는 자동으로 부모 클래스인 Parent의 생성자를 먼저 실행합니다.

실행 결과

기반(base) 클래스 생성자 호출
파생(sub) 클래스 생성자 호출

소멸자의 호출 순서 확인하기

소멸자는 생성자의 역순(LIFO 방식)으로 호출됩니다. 아래 예제를 통해 직접 확인할 수 있습니다.

#include <iostream>
using namespace std;

class Parent {
public:
    Parent()  { cout << "Parent 생성자" << endl; }
    ~Parent() { cout << "Parent 소멸자" << endl; }
};

class Child : public Parent {
public:
    Child()  { cout << "Child 생성자" << endl; }
    ~Child() { cout << "Child 소멸자" << endl; }
};

int main() {
    Child obj;
    return 0;
}

실행 결과

Parent 생성자
Child 생성자
Child 소멸자
Parent 소멸자

정리

  • 객체 생성 시에는 기반 클래스 → 파생 클래스 순서로 생성자가 호출됩니다.
  • 객체 소멸 시에는 파생 클래스 → 기반 클래스 순서로 소멸자가 호출됩니다.
  • 다중 상속의 경우, 기반 클래스들은 선언된 순서대로 생성자가 호출됩니다.
  • 부모 클래스 포인터로 자식 객체를 삭제할 가능성이 있다면, 기반 클래스의 소멸자를 virtual로 선언해야 올바른 소멸자가 호출되어 메모리 누수를 방지할 수 있습니다.