문제

이 질문에는 이미 답변이 있습니다.

다음 예에서 다음 명령문을 명시적으로 사용해야 하는 이유는 무엇입니까? b->A::DoSomething() 그냥보다는 b->DoSomething()?

컴파일러의 오버로드 해결이 내가 말하는 방법이 무엇인지 알아내면 안 됩니까?

저는 마이크로소프트 VS 2005를 사용하고 있습니다.(메모:이 경우 가상을 사용하는 것은 도움이 되지 않습니다.)

class A
{
  public:
    int DoSomething() {return 0;};
};

class B : public A
{
  public:
    int DoSomething(int x) {return 1;};
};

int main()
{
  B* b = new B();
  b->A::DoSomething();    //Why this?
  //b->DoSomething();    //Why not this? (Gives compiler error.)
  delete b;
  return 0;
}
도움이 되었습니까?

해결책

두 개의 "오버로드"는 동일한 범위에 있지 않습니다.기본적으로 컴파일러는 일치하는 이름을 찾을 때까지 가능한 가장 작은 이름 범위만 고려합니다.인수 일치가 완료되었습니다. 나중에.귀하의 경우 이는 컴파일러가 B::DoSomething.그런 다음 인수 목록과 일치하려고 시도하지만 실패합니다.

한 가지 해결책은 A ~ 안으로 B범위:

class B : public A {
public:
    using A::DoSomething;
    // …
}

다른 팁

오버로드 해결은 C++의 가장 추악한 부분 중 하나입니다.

기본적으로 컴파일러는 B 범위에서 이름 일치 "DoSomething(int)"를 찾고 매개 변수가 일치하지 않는 것을 확인하고 오류와 함께 중지합니다.

이는 클래스 B의 A::DoSomething을 사용하여 극복할 수 있습니다.

class A  
{  
  public:  
    int DoSomething() {return 0;}
};  

class B : public A  
{  
  public:  
    using A::DoSomething;
    int DoSomething(int x) {return 1;} 
};   


int main(int argc, char** argv)
{
  B* b = new B();  
  // b->A::DoSomething();    // still works, but...
  b->DoSomething();    // works now too
  delete b;  
  return 0;
}

아니요, 이 동작은 실수로 먼 기본 클래스에서 상속받는 일이 발생하지 않도록 하기 위해 존재합니다.

이 문제를 해결하려면 B 클래스에 A::DoSomething을 사용하여 호출하려는 메서드를 컴파일러에 알려야 합니다.

보다 이 기사 이 동작에 대한 빠르고 쉬운 개요를 확인하세요.

파생 클래스에 메서드가 있으면 기본 클래스에서 매개 변수에 관계없이 동일한 이름을 가진 모든 메서드가 숨겨집니다.이는 다음과 같은 문제를 피하기 위해 수행됩니다.

class A {} ;
class B :public A
{
    void DoSomething(long) {...}
}

B b;
b.DoSomething(1);     // calls B::DoSomething((long)1));

나중에 누군가 클래스 A를 변경합니다.

class A
{
    void DoSomething(int ) {...}
}

지금 갑자기:

B b;
b.DoSomething(1);     // calls A::DoSomething(1);

즉, 이렇게 작동하지 않으면 제어할 수 없는 클래스(A)에서 관련 없는 변경이 코드 작동 방식에 조용히 영향을 미칠 수 있습니다.

이는 이름 확인이 작동하는 방식과 관련이 있습니다.기본적으로 먼저 이름이 나오는 범위를 찾은 다음 해당 범위에서 해당 이름에 대한 모든 오버로드를 수집합니다.그러나 귀하의 경우 범위는 클래스 B이고 클래스 B에서는 B::DoSomething입니다. 숨기다 A::D뭔가:

3.3.7 이름 숨기기 [basic.scope.hiding]

...[한조각]...

3 멤버 기능 정의에서 로컬 이름 선언은 동일한 이름의 클래스 구성원의 선언을 숨 깁니다.보다 기본.범위.클래스.파생 클래스에서 회원의 선언 (클래스.파생) 동일한 이름의 기본 클래스 구성원의 선언을 숨 깁니다.보다 클래스.멤버.조회.

이름 숨김으로 인해 A::DoSomething은 오버로드 해결에도 고려되지 않습니다.

파생 클래스에서 함수를 정의하면 기본 클래스에서 해당 이름을 가진 모든 함수가 숨겨집니다.기본 클래스 함수가 ​​가상이고 호환 가능한 서명이 있는 경우 파생 클래스 함수도 기본 클래스 함수를 재정의합니다.그러나 이는 가시성에 영향을 미치지 않습니다.

using 선언을 사용하여 기본 클래스 함수를 표시할 수 있습니다.

class B : public A  
{  
  public:  
    int DoSomething(int x) {return 1;};  
    using A::DoSomething;
};  

과부하가 아닙니다!그게 숨어 있어요!

사용할 함수에 대한 상속 트리를 검색할 때 C++는 인수 없이 이름을 사용하고 일단 정의를 찾으면 중지한 다음 인수를 검사합니다.주어진 예에서는 클래스 B에서 중지됩니다.원하는 작업을 수행하려면 클래스 B를 다음과 같이 정의해야 합니다.

class B : public A  
{  
  public:
    using A::DoSomething;
    int DoSomething(int x) {return 1;};  
}; 

함수는 하위 클래스에서 이름이 같지만 서명이 다른 함수에 의해 숨겨집니다.A::DoSomething();을 사용하는 것처럼 using 문을 사용하여 숨기기를 해제할 수 있습니다.

라이센스 : CC-BY-SA ~와 함께 속성
제휴하지 않습니다 StackOverflow
scroll top