http://www.stroustrup.com/bs_faq2.html#vcall
답은 호출 할 수 있다. 하지만 사용하는데 조심해야 한다.
예상치 못한 일이 발생 할 수 있기 때문이다. 생성자 함수 내에서 가상함수를 호출하는 메카니즘은 사실 무의미하다. 왜냐면 파생클래스로부터의 오버라이딩이 아직 발생하지 않았기 때문이다. 모든 객체들은 "base before derived" 라는 기본 개념을 기반으로 설계 되어진다.
아래 예제 코드를 보자.
#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 가 아니다!! 어찌보면 너무 당연해보이지만.. 만약 B::B()로부터 D::f()가 호출되기 위해서 그 규칙이 다르다면 어떨지 생각해봐라. D::D() 생성자는 아직 실행되기도 전이기 때문에 D::f() 함수는 초기화 되지도 않은 string s를 할당하려고 할 것이다. 그 결과는 거의 곧 바로 크래쉬가 날 것이 뻔하다.
소멸자는 "derived class before base class" 을 기반으로 한다. 그래서 가상함수들은 생성자함수 내에서 처럼 동작한다. 오직 로컬 정의들만 사용되어진다. 그리고 현재 지워진 파생된 클래스를 건드리지 않기 위해 호출을 하지 않는다.
그동안 이것은 구현상의 제약사항으로 제안되어져 왔다. 하지만 그렇지 않다. 실제론 일반 함수내에서 가상함수를 호출하는 것처럼 생성자에서 호출하는 것은 안전하지 않은 규칙으로 여기는 것이 더 쉬울것이다.
댓글 없음:
댓글 쓰기