C++에서 기본클래스의 생성자에서는 순수가상함수를 호출할 수 없다!?

다소 황당하기도 하고, 언젠가 책에서 본것같기도 한 내용입니다. 하지만 저는 당연이 되리라 생각했던지라… 왜 않되냐며 약간 열 받기도 하였습니다. 어떤 내용인냐면…

먼저 Base라는 클래스가 있고, 이 클래스는 A라는 순수 가상 함수가 있습니다.

class Base {
public:
	Base() { };

	void TTT() {
		A();
	}

public:
	virtual void A() = 0;
};

보시면 TTT라는 함수에서 A 함수를 호출하고 있구요. 이제 Base를 상속받는 Derv라는 함수를 정의해 봅니다.

class Derv : public Base {
public:
	virtual void A() {
		printf("impl");
	}
};

상속받는 클래스는 기본 클래스의 순수 가상 함수를 구현해야할 책임이 있으므로 A 함수를 구현합니다. 이제 Base 함수를 사용해 보면…

int _tmain(int argc, _TCHAR* argv[])
{
	Base *p = new Derv();

	p->TTT();

	delete p;

	return 0;
}

화면상에 “impl”이라는 문자가 찍힙니다. 잘됩니다. 그렇다면 Base 클래스를 아래처럼 수정합니다.

class Base {
public:
	Base() { A(); };

	void TTT() {
		A();
	}

public:
	virtual void A() = 0;
};

변경된 부분은 Base의 생성자에서 순사 가상 함수를 호출하고 있습니다. 실행해보면… 않됩니다. Base::A(void) 외부 기호를 확인할 수 없다는 경고입니다. 원래 C++ 표준도 않되는 것인지.. 아니면 MS의 C++ 만 않되는 것인지는 모르겠지만, 당연히 될줄알고 사용했던지라 매우 난감했습니다. 아무튼 않되는 것을 알았으니 돌아가야겠습니다.

“C++에서 기본클래스의 생성자에서는 순수가상함수를 호출할 수 없다!?”에 대한 4개의 댓글

  1. 다른 책에서도 언급되는 걸로 보아 다른 C++ 컴파일러에서도 마찬가지일 듯 합니다.(그러나 저도 MSVC 만 써 봤군요)
    OnCreate 같은 템플릿 메서드가 나오게 된 이유 중 하나는 이런 문제가 아닐까 하는 생각도 드네요.

  2. ParkPD님, 멋진 블로그를 운영하시는군요. 블로그에 접속하니.. 웅장한 음악이 나오길레 제 블로그에도 배경음악 넣어도 괜찬을듯하다.. 했습니다. 알고보니 게시글중 리니지 동영상에서 흘러나오는.. ^^;

  3. 생성자 호출이 완료 될 때까지 객체는 완성된 것이 아니라는 관점에서 본다면 오히려 가상함수를 (순수든 아니든간에) 호출하는게 잘못되었다고 볼 수 있습니다. 가상함수란건 각 타입에 맞는 함수를 호출한다는 의미니까요.

    구현상 가상함수 테이블을 구성하는 코드가 생성자에 숨어있는데 그 구성 전에 가상함수를 호출하게 되니 문제가 생기겠죠.

    생성자에서는 절대 가상함수를 사용해선 안됩니다.
    이게 말은 쉬운데 호출하는 함수가 가상이 아니더라도 그 함수가 다시 가상함수를 호출하는 경우도 마찬가지로 문제가 생깁니다.
    effective c++에 관련 항목이 있으니 읽어보시면 이해가 더 빠르실 겁니다.

  4. 지호님의 말씀 중에, “구현상 가상함수 테이블을 구성하는 코드가 생성자에 숨어있다”라는 것에, 왜 생성자에서는 가상함수 호출이 않되는지의 이유가 명확하게 들어나있군요.. 그런데, 생성자에서 가상함수를 호출해줘야할 필요성이 분명 있습니다. ParkPD님께서 말씀하신 OnCreate 같은 템플릿이 필요한 이유도 이때문이구요. 생성자에서 가상함수를 호출할 수 있다면 OnCreate 같은 템플릿도 필요없을텐데… 하지만 역시 지호님의 말씀처럼 가상함수테이블의 생성이 생성자에서 이루어진다라는 C++ 스펙대로라면, 생성자에서 가상함수 호출은 OnCreate 같은 템플릿을 이용하는 방법으로 가야겠습니다.

답글 남기기

이메일 주소는 공개되지 않습니다. 필수 필드는 *로 표시됩니다