책 정리/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 선언 혹은 전달 함수를 있다.