clang에 의한 C ++ 과부하 가상 함수 경고?


80

clang은 다음 코드를 컴파일 할 때 경고를 내 보냅니다.

struct Base
{
    virtual void * get(char* e);
//    virtual void * get(char* e, int index);
};

struct Derived: public Base {
    virtual void * get(char* e, int index);
};

경고는 다음과 같습니다.

warning: 'Derived::get' hides overloaded virtual function [-Woverloaded-virtual]

(물론 상기 경고를 활성화해야합니다).

이유를 모르겠습니다. Base에서 동일한 선언을 주석 해제하면 경고가 종료됩니다. 내 이해는 두 개의 get () 함수가 다른 서명을 갖기 때문에 숨길 수 없다는 것입니다.

clang이 맞습니까? 왜?

이것은 최신 버전의 Xcode를 실행하는 MacOS X에 있습니다.

clang --version
Apple LLVM version 5.0 (clang-500.1.74) (based on LLVM 3.3svn)

업데이트 : Xcode 4.6.3과 동일한 동작.

답변:


115

이 경고는 재정의가 의도 된 경우 실수로 과부하를 숨기는 것을 방지하기위한 것입니다. 약간 다른 예를 고려하십시오.

struct chart; // let's pretend this exists
struct Base
{
    virtual void* get(char* e);
};

struct Derived: public Base {
    virtual void* get(chart* e); // typo, we wanted to override the same function
};

경고이므로 반드시 실수라는 의미는 아니지만 오류를 나타낼 수 있습니다. 일반적으로 이러한 경고는보다 명시 적으로 작성하고 컴파일러에게 사용자가 작성한 의도를 알 수 있도록하여 경고를 차단하는 수단이 있습니다. 이 경우 다음을 수행 할 수 있습니다.

struct Derived: public Base {
    using Base::get; // tell the compiler we want both the get from Base and ours
    virtual void * get(char* e, int index);
};

11
"로컬로 경고를 해제"하는이 솔루션은 코드의 의미를 변경하고 있음을 지적 할 수 있습니다. 이제 get정적 유형의 객체에 대해 단일 인수를 사용 하여 함수 멤버를 호출 할 수 있습니다 Derived. using 선언이 없으면 같은 일로 컴파일 오류가 발생합니다.
Ad N

29

구조체 공용 인터페이스를 그대로 유지하면서 경고를 비활성화하는 또 다른 방법은 다음과 같습니다.

struct Derived: public Base
{
    virtual void * get(char* e, int index);
private:
    using Base::get;
};

이렇게하면 소비자가 경고를 끄는 동안 Derived전화를 걸 수 없습니다 Derived::get(char* e).

Derived der;
der.get("", 0); //Allowed
der.get("");    //Compilation error

2
이것은베이스의 클래스 get메서드 를 교체 할 계획 일 때이 경고를 제거하는 안전한 방법입니다!
jpo38

그러나 이것이 모호한 호출을 유발할 수있는 경우에주의하십시오. 따라서이 솔루션도 100 % 절약되지 않습니다.
sigy

22

R. Martinho Fernandes 솔루션은 실제로 get()단일 char * 인수를 사용 하는 메서드를 Derived범위 로 가져 오려는 경우 완벽하게 유효합니다 .

실제로 제공 한 스 니펫에는 가상 메소드가 필요하지 않습니다 (Base와 Derived는 동일한 서명을 가진 메소드를 공유하지 않기 때문에).

실제로 다형성이 필요하다고 가정해도 은폐 행동은 의도 한대로 될 수 있습니다. 이 경우 다음 pragma를 사용하여 Clang의 경고를 로컬로 비활성화 할 수 있습니다.

#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Woverloaded-virtual"
    // Member declaration raising the warning.
#pragma clang diagnostic pop

1
이 대답은 두 배로 놀랍습니다. 처음에는 내가 찾던 것에 대한 정확한 대답이었고, "내 방법을 원했다"였습니다. pragma의 이유와 clang이 얼마나 어리석은 지에 대해 코드에 주석을 쓸 때, 내 눈은 내가 덮어 쓰기를 작성했지만 경고는 과부하였습니다. 그런 다음 클릭 const하고 상속 된 방법을 잊어 버렸고 clang이 제대로 작동 한다는 것을 깨달았습니다 . 확실하지 않은 경우 컴파일러를 신뢰하십시오. 컴파일러가 의심 스러우면 컴파일러를 신뢰하십시오. :) 내가 찾던 것과 필요한 것을 모두 나에게주는 +1!
nevelis

17

경고는 Derived 클래스의 범위에 void * get (char * e) 함수가 없으므로 동일한 이름의 다른 메서드에 의해 숨겨 짐을 의미합니다. 파생 클래스에 지정된 이름의 메서드가 하나 이상 있으면 다른 인수가 있더라도 컴파일러는 기본 클래스의 함수를 검색하지 않습니다.

이 샘플 코드는 컴파일되지 않습니다.

class A
{
public:
    virtual void Foo() {}
};

class B : public A
{
public:
    virtual void Foo(int a) {}
};


int main()
{
    B b;
    b.Foo();
    return 0;
}

1
그것은 좋은 점이다. 비록 다른 서명이 그것을 방지하기에 충분해야하지만 은폐는 실제로 활발하게 일어나고있다.
Jean-Denis Muys 2013-08-30

은폐에 대한 내 정의는 동일한 서명을 가지고 있지만 재정의하지 않는 것입니다. 여기에서는 그렇지 않습니다.
NGauthier

에서 피하기 숨어,에 대한 해결책 요컨대 C ++는 : 다른 답변에서와 같이, "당신은 컴파일러가 후보로 기본 클래스의 기능을 고려할 경우 파생 클래스에서 사용 선언을 삽입합니다."
qris

그것은 또한 솔루션을 포함 할 경우 제대로 무슨 일이 유효한 경고 이유를 설명하는 하나이기 때문에,이 허용 대답해야한다 (... 사용)
MikeMB

1
이것이 제가 생각하는 가장 명확한 대답입니다. 그러나 실제로 b.Foo();. 당신은 작성해야합니다 b.A::Foo();.
Timmmm
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.