2011-03-20 2 views
44

다음 코드는 컴파일시 오류 "foo는 할 ambigious 호출은"생산, 나는이 문제를 어떤 방법이 있는지 완전히 foo를하기 위해 전화를 자격없이 알고 싶습니다 :이름이 같지만 서명이 다른 다중 상속 된 함수가 오버로드 된 함수로 취급되지 않는 이유는 무엇입니까?

그래서
#include <iostream> 

struct Base1{ 
    void foo(int){ 
    } 
}; 

struct Base2{ 
    void foo(float){ 
    } 
}; 

struct Derived : public Base1, public Base2{ 
}; 

int main(){ 
    Derived d; 
    d.foo(5); 

    std::cin.get(); 
    return 0; 
} 

, 질문을 제목이 말하는대로입니다. 아이디어? 내 말은, 다음은 완벽하게 작동한다는 것입니다.

#include <iostream> 

struct Base{ 
    void foo(int){ 
    } 
}; 

struct Derived : public Base{ 
    void foo(float){ 
    } 
}; 

int main(){ 
    Derived d; 
    d.foo(5); 

    std::cin.get(); 
    return 0; 
} 
+2

두 번째 foo (두 번째 경우)에서 logging 문을 호출하여 함수가 호출되는 상수에 추가하면 놀랄 것입니다. C++은 난잡한 규칙으로 가득합니다.) –

+1

@Matthieu : * gasp *! 빌어 먹을 숨어있는 규칙. : – Xeo

답변

42

회원 룩업 규칙 10.2/2

다음 단계는, 클래스 범위를 C 이름 조회 결과를 정의 섹션에 정의되어있다. 먼저, 클래스 및 각 기본 클래스 하위 객체의 이름에 대한 모든 선언이 고려됩니다. AB의 기본 클래스의 하위 개체 인 경우 하나의 서브 - 객체 B의 구성원 이름 f은 부 객체에서 A 멤버 이름 f을 숨긴다. 이렇게 숨겨진 모든 선언은 고려 사항에서 제거됩니다. 사용 선언에 의해 도입 된 이러한 선언 각각은 사용 선언에 의해 지정된 선언을 포함하는 유형 인 C의 각 하위 오브젝트로 간주됩니다. 선언의 결과 세트는 동일한 타입의 서브 - 객체의 모든 없거나 세트는 비 정적 부재를 갖고 뚜렷한 하위 개체의 구성원을 포함하는 경우 은 모호성이 있고 프로그램 아프 형성된다. 그렇지 않으면 해당 집합이 조회의 결과입니다.

class A { 
public: 
    int f(int); 

}; 
class B { 
public: 
    int f(); 

}; 
class C : public A, public B {}; 
int main() 
{ 
    C c; 
    c.f(); // ambiguous 
} 

그래서 당신은 모호함 void foo(float)가 C의 범위 내에 있기 때문에 두 번째 코드는 완벽하게 작동

class C : public A, public B { 
    using A::f; 
    using B::f; 

}; 

int main() 
{ 
    C c; 
    c.f(); // fine 
} 

를 해결하기 위해 using 선언 A::fB::f를 사용할 수 있습니다. 사실 d.foo(5);void foo(float) 아닌 int 버전을 호출합니다.

+2

'void foo (float)'버전이 정말로 거기에 있습니다. 광범위한 대답을 주셔서 감사합니다. :) – Xeo

+1

마음에 떠오르는 한 가지 ... 상황이 있습니다. 서명이 다른 경우 기본 클래스 함수? 똑같은 서명 함수들에 대해서는 확실히 유용하지만 다른 것들에 대해서는 좋은 예제를 상상할 수 없습니다. – Xeo

+0

+1. 아주 좋아. 나는 이것을 몰랐다. 감사합니다 Prasoon. :-) – Nawaz

2

효과가 있습니까?

struct Derived : public Base1, public Base2{ 
    using Base2::foo;} 
2

이름 조회과부하 해결과는 별도의 단계입니다.

이름 조회가 먼저 발생합니다. 이것이 이름이 적용되는 범위를 결정하는 과정입니다. 이 경우 d.food.D::foo 또는 d.B1::foo 또는 d.B2::foo을 의미하는지 여부를 결정해야합니다. 이름 검색 규칙은 함수 매개 변수 나 다른 것을 고려하지 않습니다. 그것은 이름과 범위에 관한 것입니다.

한 번만 결정한 후에는 이름이있는 범위의 함수 오버로드에 대해 과부하 해결을 수행합니다.

예를 들어 을 호출하면 해당 기능이있는 경우 D::foo()이 표시됩니다. 그러나 아무 것도 없습니다. 따라서 범위를 뒤쪽으로 작업하여 기본 클래스를 시도합니다. 이제 fooB1::foo 또는 B2::foo까지 똑같이 볼 수 있으므로 모호합니다.

동일한 이유로 D 멤버 함수 내에서 무 규정 foo(5);을 호출하는 모호성이 발생합니다.


권장 솔루션의 효과 :

struct Derived : public Base1, public Base2{ 
    using Base1::foo; 
    using Base2::foo; 

는이 이름 D::foo을 생성하고,이 두 가지 기능을 식별 할 수 있다는 것입니다. 결과적으로 d.food.D::foo으로 해석되고 D::foo으로 식별되는이 두 기능에서 과부하 해결이 발생할 수 있습니다.

참고 :이 예에서 D::foo(int)Base1::foo(int)은 하나의 기능에 대한 두 개의 식별자입니다. 그러나 일반적으로 이름 조회 및 오버로드 확인 프로세스의 경우 두 가지 개별 기능인지 여부에 차이가 없습니다.

관련 문제