2012-01-28 3 views
10
void foo(int) 
{ 
} 

class X 
{ 
    void foo() 
    { 
    } 

    void bar() 
    { 
     foo(42); 
     // error: no matching function for call to 'X::foo(int)' 
     // note: candidate is: 
     // note: void X::foo() 
     // note: candidate expects 0 arguments, 1 provided   
    } 
}; 

왜 C++은 무료 함수 (올바른 서명이있는 유일한 함수)를 호출 할 수 없습니까?멤버 함수 숨기기 무료 함수

+2

이 경우':: foo (42)'를 사용하여 외부 foo에 액세스 할 수 있습니다. [Ideone demo] (http://ideone.com/6HljO). 그러나 나는 네임 스페이스에 대해 많이 모른다. –

+0

나는 이것을 C++의 하나의 아킬레스 건으로 생각한다. isempty (thing)와 같이 일반적인 오버로드 된 자유 함수 이름을 사용하는 것이 불가능합니다. isempty (thing)는 주어진 유형의 isempty에 과부하가 많이 걸리는 반면 thing.isempty()도 존재할 수 있습니다. 어리석은, 불행한, clunky. – Mordachai

답변

5

논리적 이유는 일관성입니다 :

이 예에서 전역 함수를 호출하려면 :: 구문을 사용합니다. 제안에 따라 가정하자

  • 는 컴파일러 ::foo(int)foo(42)를 해결한다.
  • 이제 X::foo()X::foo(int)으로 변경하면 foo(42)X::foo(int)으로 확인됩니다. 일관성이 없습니다.

비슷한 이름이있을 때 파생 클래스 함수가 ​​기본 클래스 함수를 숨기는 이유이기도합니다.

이러한 경우는 2 가지 방법으로 해결할 수 있습니다.

(1) 완전한 이름을 지정합니다 (예를 들어, ::foo(42))

(2) using 유틸리티를 사용하여; 예 :

void bar() 
{ 
    using ::foo; 
    foo(42); 
} 
+1

누군가 나중에 foo (int) 멤버를 추가하면 명시 적으로이를 의도합니다. 나쁜 언어 디자인, IMO. – Mordachai

12

두 개의 식별자가 서로 다른 범위에 정의되어 있고 과부하 해결은 동일한 범위에있는 기능에만 관심이 있으므로. 컴파일러에서 클래스에 foo이 있으면 넓은 범위 (C++ 11 §3.4.1/1)로 올라가는 것을 중지하므로 무료 함수 foo이 숨겨집니다. - 내가 언어 사양에서 그 뒤에있는 근거 무엇인지 모르는

::foo(42); 
+1

참고 : 이것은 'int'때문에 특별한 경우이며, ADL이 좋기 때문에 여전히 작동합니다. –

0

내가 당신의 질문의 이유 부분에 대답 할 수 없습니다

당신은 세계 foo를 참조 할 자격이 이름을 사용해야합니다 .

::foo(42); 
0

이 이유는 컴파일러가 반환 값과 매개 변수를 무시하고 일치하는 함수 이름을 먼저 찾습니다. 클래스 내부에서 일치하는 멤버를 찾으려고 할 것입니다 (사실 상향 스코프, 로컬 스코프, 함수 스코프, 클래스 스코프, 네임 스페이스 스코프, 전역 스코프 등 모든 스코프를 보게됩니다).).

X::foo이 처음으로 일치하는 이름입니다. 그런 다음 (여러 개의 선언이있는 경우) 매개 변수를 기반으로 올바른 오버로드를 선택하려고 시도합니다 (다른 매개 변수로 동일한 함수에 오버로드 할 수 있지만 다른 반환 값만 오버로드 할 수있는 이유 임). 반환 값 (있는 경우).

1

정말 질문이 있으십니까?또한 나는이 구문을 사용, 말할 수 :

::foo(42); 

을하지만 이런 식으로 뭔가 쓸 수 있도록 나는, 내 의견으로는 더 우아하고 좋은 프로그래밍, 세트 네임 스페이스 있다고 말할 수있다 :

namespace MyNameSpace 
{ 
    void foo(int){} 

    class X 
    { 
     void foo(){} 

     void bar() 
     { 
      MyNameSpace::foo(42); 
     } 
    }; 
}; 

이를 Namespaces은 이름 아래 클래스, 개체 및 기능을 그룹화 할 수 있기 때문에 좋은 것입니다.

추신 : 그러면 네임 스페이스가 없을 때 ::foo(42);의 의미를 이해하는 데 도움이됩니다.

2

내부 범위의 이름은 외부 범위의 이름을 숨 깁니다. 함수가 아니면 다른 것이거나 클래스 또는 네임 스페이스에있는 경우에는 중요하지 않습니다.

같은 이름의 여러 기능을 이름 검색에서 찾으면 과부하 해결로 통화에 가장 적합한 것이 선택됩니다.