728x90

황기태 저자의 명품 C++ Programming 개정판을 읽고 학습한 내용을 정리한 포스트입니다!

https://search.shopping.naver.com/book/catalog/32436115747

 

C++ Programming : 네이버 도서

네이버 도서 상세정보를 제공합니다.

search.shopping.naver.com

 

파생 클래스와 기본 클래스의 생성자 호출 및 실행 관계

파생 클래스와 기본 클래스는 각각 생성자를 가지고 있다. 이 때 아래 2가지 질문을 살펴보자

 

 1. 파생 클래스의 객체가 생성될 때 파생 클래스의 생성자와 기본 클래스의 생서자가 모두 실행되는가? 아니면 파생 클래스의 생성자만 실행되는가?

 둘 다 실행된다.
생성자는 객체를 초기화할 목적으로 사용되므로, 파생 클래스의 생성자는 파생 클래스의 멤버를 초기화하거나 필요한 초기 작업을 수행하고, 기본 클래스의 생성자는 기본 클래스의 멤버 초기화나 필요한 초기화를 각각 수행한다.

 

2. 파생 클래스의 생성자와 기본 클래스의 생성자 중 어떤 생성자가 먼저 실행되는가?

기본 클래스의 생성자가 먼저 실행된다.

 

클래스 A, B, C가 상속 관계에 있는 아래 그림을 보면서 위의 질문에 대한 답변을 살펴보자.

 

  • 객체 c가 생성될 때, 생성자 C()가 바로 호출된다. 이 때, C가 B를 상속받고 있기 때문에 C()는 자신이 실행되기 전에 기본 클래스 B의 생성자 B()를 호출하며 B는 같은 이유로 A()를 호출한다.
  • A는 어떤 상속도 받고 있지 않기에 A()를 실행 후 리턴, B() 실행 리턴, C() 실행의 순서로 진행된다.

여기서 2번 질문의 답을 찾을 수 있다. 파생 클래스의 생성자가 먼저 호출되지만, 결국 기본 클래스의 생성자가 먼저 실행된다.

 

소멸자의 실행 순서
  • 생성자와 마찬가지로 파생 클래스의 객체가 소멸될 때, 기본 클래스와 파생 클래스의 소멸자 역시 각각 실행된다.
  • 왜냐하면, 파생 클래스의 소멸자를 컴파일할 때, 파생 클래스의 소멸자 코드를 실행한 후 기본 클래스의 소멸자를 호출하도록 컴파일하기 때문
  • 따라서, 소멸자는 생성자의 실행 순서와 반대로 실행

파생 클래스에서 기본 클래스 생성자 호출

파생 클래스와 기본 클래스는 여러 개의 생성자를 가질 수는 있지만, 객체가 생성될 때 반드시 파생 클래스 생성자 하나와 기본 클래스 생성자 하나가 실행된다. 이 때, 파생 클래스의 생성자가 실행될 때 함께 실행되는 기본클래스의 생성자는 어떻게 결정되는가??

  • 원래는 파생 클래스의 생성자와 함께 실행할 기본 클래스의 생성자를 지정하여 개발한다.
  • 다만, 명시적으로 지정하지 않으면 컴파일러는 묵시적으로 기본 클래스의 기본 생성자가 실행되도록 컴파일한다.

 

컴파일러에 의해 묵시적으로 기본 클래스의 생성자가 선택되는 경우

  • 파생 클래스의 기본 생성자 B()가 호출될 때, 기본 클래스의 기본 생성자 A()가 호출되도록 컴파일러에 의해 묵시적으로 짝지어졌다.
  • class A에는 A(int x)가 잇지만 컴파일러는 B()가 기본 생성자 A()를 호출하도록 컴파일한다.
  • 만약 아래와 같이 기본 생성자 A()가 선언되어 있지 않다면 error C2512: 'A' : 사용할 수 있는 적절한 기본 생성자가 없습니다. 와 같은 에러가 발생한다.

 

  • 또한 아래와 같이 B(int x)를 실행하더라도 기본 생성자 A()를 호출하도록 컴파일한다.


명시적인 기본 클래스의 생성자 선택
  • 기본 클래스의 생성자를 명시적으로 선택하기 위해 작성된 코드이다.
  • B(int x) 생성자가 호출되면, 매개 변수 x로 받은 값에 3을 더하여 생성자 A(int x)의 매개 변수 x에 넘겨준다.
B(int x) : A(x + 3) {
	cout << "매개 변수 생성자 B" << x << endl;
}

 

파생 클래스의 개체를 생성할 때, 파생 클래스의 생성자를 통해 기본 클래스의 생성자에게까지 매개 변수를 전달한다.


컴파일러의 기본 생성자 호출 코드 삽입
  • 아까 보았듯이 클래스 B의 생성자가 기본 클래스의 생성자 A()를 묵시적으로 호출하게 되는 것은, 사실상 컴파일러가 다음과 같이 명시적으로 A()를 호출하도록 클래스 B의 생성자를 변형하기 때문이다.
class B {
	B() : A() { // 컴파일러가 묵시적으로 삽입한 코드
		cout << "생성자 B" << endl;
	}
	B(int x) : A() {
		cout << "매개변수생성자 B" << x << endl;
	}
};

 

728x90

'Programming Language > C++' 카테고리의 다른 글

[C++] 다중 상속과 가상 상속  (0) 2023.12.15
[C++] public, protected, private 상속  (0) 2023.12.14
[C++] protected 접근 지정  (0) 2023.12.14
[C++] 상속과 객체 포인터  (0) 2023.12.14
[C++] 상속  (1) 2023.12.06