어떤 함수에 대해서도 상속받은 기본 매개변수 값은
절대로 재정의하지 말자.
가상 함수는 동적으로 바인딩되지만,
기본 매개변수 값은 정적으로 바인딩된다.
class AAA{
public:
enum num { first , second , third };
virtual void show(num n = first);
}
class BBB : public AAA{
public:
virtual void show(num n = second);
}
class CCC : public AAA{
public:
virtual void show(inum n);
}
AAA *pa;
AAA *pb = new BBB;
AAA *pc = new CCC;
여기서 pb, pc는 모두 AAA에 대한 포인터로
선언되었기 때문에, 각각의 정적 타입도 모두 이 타입니다.
객체의 동적 타입은 현재 그 객체가 진짜로 무엇이냐에
따라 결정되는 타입니다. 다시 말해, '이 객체가 어떻게
동작할 것이냐'를 가리키는 타입이 동적 타입이다.
따라서 pb의 동적타입은 BBB*
pc의 동적 타입은 CCC*
pa는 동적 타입이 없다.
pb->show();
문제는 이 가상함수를 호출했을 때 발생한다.
파생 클래스에 정의된 가상 함수를 호출하면서
기본 클래스에 정의된 기본 매개변수 값을
사용해 버릴 수 있다는 것이다.
pb의 동적타입은 BBB*이기 때문에
함수는 BBB::show가 호출되지만
기본 매개변수 값은 AAA에서 가져온다.
이러한 동작방식은 런타임 효율이라는 요소가 숨어있다.
프로그램 실행 중에 가상 함수의 기본 매개변수 값을
결정할 방법을 컴파일러 쪽에서 마련해 주어야 하는데,
이 방법은 컴파일 과정에서 결정하는 현재의 메커니즘보다
느리고 복잡하다. 때문에 속도와 구현 간편성에 무게를
더 두어야 했고, 그 덕에 효율 좋은 실행 동작을 누릴 수 있게 되었다.
그렇다면 원하는 대로 가상함수가 동작하도록 만들어보자.
그 전 포스팅에서도 언급했던 NVI 관용구를 써보자.
class AAA{
public:
enum num { first , second , third };
void show ( num n = first ) const {
doShow(n);
}
private:
virtual void doShow(num n) const = 0;
}
class BBB : public AAA{
public:
...
private:
virtual void doShow(num n) const;
};
비가상 함수는 파생 클래스에서 오버라이드되면 안 되기 떄문에
위와 같이 설계한다면, 기본 매개변수에 대한 문제를 해결할 수 있다.
POINT!!
상속받은 기본 매개변수 값은 절대로 재정의해서는 안된다.
기본 매개변수 값은 정적으로 바인딩되는 반면, 가상 함수는
동적으로 바인딩되기 때문이다.
'C++ 심화' 카테고리의 다른 글
[C++] public 상속은 반드시 is-a 관계를 따르도록 하자. (0) | 2017.03.29 |
---|---|
[C++] 타입 변환이 모든 매개변수에 적용되어야 한다면 비멤버 함수 (0) | 2017.03.04 |
[C++] 상속받은 비가상 함수의 재정의 (0) | 2017.02.21 |
[C++] 오버로딩 된 함수의 상속, using 선언 (0) | 2017.02.21 |
[C++] 인터페이스 상속과 구현 상속의 차이(3) (0) | 2017.02.20 |