C++ 기본 클래스 생성자 호출의 기본 원리
C++에서는 기존 클래스를 상속하여 새로운 파생 클래스(derived class)를 만들 수 있습니다. 파생 클래스의 객체를 생성하면 컴파일러는 먼저 슈퍼클래스, 즉 기본 클래스(base class)의 생성자를 호출한 뒤 파생 클래스의 생성자를 실행합니다.
흥미로운 점은 Java와 달리 C++에는 super처럼 슈퍼클래스를 가리키는 참조 변수나 키워드가 없다는 것입니다. 대신 다음 두 가지 규칙에 따라 기본 클래스의 생성자가 호출됩니다.
- 매개변수가 없는 생성자(디폴트 생성자)인 경우: 파생 클래스 객체가 생성될 때 별도의 코드 없이 자동으로 호출됩니다.
- 매개변수가 있는 생성자인 경우: 반드시 파생 클래스 생성자의 멤버 초기화 리스트(initializer list)에 기본 클래스 생성자를 명시적으로 작성해야 합니다. 생략하면 컴파일 오류가 발생합니다.
먼저 인수가 없는 생성자가 어떻게 자동으로 호출되는지 예제를 통해 살펴보겠습니다.
예제 1: 디폴트 생성자의 자동 호출
#include <iostream>
using namespace std;
class MyBaseClass {
public:
MyBaseClass() {
cout << "Constructor of base class" << endl;
}
};
class MyDerivedClass : public MyBaseClass {
public:
MyDerivedClass() {
cout << "Constructor of derived class" << endl;
}
};
int main() {
MyDerivedClass derived;
}
출력 결과
Constructor of base class Constructor of derived class
파생 클래스의 객체를 하나만 생성했는데도 출력 결과를 보면 기본 클래스의 생성자가 먼저 실행된 것을 확인할 수 있습니다. 이는 파생 클래스 객체가 만들어질 때 항상 기본 클래스부터 초기화되기 때문이며, 개발자가 아무것도 작성하지 않아도 컴파일러가 자동으로 처리해 줍니다.
예제 2: 초기화 리스트로 매개변수 생성자 호출하기
이번에는 매개변수를 받는 생성자의 경우입니다. 기본 클래스의 생성자가 인수를 요구한다면, 파생 클래스 생성자 이름 뒤에 콜론(:)을 붙이고 초기화 리스트에 기본 클래스 생성자를 지정해 주어야 합니다.
#include <iostream>
using namespace std;
class MyBaseClass {
public:
MyBaseClass(int x) {
cout << "Constructor of base class: " << x << endl;
}
};
class MyDerivedClass : public MyBaseClass { // 초기화 리스트로 기본 클래스 생성자 호출
public:
MyDerivedClass(int y) : MyBaseClass(50) {
cout << "Constructor of derived class: " << y << endl;
}
};
int main() {
MyDerivedClass derived(100);
}
출력 결과
Constructor of base class: 50 Constructor of derived class: 100
위 예제에서는 MyDerivedClass derived(100);으로 객체를 생성했지만, 초기화 리스트 덕분에 기본 클래스 생성자에는 값 50이 전달되었습니다. 만약 파생 클래스가 받은 값을 그대로 넘기고 싶다면 MyDerivedClass(int y) : MyBaseClass(y)처럼 작성하면 됩니다.
핵심 정리
- C++에는 Java의
super키워드가 없으며, 그 역할을 초기화 리스트가 대신합니다. - 객체 초기화 순서는 항상 기본 클래스 생성자 → 멤버 변수 → 파생 클래스 생성자 본문 순으로 진행됩니다.
- 기본 클래스에 디폴트 생성자가 있으면 호출을 생략할 수 있지만, 매개변수 생성자만 존재한다면 초기화 리스트에서 반드시 명시적으로 호출해야 합니다.