본문 바로가기
번역/Bjarne Stroustrup's C++ Style and Technique FAQ

Can I call a virtual function from a constructor?

by 겜게준 2019. 2. 27.

생성자에서 가상 함수를 호출할 수 있나요?


할 수는 있지만 조심해야 합니다. 예상한 대로 동작하지 않을 수 있습니다. 생성자에서는, 파생 클래스의 오버라이딩이 아직 일어나지 않았기 때문에 가상 함수 메커니즘이 비활성화됩니다. 오브젝트는 기본 클래스부터 위로 "파생 클래스 전 기본 클래스" 로 생성됩니다.


#include<string>

#include<iostream>

using namespace std;


class B {

public:

B(const string& ss) { cout << "B constructor\n"; f(ss); }

virtual void f(const string&) { cout << "B::f\n";}

};


class D : public B {

public:

D(const string & ss) :B(ss) { cout << "D constructor\n";}

void f(const string& ss) { cout << "D::f\n"; s = ss; }

private:

string s;

};


int main()

{

D d("Hello");

}


프로그램을 컴파일하고 실행하면 다음과 같습니다.


B constructor

B::f

D constructor


D::f가 아님을 주의하세요.  D::f()가 B::B()에서 호출되도록 규칙이 달라지면 어떻게 될지 생각해봅시다. D::D() 생성자가 아직 실행이 되지 않았기 때문에, D::f()가 초기화되지 않은 string s에 인자를 대입할 것 입니다. 그리고 결과는 즉시 크래쉬가 날 것입니다.

파괴는 "기본 클래스 전에 파생 클래스"로 일어납니다, 그렇기 때문에 가상 함수는 생성자에서 처럼 동작합니다. 지역 정의들만 사용되고, 객체의 파생 클래스 부분을(막 파괴된) 건드리지 않으려면 오버라이딩된 함수를 호출하지 않습니다.


더 자세한 사항은 D&E 13.2.4.2나 TC++PL3 15.4.3을 참고하세요


이 규칙은 "implementation artifact"라고 제안되었습니다. 그렇지 않습니다. 실제로 생성자에서 가상 함수를 호출하는 안전하지 않은 규칙을 다른 함수에서와 똑같이 구현하는 것이 눈에 띄게 쉬울 것입니다. 그러나 이는 기본 클래스에 의해 설정된 불변성에 의존하기 위해 가상 함수를 작성할 수 없다는 것을 의미합니다. 정말 혼란스럽고 끔찍합니다.

댓글