C++의 이름 가리기 규칙에 의하면 안쪽 유효범위에 있는 이름이 바깥쪽 유효범위에 있는 이름을 가린다.
컴파일러는 자신이 처리하고 있는 유효범위에서 같은 이름을 가진 것이 있는지 찾는다.
int x; // 전역 변수
void someFunc()
{
double x; // 지역 변수
cin >> x;
}
cin >> x;
에서 x
는 지역 변수인 double x 이다. (전역 변수 x
의 타입은 중요하지 않다.)
class Base
{
private:
int x;
public:
virtual void mf1() = 0;
virtual void mf2();
void mf3();
...
};
class Derived : public Base
{
public:
virtual void mf1();
void mf4();
...
};
void Derived::mf4()
{
...
mf2();
...
}
컴파일러가 mf4()
에서 호출하는 mf2()
가 어느 것인지 파악하는 과정
mf4
의 유효범위) 탐색mf4
유효범위를 감싸는 유효범위(Derived
유효범위)를 찾아 탐색Derived
유효범위를 감싸는 유효범위(Base
유효범위)를 찾아 탐색 > 찾았다!Base
를 둘러싸는 네임스페이스, 전역 유효범위까지 탐색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(); // Success. Derived::mf1 호출
d.mf1(x); // Error. Derived::mf1이 Base::mf1을 가린다
d.mf2(); // Success. Basse::mf2 호출
d.mf3(); // Success. Derived::mf3 호출
d.mf3(x); // Error. Derived::mf3이 Base::mf3을 가린다
Base::mf1(int)
, Base::mf3(double)
이 Derived
의 mf1
, mf3
에 의해 가려진다.
이름 가리기 규칙에 의하면 함수의 매개변수 타입의 차이나 가상/비가상 함수 여부와는 상관없이 이름이 가려진다.는 것을 알 수 있다.
위의 예시처럼 public 상속에서 기본 클래스의 함수 중 몇 개만 재정의 하면,
기본 클래스의 오버로드된 다른 함수들이 파생 클래스 함수 이름에 가려져 사용할 수 없게 된다.
일반적으로 다른 오버로드된 함수들을 상속받고 싶을 것이며 그렇지 않다면 이는 is-a 관계에도 위반된다.
이런 상황에서 이름 가리기 규칙을 피해보자.
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:
using Base::mf1;
using Base::mf3;
virtual void mf1();
void mf3();
void mf4();
...
};
d.mf1(x); // Success. Base::mf1 호출
d.mf3(x); // Success. Base::mf3 호출
이전에는 볼 수 없었던 Base::mf1(int)
, Base::mf3(double)
를 볼 수 있게 되었다.
using 선언을 하면 mf1(int)
도 사용할 수 있게 되어버린다.
Derived
가 mf1()
만 상속하고 싶다면, private 상속과 전달 함수를 이용한다.
class Base
{
public:
virtual void mf1() = 0;
virtual void mf1(int);
...
};
class Derived : private Base
{
public:
virtual void mf1() { Base::mf1(); } // 인라인 함수이며 전달 함수
...
};
정리
- 파생 클래스의 이름은 기본 클래스의 이름을 가린다. public 상속에서는 바람직하지 않은 현상
- 가려진 이름을 다시 볼 수 있게 using 또는 전달 함수를 사용