KoreanFoodie's Study

Effective C++ | 항목 36 : 상속받은 비가상 함수를 파생 클래스에서 재정의하는 것은 절대 금물! 본문

Tutorials/C++ : Advanced

Effective C++ | 항목 36 : 상속받은 비가상 함수를 파생 클래스에서 재정의하는 것은 절대 금물!

GoldGiver 2022. 10. 25. 16:28

C++ 프로그래머의 필독서이자 바이블인, 스콧 마이어스의 Modern Effective C++ 를 읽고 기억할 내용을 요약하고 있습니다. 꼭 읽어보시길 추천드립니다!

항목 36 : 상속받은 비가상 함수를 파생 클래스에서 재정의하는 것은 절대 금물!

핵심 :

상속받은 비가상 함수를 재정의하는 일은 절대로 하지 말자


사실 이 항목은 당연하다면 당연한데, 비가상 함수를 상속받는다는 것은 기반 클래스의 인터페이스와 구현을 모두 물려받는다는 뜻이므로 파생클래스에서 재정의한다는게 이론적으로도 모순되게 된다. 해당 기반 클래스를 물려받은 클래스는 해당 비가상 클래스를 호출할 때 기반 클래스에서 의도한 비가상 함수의 동작을 그대로 재현해야 하기 때문이다!
예시를 하나 보자.

class B
{
public:
	void mf() {}
};

class D: public B 
{
public:
	// B::mf 를 가린다
	void mf() {}
};


int main()
{
	D x;

	B *pB = &x;
	pB->mf();

	D *pD = &x;
	pD->mf();
}

위와 같이 되면, pD 에서의 mf 함수 호출은 D::mf 를 호출한다. 이는 비가상 함수는 정적 바인팅(static binding) 으로 묶여 있어서 포인터 타입에 맞는 함수가 호출된다. 반면, 가상 함수는 동적 바인딩(dynamically binding) 으로 묶여 pB 및 pD 가 진짜로 가리키는 D 타입 객체의 함수가 호출된다.
참고로, 정적 바인딩은 빌드 중에 타입이 정해지고, 동적 바인딩은 런타임에 정해진다. 하지만 C++ 의 가상 함수의 바인딩은 문서상으로는 동적 바인딩이지만, 구현상으로는 런타임 성능을 높이기 위해 정적 바인딩을 쓰고 있다. 즉, 컴파일 중에 아예 가상 함수 테이블을 파생 클래스에 맞게 바꿈으로써, 겉보이게은 파생 클래스 타입에서 오버라이드한 가상 함수를 호출하는 것처럼 보이게 만든다.

Comments