Предупреждение: перегруженная виртуальная функция Base :: process только частично переопределяется в производном классе

Я получаю предупреждение ниже. часть моего кода:

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"

в любом случае я сделал процесс как виртуальную функцию, поэтому я ожидаю, что это предупреждение не должно появиться ... В чем причина этого ??


person Ashwin    schedule 30.01.2014    source источник
comment
virtual void Base::process(int x); скрыт в derived. Вы можете добавить using Base::process, чтобы решить эту проблему.   -  person Jarod42    schedule 30.01.2014


Ответы (5)


Причина предупреждения

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;
}
person 4pie0    schedule 30.01.2014

Когда вы переопределяете виртуальный метод в классе, любые непереопределенные перегрузки этого метода скрыты для этого класса и не могут быть использованы. Итак, в вашем примере попытка вызвать process(int) для объекта derived не удалась, потому что переопределенный process(int, float) скрыл его.

person ApproachingDarknessFish    schedule 30.01.2014
comment
... скрыты для этого класса и не могут использоваться Ну, только при статическом вызове функции. Вы всегда можете вызвать его с помощью указателя / ссылки Base. Мне кажется странным вызывать виртуальную функцию в статическом контексте, но иногда это имеет смысл. Поэтому я считаю вполне разумным переопределить только одну из перегрузок ... - person leemes; 30.01.2014
comment
@leemes Безусловно, разумно переопределить только одну перегрузку, но я не могу представить, чтобы вам когда-либо понадобилось такое поведение. Лично я считаю это недостатком дизайна, но, возможно, мне не хватает некоторых нюансов того, как работает разрешение перегрузки, или что-то в этом роде. Все, что я знаю наверняка, - это то, что работа с ООП в C ++ быстро заставляет меня тосковать по Java. - person ApproachingDarknessFish; 30.01.2014

Вы переопределили только одну из двух перегрузок 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. Просто переопределите перегрузку int в derived; или

  2. сделайте int перегрузку невиртуальной и позвольте ей вызывать виртуальную int, float перегрузку.

Два боковых примечания: (a) Хотя большинство компиляторов это принимают, знак ; после тела функции синтаксически неверен. (b) Защищенные переменные-члены обычно не одобряются почти так же, как и общедоступные; вы должны использовать защищенные геттеры / сеттеры и сделать переменные приватными.

person Oberon    schedule 30.01.2014
comment
Я бы избегал параметра по умолчанию в виртуальном методе. - person Jarod42; 30.01.2014
comment
@ Jarod42: Вы правы. Теперь, когда вы это говорите, я даже вспомнил, что у Скотта Мейерса есть целый пункт по этому поводу в Effective C ++: никогда не переопределяйте значение параметра по умолчанию унаследованных функций. Так что лучше используйте последний вариант. - person Oberon; 30.01.2014

Разрешение перегрузки C ++.

Короче говоря, частичное переопределение перегруженной функции может быть странным при попытке разрешить имя.

Кроме того, с точки зрения дизайна. узор вообще странный. У меня есть функция, которую, как я решил, достаточно и для того же имени: в общем, это молчаливое соглашение, что она делает то же самое. Когда вы меняете поведение функции в дочернем классе, это странно, если вы изменяете только часть ее в производном классе. По сути, его легко читать (используя ~ = как примерно равное)

// ПОДРАЗУМЕВАЕМЫЕ ЗАЯВЛЕНИЯ

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

2) производный :: процесс (int) ~ = производный :: процесс (int, float)

// ЯВНЫЕ ЗАЯВЛЕНИЯ

3) Base :: process (int) == производный :: процесс (int)

4) Base :: process (int, float)! = Производный :: процесс (int, float)

по сути, поскольку 3 и 4 находятся в противоречии, то 2 не может быть истинным.

person IdeaHat    schedule 30.01.2014

Когда вы объявляете метод с тем же именем, что и в Base, эти методы скрываются.

Это тот случай, когда вы переопределяете один метод.

So

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

Поскольку предыдущий метод не подавляет предупреждение о ворсинах, другой способ решить эту проблему - переопределить каждый метод process:

class derived: public Base {
public:
    void process(x) { Base::process(x); }
    void process(int a, float b);
};
person Jarod42    schedule 30.01.2014
comment
@Ashwin: Значит, я считаю это предупреждение ложным срабатыванием ... Кстати, void process(int x) { Base::process(x); } следует отключить предупреждение ... - person Jarod42; 31.01.2014
comment
Я только что создал одну фиктивную функцию процесса в производном классе, как показано ниже void process (int x) {;}; .... Это сняло мое предупреждение ... - person Ashwin; 31.01.2014
comment
@Ashwin: Значит, вы переопределяете его с тем же определением, что и Base, мой вызывает Base, чтобы убедиться, что это то же самое. Я думаю, намерение яснее. Я предлагаю добавить комментарий, чтобы сказать, что это все равно беззвучное предупреждение о ворсинах. - person Jarod42; 31.01.2014