web-dev-qa-db-ja.com

c ++ clangによる仮想関数のオーバーロード警告?

次のコードをコンパイルすると、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で同じ宣言のコメントを解除すると、警告が閉じられることに注意してください。私の理解では、2つのget()関数は異なるシグネチャを持っているため、隠れることはできません。

Clangは正しいですか?どうして?

これはMacOS X上で、Xcodeの最新バージョンを実行していることに注意してください。

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

更新:Xcode 4.6.3と同じ動作。

64
Jean-Denis Muys

この警告は、オーバーライドが意図されているときに、オーバーロードが偶発的に隠れないようにするためのものです。少し異なる例を考えてみましょう:

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);
};
107

R。Martinho Fernandesソリューションは、単一のchar *引数を取るget()メソッドをDerivedスコープに実際に持ち込む場合に完全に有効です。

実際、提供したスニペットでは、仮想メソッドは必要ありません(BaseとDerivedは同じ署名を持つメソッドを共有しないため)。

ポリモーフィズムが実際に必要であると仮定すると、それでも非表示の動作は意図したものになる可能性があります。この場合、次のプラグマを使用して、Clangの警告をローカルで無効にすることができます。

#pragma clang diagnostic Push
#pragma clang diagnostic ignored "-Woverloaded-virtual"
    // Member declaration raising the warning.
#pragma clang diagnostic pop
22
Ad N

Structパブリックインターフェイスをそのまま保持する警告を無効にする別の方法は次のとおりです。

_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
_
21
Pedro

警告は、Derivedクラスのスコープ内にvoid * get(char * e)関数が存在せず、同じ名前の別のメソッドによって非表示になることを意味します。派生クラスに別の引数がある場合でも、派生クラスに指定された名前のメソッドが少なくとも1つある場合、コンパイラは基本クラスの関数を検索しません。

このサンプルコードはコンパイルされません。

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

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


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