Effective C++/Effective C++
[Effective C++] 37. 상속된 함수의 매개변수 기본값 재정의 문제
김디트
2024. 7. 5. 09:48
728x90
항목 37. 어떤 함수에 대해서도 상속받은 기본 매개변수 값은 절대로 재정의하지 말자
기본 매개변수 값을 재정의할 시 문제 상황
class Shape
{
public:
enum ShapeColor { Red, Green, Blue };
virtual void draw(ShapeColor color = Red) const = 0;
...
};
class Rectangle : public Shape
{
public:
virtual void draw(ShapeColor color = Green) const; // 기본 매개변수 재정의!!!
...
};
Shape* ps;
Shape* pr = new Rectangle;
pr->darw(); // Rectangle::draw(Shape::Red)를 호출한다!!!!
- 호출 함수의 경우 동적 타입에서 가져오지만, 매개변수의 경우 정적 타입에서 가져온다.
- 즉, 기본 매개변수 재정의가 되어있는 경우, 정적 타입에 따라 기본 매개변수가 마구 변경되기에 동작을 예측하기 쉽지 않다!
정적 타입과 동적 타입
- 정적 타입(static type)
- 선언문을 통해 그 객체가 갖는 타입.
- 동적 타입(dynamic type)
- 현재 그 객체가 진짜로 무엇이냐에 따라 결정되는 타입.
Shape* pr = new Rectangle;
// 정적 타입 : Shape
// 동적 타입 : Rectangle
C++이 이런 방식을 고집하는 이유
- 런타임 효율 문제
- 기본 매개변수가 동적으로 바인딩된다면?
- 런타임 중 가상함수의 기본 매개변수 값을 결정할 방법을 컴파일러 쪽에서 마련해야 한다.
- 이는 현재 메커니즘보다 느리고 복잡할 것이 분명하다.
- 기본 매개변수를 사용하는 경우가 한정적이므로 효율을 선택했을 것이다.
- 기본 매개변수가 동적으로 바인딩된다면?
파생 클래스가 기본 매개변수 값을 똑같이 제공한다면?
class Shape
{
public:
virtual void draw(ShapeColor color = Red) const = 0;
...
};
class Rectangle : public Shape
{
public:
virtual void draw(ShapeColor color = Red) const;
...
};
- 문제점
- 코드 중복이며, 의존성까지 걸려있다.
- 부모 클래스 draw의 기본 매개변수를 변경한다면?
- 상속받은 기본 매개변수 값을 재정의하는 꼴이나 마찬가지가 되므로 파생 클래스 쪽도 손봐줘야 한다.
- 코드 중복이며, 의존성까지 걸려있다.
해결 방법
- 가상 함수 대신 사용할 수 있는 방법들을 활용하자.(항목 35 참조)
- 비가상 인터페이스 관용구(NVI 관용구)를 사용해 보자.
class Shape
{
public:
// 비가상 함수에 기본 매개변수 처리
void draw(ShapeColor color = Red) const
{
// 가상 함수 호출
doDraw(color);
}
...
private:
virtual void doDraw(ShapeColor color) const = 0;
};
class Rectangle : public Shape
{
public:
...
private:
virtual void doDraw(ShapeColor color) const;
...
};
728x90