【问题标题】:Warning: overloaded virtual function "Base::process" is only partially overridden in class "derived"警告:重载的虚函数“Base::process”在“派生”类中仅被部分覆盖
【发布时间】:2014-02-23 03:13:59
【问题描述】:

我低于警告。 我的部分代码是:

class Base {
public:
    virtual void process(int x) {;};
    virtual void process(int a,float b) {;};
protected:
    int pd;
    float pb;
};

class derived: public Base{
public:
    void process(int a,float b);
}

void derived::process(int a,float b){
    pd=a;
    pb=b;
    ....
}

我收到以下警告:

 Warning: overloaded virtual function "Base::process" is only partially overridden in class "derived"

我以任何方式将进程作为虚函数,所以我期待这个警告不应该出现...... 这背后的原因是什么??

【问题讨论】:

  • virtual void Base::process(int x); 隐藏在derived 中。您可以添加using Base::process 来解决这个问题。

标签: c++ overriding virtual-functions name-hiding


【解决方案1】:

警告原因

Warning: overloaded virtual function "Base::process" is only partially overridden in class "derived"

是你没有覆盖所有的签名,你已经这样做了

virtual void process(int a,float b) {;}

但不是为了

virtual void process(int x) {;}

此外,当您不覆盖并且不使用 using Base::process 将函数限定为对 derived::process(int) 的静态调用时,甚至不会编译。这是因为 Derived 在这种情况下没有 process(int)。所以

Derived *pd = new Derived();
pd->process(0);

Derived d;
d.process(0);

不会编译。

添加using 声明将解决此问题,以便通过指向 Derived* 的指针对隐藏函数进行静态调用并选择运算符 d.process(int) 进行编译和虚拟调度(通过基指针或引用调用派生)进行编译没有警告。

class Base {
public:
    virtual void process(int x) {qDebug() << "Base::p1 ";};
    virtual void process(int a,float b) {qDebug() << "Base::p2 ";}
protected:
    int pd;
    float pb;
};

class derived: public Base{
public:
    using Base::process;

    /* now you can override 0 functions, 1 of them, or both
    *  base version will be called for all process(s) 
    *  you haven't overloaded
    */
    void process(int x) {qDebug() << "Der::p1 ";}
    void process(int a,float b) {qDebug() << "Der::p2 ";}
};

现在:

int main(int argc, char *argv[])
{
    derived d;
    Base& bref = d;
    bref.process(1);    // Der::p1
    bref.process(1,2);  // Der::p2 
    return 0;
}

【讨论】:

    【解决方案2】:

    当您覆盖类中的虚拟方法时,该方法的任何未被覆盖的重载对于该类将隐藏并且不能使用。因此,在您的示例中,尝试在 derived 对象上调用 process(int) 将失败,因为覆盖的 process(int, float) 已将其隐藏。

    【讨论】:

    • "...对于那个类是隐藏的,不能使用"好吧,只有在静态调用函数时。您始终可以通过 Base 指针/引用调用它。我发现在静态上下文中调用虚函数很奇怪,但有时它是有意义的。所以我发现只覆盖其中一个重载是完全合理的......
    • @leemes 只覆盖一个重载当然是合理的,但我无法想象你会想要这种行为。我个人认为这是一个设计缺陷,但我可能会遗漏一些关于重载解决方案如何工作的细微差别。我所知道的是,在 C++ 中使用 OOP 很快就让我向往 Java。
    【解决方案3】:

    您只覆盖了process 的两个重载之一。您错过了仅采用int 的重载。

    class Base {
    public:
        virtual void process(int x) {;}; // You do *not* override this in derived
        virtual void process(int a,float b) {;}; // You do override this
    // ...
    };
    

    根据你的需要,你可以:

    1. derived 中也简单地覆盖int 重载;或

    2. int 重载设为非虚拟并让它调用虚拟int, float 重载。

    两个旁注:(a) 尽管大多数编译器都接受它,但函数体后面的 ; 在语法上是错误的。 (b) 受保护的成员变量通常与公共变量一样不受欢迎;您应该使用受保护的 getter/setter 并将变量设为私有。

    【讨论】:

    • 我会避免在虚拟方法中使用默认参数。
    • @Jarod42:你是对的。既然你这么说,我什至记得 Scott Meyers 在 Effective C++ 中有一个完整的项目:“永远不要重新定义继承函数的默认参数值”。所以最好使用最后一个选项。
    【解决方案4】:

    当您声明与Base 中的同名方法时,这些方法将被隐藏。

    当你覆盖一个方法时就是这种情况。

    所以

    derived d;
    d.process(42); // won't compile
    

    要解决这个问题:添加using Base::process

    class derived: public Base {
    public:
        using Base::process;
        void process(int a, float b);
    };
    

    由于以前的方法不会使 lint 警告静音, 另一种解决方法是覆盖每个方法process:

    class derived: public Base {
    public:
        void process(x) { Base::process(x); }
        void process(int a, float b);
    };
    

    【讨论】:

    • @Ashwin:所以我将此警告视为误报...顺便说一句 void process(int x) { Base::process(x); } 应该使警告静音...
    • 我刚刚在派生类中创建了一个虚拟进程函数,如下所示 void process(int x) {;}; ....它解决了我的警告...
    • @Ashwin:所以你用与Base 相同的定义覆盖它,我的调用Base 以确保它是相同的。我认为意图更清楚。我建议添加评论,告诉它无论如何都是无声的 lint 警告。
    【解决方案5】:

    C++ overload resolution.

    长话短说,在尝试解析名称时,部分覆盖重载函数可能会很奇怪。

    另外,从设计的角度来看。图案通常很奇怪。我有一个我认为相同的功能足以保证相同的名称:一般来说,它做同样的事情是一种默契。当你在子类中改变一个函数的行为时,如果你只在派生类中改变它的一部分,那就很奇怪了。本质上,它易于阅读(使用 ~= 大致相同)

    //隐含陈述

    1) Base::process(int) ~= Base::process(int,float)

    2) 派生::进程(int) ~= 派生::进程(int,float)

    //明确的陈述

    3) Base::process(int) == derived::process(int)

    4) Base::process(int,float) != derived::process(int,float)

    本质上,既然 3 和 4 是冲突的,那么 2 不可能是真的。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2018-12-23
      • 1970-01-01
      • 2014-01-15
      • 2017-08-12
      • 2020-07-16
      • 2015-10-24
      • 2021-06-14
      相关资源
      最近更新 更多