파생 클래스에서 이름은 같지만 서명이 다른 함수


92

동일한 이름의 함수가 있지만 기본 및 파생 클래스에 다른 서명이 있습니다. 파생에서 상속 된 다른 클래스에서 기본 클래스의 함수를 사용하려고하면 오류가 발생합니다. 다음 코드를 참조하십시오.

class A
{
    public:
    void foo(string s){};
};

class B : public A
{
    public:
    int foo(int i){};
};

class C : public B
{
    public:
    void bar()
    {
        string s;
        foo(s);
    }
};

gcc 컴파일러에서 다음 오류를 수신합니다.

In member function `void C::bar()': no matching function for call to `C::foo(std::string&)' candidates are: int B::foo(int)

int foo(int i){};class B에서 제거 하거나에서 이름을 바꾸면 foo1모든 것이 잘 작동합니다.

이것의 문제는 무엇입니까?


1
기술적 으로이 질문 의 중복 이지만 이 질문 에는 더 나은 제목과 답변이 있습니다.
Troubadour 2011 년

답변:


79

기본 클래스의 함수를 재정의하지 않지만 이름이 같은 파생 클래스의 함수는 기본 클래스에서 같은 이름의 다른 함수를 숨 깁니다 .

일반적으로보고있는 것이 일반적으로 바람직한 동작이 아니므로 기본 클래스 함수를 재정의하지 않는베이스 클래스의 함수와 이름이 같은 파생 클래스에 함수를 포함하는 것은 나쁜 습관으로 간주됩니다. 일반적으로 다른 기능에 다른 이름을 지정하는 것이 좋습니다.

기본 함수를 호출해야하는 경우를 사용하여 호출 범위를 지정해야합니다 A::foo(s). 이렇게하면 동시에 가상 기능 메커니즘도 비활성화 A::foo(string)됩니다.


13
또한 litdb의 답변을 읽으십시오. B에서 'using A :: foo'절을 통해 기본 함수를 '숨기기 해제'할 수 있습니다.
xtofl

사실, 저는 기본 계층 구조를 고정 된 것으로 취급하면서 호출 사이트에서 사용할 수있는 솔루션을 찾고있었습니다.
CB Bailey

2
이 주장의 기초는 무엇이며 다음과 같은 조언이 따릅니다. "일반적으로 기본 클래스 함수를 재정의하지 않는베이스 클래스의 함수와 이름이 같은 파생 클래스에 함수를 갖는 것은 나쁜 습관 으로 간주 됩니다. 당신이보고있는 것은 일반적으로 바람직한 행동이 아니다. 다른 기능을 다른 이름을 부여하는 것이 바람직하다 " . 그들이 의미 론적으로 똑같은 일을하고 있다면 어떨까요? C ++는 Johannes의 답변에서 설명한 것처럼 이로 인해 발생하는 문제에 대한 솔루션을 제공합니다.
Nawaz

109

기지 중 하나에서 이름을 찾으면 이름 조회가 중지되기 때문입니다. 그것은 다른 기지를 넘어 보지 않을 것입니다. B의 함수 그림자 두 함수 B 및 C 내에서 표시되도록하는 것이, B의 범위에서의 기능을 재 - 선언 당신이 가지고 A. 펑션 :

class A
{
    public:
    void foo(string s){};
};

class B : public A
{
    public:
    int foo(int i){};
    using A::foo;
};

class C : public B
{
    public:
    void bar()
    {
        string s;
        foo(s);
    }
};

편집 : 표준이 제공하는 실제 설명은 (10.2 / 2에서) :

다음 단계에서는 클래스 범위 C에서 이름 조회의 결과를 정의합니다. 먼저 클래스와 각 기본 클래스 하위 개체의 이름에 대한 모든 선언이 고려됩니다. 한 하위 개체 B의 멤버 이름 f는 A가 B의 기본 클래스 하위 개체 인 경우 하위 개체 A에서 멤버 이름 f를 숨 깁니다. 이렇게 숨겨진 선언은 고려 대상에서 제거됩니다. using-declaration에 의해 도입 된 이러한 각 선언은 using-declaration에 의해 지정된 선언을 포함하는 유형 인 C의 각 하위 개체에서 온 것으로 간주됩니다 .96) 결과 선언 집합이 그렇지 않은 경우 모두 동일한 유형의 하위 개체에서 가져 오거나 세트에 비 정적 멤버가 있고 별개의 하위 개체의 멤버를 포함하는 경우 모호성이 있고 프로그램의 형식이 잘못되었습니다. 그렇지 않으면 그 세트는 조회의 결과입니다.

다른 위치 (바로 위)에서 다음과 같이 말할 수 있습니다.

id-expression [ "foo"와 같은 ]의 경우 이름 조회는 this의 클래스 범위에서 시작됩니다. 정규화 된 ID의 경우 [ "A :: foo"와 같은 A는 중첩 된 이름 지정자입니다. ], 이름 검색은 중첩 된 이름 지정자의 범위에서 시작됩니다. 이름 조회는 액세스 제어 전에 발생합니다 (3.4, 11 절).

([...] 내가 쓴). B의 foo가 비공개 인 경우에도 A의 foo를 찾을 수 없습니다 (액세스 제어가 나중에 발생하기 때문에).


litb, 답변 주셔서 감사합니다. 난 당신의 코드를 컴파일 할 때, 나는 얻을 : 액세스 조정할 수 없습니다 void A::foo(class basic_string<char,char_traits<char>,allocator<char> >)' in 클래스 B를 같은 이름을 가진 '때문에 현지 법`INT의 B :: foo는 (INT)의'. 이전 버전의 gcc를 사용했기 때문일 수 있습니다.
Igor

1
네, 확실히 컴파일러 버그입니다. "A :: foo;"를 사용하는 오래된 컴파일러 "using A :: foo;"대신 그러나 전자는 C ++에서 더 이상 사용되지 않습니다.
Johannes Schaub-litb
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.