유효범위(scope)에 대해 알고있을 것이다.
int x; // 전역변수
void func()
{
double x; //지역변수
cin >> x; // 지역변수 double x를 입력받는다.
}
컴파일러가 x를 추적할때 func함수를 먼저 살핀다.
타입은 중요치않다. 어쨌든 double x가 int x의 이름을 가리게 된다.
이제 상속얘기를 해보자.
기본 클래스에 속해 있는것을 파생클래스가 참조한다면 컴파일러는 이 참조대상을 바로 찾을 수 있다.
class Base{
private:
int x;
public:
virtual void mf1() = 0; //순수 가상함수
virtual void mf2(); // 가상함수
void mf3(); // 비가상함수
};
class Derived : public Base{
public :
virtual void mf1(); // Base의 mf1이 아닌 Derived의 mf1()을 호출한다.
void mf4() { … mf2() ; } // 컴파일러가 mf2를 우선순위가 높은 유효범위 부터 탐색하다가 베이스 클래스에서 찾게된다.
};
Q. 만약 Base 클래스에서 mf1을 매개변수가 있는 mf1()으로 오버라이딩 했다고 생각해보자.
class Base{
private :
...
public :
virtual void mf1() = 0 ;
virtual void mf1(int); //오버라이딩된 mf1();
...
}
또한 Dervied는 좀전 예제와 동일하게, Base를 상속받았다고 가정해보자.
Derived d;
int x;
d.mf1(); // OK !
d.mf1(x); // Error !! , Derived::mf1 이 Base::mf1을 가리게 된다.
위 sample의 의도는 기본 클래스로부터 오버로드 버전을 상속시키는 경우를 막겠다는 의도이다.
사실 이건 32장에서 공부한 "is-a" 관계 위반이다.
해결 방안은 다음과 같다.
class Derived : public Base {
public :
using Base::mf1; // Base에 있는 mf1을 Derived의 유효범위 내로 가져온다.
virtual void mf1(); // 자식클래스에서 오버라이딩하고싶은것만 오버라이딩한다.
};
즉, using 선언을 하면 그 이름에 해당되는 것들이 모두 파생클래스로 내려간다.
그렇다면 만약 필요한것 들만 상속받고 싶다면?
--> private 상속을 받고, 전달함수(forwarding function)을 만들어 놓는것이다.
class Base {
public :
virtual void mf1() = 0 ;
virtual void mf1(int);
};
class Derived: private Base {
public :
virtual void mf1() // 전달함수
{ Base::mf1() ;} // 암시적으로 인라인함수가 된다.
};
이것만은 잊지 말자!
- 파생클래스의 이름은 기본클래스의 이름을 가린다. public 상속에서 이런 가림현상을 바람직하지 않다.
- 가려진 이름을 볼 수 있는 방법으로, using 선언 혹은 전달 함수를 쓸 수 있다.
'책 정리 > Effective C++ 3rd' 카테고리의 다른 글
항목 35. 가상 함수 대신 쓸 것들도 생각해 두는 자세를 시시때때로 길러 두자 (0) | 2020.03.10 |
---|---|
항목 34. 인터페이스 상속과 구현 상속의 차이를 제대로 파악하고 구별하자 (0) | 2020.03.09 |
항목 32. public 상속 모형은 반드시 "is-a"를 따르도록 만들자 (0) | 2020.03.09 |
항목 30. 인라인 함수는 미주알고주알 따져서 이해해 두자 (0) | 2020.03.06 |
항목 29. 예외 안전성이 확보되는 그날 위해 싸우고 또 싸우자 (0) | 2020.03.05 |
댓글