어떤 함수에 대해서도 상속받은 기본 매개변수 값은

절대로 재정의하지 말자.


가상 함수는 동적으로 바인딩되지만,

기본 매개변수 값은 정적으로 바인딩된다.




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!!

상속받은 기본 매개변수 값은 절대로 재정의해서는 안된다.

기본 매개변수 값은 정적으로 바인딩되는 반면, 가상 함수는

동적으로 바인딩되기 때문이다.


+ Recent posts