본문 바로가기
C++

[Effective C++] 상속받은 비가상 함수를 파생클래스에서 재정의 하지 말자

by Warehaus 2021. 6. 11.

주요 개념은 클래스를 상속받는 하위 클래스에서 상위 클래스에 있는 비 가상함수를 재정의 하게되는 경우 생각하지 못한 동작이 발생할 수 있다는 부분을 설명해 준다.

코드 예시를 보자.

class Fruit
{
public:
    void get();
    ...
};

class Apple : public Fruit {
...
};

위 코드를 바탕으로 아래처럼 구현 시 결과가 생각과 다를 수 있다. 

Apple a;

Fruid *f = &a;
f->get(); // a 에 대한 포인터로 get을 호출한다.

// 위의 코드는 아래 코드처럼 동작하기를 기대하면서 작성되었다.
Apple *aa = &a;
aa->get();

// 하지만, Apple 에서 get을 다시 정의하는 경우 문제가 발생한다.

class Apple : public Fruit
{
public:
    void get(); // Fruit의 get 함수를 가린다.
};

f->get(); // Fruit의 get을 호출
aa->get(); // Apple의 get을 호출

이런 결과가 나타나는 이유는 비 가상함수는 정적 바인딩으로 묶이기 때문에, 포인터 타입으로 호출 클래스 범위를 정의하기 때문이다.

반면, 가상함수는 동적 바인딩으로 묶이기 때문에 이를 재 정의 하려는 의도였다면 Fruit의 get을 virtual로 선언해서 다시 구현했어야 하는게 맞다.

어떤 용도가 되었건, 비가상 함수를 하위 클래스에서 다시 정의함으로써 호출 시 원하지 않는 결과를 얻지 않도록 해야한다는 게 이 내용의 핵심이니, 몸에 익혀두도록 하는게 좋겠다.