책 정리/Effective C++ 3rd
항목 33. 상속된 이름을 숨기는 일을 피하자
ocean20
2020. 3. 9. 12:15
유효범위(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 선언 혹은 전달 함수를 쓸 수 있다.