이번 글에서는 C++의 생성자 위임(Constructor Delegation)에 대해 알아보겠습니다. 생성자 위임이란 한 클래스의 생성자가 같은 클래스의 다른 생성자를 호출하는 기능을 말하며, C++11부터 도입된 특징입니다.
먼저 다음 예제 코드를 살펴보고, 이 코드에서 어떤 문제점이 있는지 분석해 보겠습니다.
문제가 있는 코드 예제
#include <iostream>
using namespace std;
class MyClass {
int a, b, c;
public:
MyClass(){
a = b = c = 0;
}
MyClass(int c) {
// a와 b를 초기화하는 것은 중복된 작업이며,
// 여기서는 c만 초기화하면 됩니다.
a = 0;
b = 0;
this->c = c;
}
void display(){
cout << "a : " << a << ", b : " << b << ", c : " << c;
}
};
main() {
MyClass my_obj(5);
my_obj.display();
}실행 결과
a : 0, b : 0, c : 5
코드 자체는 정상적으로 동작하지만, 중복 코드(redundant code)가 존재한다는 문제가 있습니다. 매개변수가 없는 기본 생성자는 이미 a와 b를 0으로 설정하고 있으므로, 두 번째 생성자에서 a와 b를 다시 초기화하는 것은 불필요한 반복입니다.
만약 첫 번째 생성자를 두 번째 생성자 안에서 재사용할 수 있다면 코드가 훨씬 효율적일 것입니다. 바로 이럴 때 생성자 위임을 사용합니다.
생성자 위임을 적용한 코드
#include <iostream>
using namespace std;
class MyClass {
int a, b, c;
public:
MyClass(){
a = b = c = 0;
}
MyClass(int c) : MyClass(){ // 생성자 위임 사용
this->c = c;
}
void display(){
cout << "a : " << a << ", b : " << b << ", c : " << c;
}
};
main() {
MyClass my_obj(5);
my_obj.display();
}실행 결과
a : 0, b : 0, c : 5
위 코드에서 MyClass(int c) : MyClass() 부분이 핵심입니다. 멤버 초기화 리스트(member initializer list)를 통해 같은 클래스의 기본 생성자를 호출함으로써, a와 b의 초기화 로직을 중복해서 작성할 필요가 없어졌습니다.
생성자 위임의 장점
- 코드 중복 제거: 여러 생성자에서 반복되는 초기화 코드를 하나의 생성자에 모아 관리할 수 있습니다.
- 유지보수성 향상: 초기화 로직이 변경될 경우 위임 대상인 단 하나의 생성자만 수정하면 됩니다.
- 가독성 개선: 각 생성자는 자신에게 필요한 추가 초기화에만 집중할 수 있어 코드 의도가 명확해집니다.
단, 주의할 점도 있습니다. 위임받은 생성자가 먼저 실행된 후 위임한 생성자의 본문(body)이 실행되므로, 위임 대상 생성자에서 객체가 완전히 유효한 상태로 초기화되도록 설계해야 합니다. 또한 생성자 위임 시 순환 참조(예: 서로를 무한히 위임하는 구조)가 발생하지 않도록 주의해야 컴파일 오류나 무한 루프를 피할 수 있습니다.