스토리텔링 개발자

[Effective C++] 33. 상속된 이름 가리기 문제 본문

Effective C++/Effective C++

[Effective C++] 33. 상속된 이름 가리기 문제

김디트 2024. 7. 2. 14:06
728x90

항목 33. 상속된 이름을 숨기는 일은 피하자

 

 

 

상속과 유효범위
  • 상속 역시 유효범위로 취급한다.
  • 유효범위 내에서 이름을 찾지 못하면 상위 유효범위를 탐색한다.

 

 

 

C++ 이름 가리기 규칙
  • c++의 이름 가리기 규칙은 단지 이름만으로 유효범위를 탐색하고, 가려버린다.
  • 그렇기에 아래와 같은 문제가 발생할 수 있다. 
class Base
{
private:
    int x;
public
    virtual void mf1() = 0;
    virtual void mf1(int);
    
    virtual void mf2();
    
    void mf3();
    void mf3(double);
    ...
};

class Derived : public Base
{
public:
    virtual void mf1();
    void mf3();
    void mf4();
    ...
};


Derived d;
int x;
...
d.mf1(); // 컴파일 성공
d.mf1(x); // 에러! Derived::mf1이 Base::mf1을 가려서 찾을 수 없다.

d.mf2(); // 컴파일 성공

d.mf3(); // 컴파일 성공
d.mf3(x); // 에러! Derived:mf3이 Base::mf3을 가려서 찾을 수 없다.
  • 함수의 매개변수, 리턴값, 심지어 가상 비가상 여부조차 가리지 않고 이름을 가려버린다.

 

 

 

상속 시 이름가리기 규칙의 의미
  • 어떤 라이브러리나 프레임워크로 파생 클래스를 만들 때, 멀리 떨어진 기본 클래스로부터 오버로드 버전을 상속받아 버리는 경우를 실수로 간주하겠다는 의도일 것이다.
  • 허나 오버로드 버전을 상속하고 싶은 경우가 너무나 많은 문제가 있다.

 

 

 

가려진 이름 꺼내기
  • 가려진 이름은 using 선언으로 끄집어낼 수 있다.
class Base 
{ 
public: 
    virtual void mf1() = 0; 
    virtual void mf1(int); 
    void mf3(); 
    void mf3(double); 
} 
class Derived : public Base 
{ 
public: 
    using Base::mf1;
    using Base::mf3;
    // 유효 범위 내에서 볼 수 있도록 using 처리
    
    virtual void mf1(); 
    void mf3(); 
};
    • using 기법으로는, 기본 클래스가 가진 함수 중 일부만 상속하고 싶은 경우에 대한 처리가 불가능하다.
      • 전달 함수를 정의하여 해결한다.
      • using을 지원하지 않는 컴파일러에서도 유용할 것이다.
class Base 
{ 
public: 
    virtual void mf1() = 0; 
    virtual void mf1(int); 
    ...
} 
class Derived : private Base // private 상속이므로 각 public 부모 함수들은 private화
{ 
public: 
    virtual void mf1() { Base::mf1(); } // 전달 함수로 처리한다.
    ...
};

 

 

 

  • 템플릿 클래스 상속과 엮일 경우 다른 문제가 발생한다.(항목 43 참조)
728x90
Comments