【问题标题】:c++ overloaded virtual function warning by clang?c++ 用c ++重载虚函数警告?
【发布时间】:2013-09-02 03:17:21
【问题描述】:

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() 函数的签名不同,所以无法隐藏。

叮当声对吗?为什么?

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

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

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

【问题讨论】:

    标签: c++ warnings overloading virtual hidden


    【解决方案1】:

    此警告用于防止在打算覆盖时意外隐藏重载。考虑一个稍微不同的例子:

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

    【讨论】:

    • 可以指出,这种“本地关闭警告”的解决方案也改变了代码的语义:您现在可以在对象的单个参数上调用get 函数成员静态类型Derived。如果没有 using 声明,同样的事情会导致编译错误。
    【解决方案2】:

    警告的意思是,不会有 无效*获取(字符* 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;
    }
    

    【讨论】:

    • 这是一个很好的观点:隐藏是实际上 主动发生的,即使不同的签名应该足以防止它。
    • 我对隐藏的定义是具有相同的签名但不能覆盖......这里不是这种情况。
    • 避免隐藏的解决方案,来自 C++ in a Nutshell:“如果您希望编译器将基类函数视为候选函数,请在派生类中插入 using 声明” ,如其他答案所示。
    • 如果它还包括一个解决方案(使用...),这应该是公认的答案,因为它是唯一正确解释发生了什么以及为什么这是一个有效警告的答案
    • 这是我认为最清楚的答案。但值得注意的是,您实际上仍然可以致电b.Foo();。你只需要写b.A::Foo();。
    【解决方案3】:

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

    其实在你提供的sn-p中,是不需要虚方法的(因为Base和Derived不共享任何具有相同签名的方法)。

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

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

    【讨论】:

    • 这个答案令人惊讶。起初,这是我正在寻找的确切答案,我“想要我的方法”。由于 pragma 和 clang 是多么愚蠢,我在代码中写了一条评论时,我注意到我写了 override,但警告是超载的。然后我点击并意识到我在继承方法上忘记了const,并且clang一直都是对的。如有疑问,请相信编译器。当您怀疑编译器时,请相信编译器。 :) +1 为我提供了我所寻求和需要的东西!
    【解决方案4】:

    另一种禁用警告保持结构公共接口完整的方法是:

    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
    

    【讨论】:

    • 当您计划替换基类的get 方法时,这绝对是消除此警告的安全方法!
    • 但是,请注意这会导致模棱两可的调用。所以这个解决方案也不是 100% 节省。
    猜你喜欢
    • 2017-08-12
    • 1970-01-01
    • 2016-07-30
    • 1970-01-01
    • 2021-10-16
    • 2013-06-11
    • 1970-01-01
    • 1970-01-01
    • 2015-11-13
    相关资源
    最近更新 更多