당신의 질문의 말로 판단하면 ( "숨기기"라는 단어를 사용했습니다), 당신은 이미 여기서 무슨 일이 일어나고 있는지 알고 있습니다. 이 현상을 "이름 숨기기"라고합니다. 어떤 이유로 누군가가 이름 숨기기가 발생 하는 이유 에 대해 질문 할 때마다 응답하는 사람들은 "이름 숨기기"라고 말하고 작동 방식 (아마 이미 알고 있음)을 설명하거나 무시하는 방법 ( 에 대해 묻지 않았지만 실제 "이유"질문을 다루는 사람은 아무도 없습니다.
이름 숨김의 근거, 즉 실제로 C ++로 설계된 이유에 대한 결정 은 상속 된 오버로드 된 함수 집합이 현재의 주어진 클래스에서 과부하. C ++에서 과부하 해결은 후보 세트에서 최상의 기능을 선택하여 작동한다는 것을 알고있을 것입니다. 이는 인수 유형을 매개 변수 유형과 일치시켜 수행됩니다. 일치 규칙은 때때로 복잡 할 수 있으며 종종 준비되지 않은 사용자에 의해 비논리적 인 것으로 인식 될 수 있습니다. 기존 기능 세트에 새 기능을 추가하면 과부하 해결 결과가 다소 급격히 변할 수 있습니다.
예를 들어, 기본 클래스 에 유형의 매개 변수를 사용 B
하는 멤버 함수 foo
가 void *
있고에 대한 모든 호출 foo(NULL)
이 해결 되었다고 가정 해 봅시다 B::foo(void *)
. 숨어있는 이름이 없으며이 이름이 B::foo(void *)
에서 유래하는 많은 다른 클래스에서 볼 수 있다고 가정 해 봅시다 B
. 그러나 D
클래스 B
의 일부 [간접, 원격] 자손 에서 함수 foo(int)
가 정의 되었다고 가정 해 봅시다 . 이제 이름 숨기지 않고 D
모두가 foo(void *)
와 foo(int)
가시와 오버로드 확인에 참여합니다. foo(NULL)
유형의 객체를 통해 호출되는 경우 어떤 함수를 해결할 D
것인가? 그들은으로 해결할 수 D::foo(int)
있기 때문에,int
통합 제로를위한 더 나은 일치 (예 :NULL
)보다 모든 포인터 유형. 따라서 계층 구조 전체에서 foo(NULL)
하나의 함수 로 해결하도록 요청하는 반면, 내부 D
및 아래로 갑자기 다른 기능으로 해결됩니다.
또 다른 예는 C ++의 디자인과 진화 페이지 77에 나와 있습니다.
class Base {
int x;
public:
virtual void copy(Base* p) { x = p-> x; }
};
class Derived{
int xx;
public:
virtual void copy(Derived* p) { xx = p->xx; Base::copy(p); }
};
void f(Base a, Derived b)
{
a.copy(&b); // ok: copy Base part of b
b.copy(&a); // error: copy(Base*) is hidden by copy(Derived*)
}
이 규칙이 없으면 b의 상태가 부분적으로 업데이트되어 슬라이싱이 발생합니다.
이 동작은 언어를 디자인 할 때 바람직하지 않은 것으로 간주되었습니다. 더 나은 접근 방식으로, "이름 숨기기"사양을 따르기로 결정했습니다. 즉, 각 클래스는 선언하는 각 메소드 이름과 관련하여 "클린 시트"로 시작합니다. 이 동작을 무시하려면 사용자에게 명시 적 조치가 필요합니다. 원래 상속 된 메소드 (현재 사용되지 않음)의 재 선언, 이제는 명시 적으로 using-declaration을 사용합니다.
원래 게시물에서 올바르게 관찰 한 것처럼 ( "다형성이 아님"설명 참조)이 동작은 클래스 간 IS-A 관계 위반으로 간주 될 수 있습니다. 이것은 사실이지만, 분명히 그 당시에는 숨기는 것이 더 악한 것으로 판명되었습니다.