c ++通过clang重载虚函数警告?

Jea*_*uys 65 c++ virtual hidden warnings overloading

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);
};
Run Code Online (Sandbox Code Playgroud)

警告是:

warning: 'Derived::get' hides overloaded virtual function [-Woverloaded-virtual]
Run Code Online (Sandbox Code Playgroud)

(当然需要启用上述警告).

我不明白为什么.请注意,在Base中取消注释相同的声明会关闭警告.我的理解是,由于两个get()函数具有不同的签名,因此不能隐藏.

clang对吗?为什么?

请注意,这是在MacOS X上,运行最新版本的Xcode.

clang --version
Apple LLVM version 5.0 (clang-500.1.74) (based on LLVM 3.3svn)
Run Code Online (Sandbox Code Playgroud)

更新:与Xcode 4.6.3相同的行为.

R. *_*des 108

此警告用于防止在超控时意外隐藏过载.考虑一个稍微不同的例子:

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
};
Run Code Online (Sandbox Code Playgroud)

因为它是一个警告,它并不一定意味着它是一个错误,但它可能表明一个.通常这样的警告有一种方法可以通过更明确地关闭它们,并让编译器知道你确实打算写下你写的东西.我相信在这种情况下你可以做到以下几点:

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);
};
Run Code Online (Sandbox Code Playgroud)

  • 可以指出,这种"本地关闭警告"的解决方案也改变了代码的语义:现在可以在静态类型"派生"的对象上使用单个参数调用`get`函数成员.没有using声明,同样的事情会导致编译错误. (9认同)

Ad *_*d N 22

R. Martinho Fernandes解决方案是完全有效的,如果你真的想让get()方法将一个char*参数带入Derived范围.

实际上,在您提供的代码段中,不需要虚拟方法(因为Base和Derived不共享具有相同签名的任何方法).

假设实际上需要多态性,隐藏行为仍然可以是预期的.在这种情况下,可以使用以下编译指示在本地禁用Clang的警告:

#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Woverloaded-virtual"
    // Member declaration raising the warning.
#pragma clang diagnostic pop
Run Code Online (Sandbox Code Playgroud)


Ped*_*dro 22

禁用保持struct public interface完整的警告的另一种方法是:

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

这不允许的消费者Derived打电话Derived::get(char* e),而沉默的警告:

Derived der;
der.get("", 0); //Allowed
der.get("");    //Compilation error
Run Code Online (Sandbox Code Playgroud)

  • 当您计划替换基类的`get` 方法时,这绝对是消除此警告的安全方法! (2认同)

小智 12

警告意味着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;
}
Run Code Online (Sandbox Code Playgroud)

  • 这是一个很好的观点:隐藏是“实际上”“主动”发生的,尽管不同的签名应该足以阻止它。 (2认同)
  • 这是我认为最明确的答案。但值得注意的是,您实际上仍然可以调用 `b.Foo();`。你只需要写“bA::Foo();”。 (2认同)