Incompatible types prevent overriding

Метод производного класса скрывает virtual метод базового класса вместо переопределения его

Описание

Этот дефект возникает, когда метод производного класса имеет то же имя и количество параметров, что и virtual метод базового класса, но:

  • Списки параметров различаются по крайней мере одним типом параметров.

  • Списки параметров отличаются наличием или отсутствием таких квалификаторов, как const.

Метод производного класса скрывает virtual метод базового класса вместо переопределения.

Риск

  • Можно непреднамеренно скрыть метод базового класса вместо переопределения его методом производного класса.

  • Если метод базового класса скрыт, и вы используете объект производного класса для вызова метода с параметрами базового класса, то вместо этого вызывается метод производного класса. Для параметров, типы которых не совпадают с аргументами, которые вы передаете, приведение происходит, если это возможно. В противном случае происходит отказ компиляции.

Зафиксировать

Чтобы переопределить виртуальный метод базового класса с помощью метода производного класса, объявите методы с помощью идентичных списков параметров. Например, измените тип параметра или добавьте const квалификатор при необходимости.

В C++ 11 и более поздних версиях можно объявить предполагаемые методы переопределения в производном классе с помощью спецификатора override. Когда вы объявляете производные методы класса с помощью спецификатора overrideкомпиляция прекращает работать, если списки параметров метода базового класса и метода производного класса отличаются. Методы производного класса не могут непреднамеренно скрыть методы базового класса, и обеспечивается переопределение виртуальных методов базового класса.

В противном случае добавьте линии с помощью Base_class_name:: method_name к производному объявлению класса. Затем можно получить доступ к методу базового класса с помощью объекта производного класса.

Примеры

расширить все

class Base {
public:
    Base();
    virtual ~Base();
    virtual void func(float i);
    virtual void funcp(float* i);
    virtual void funcr(float& i);
};

typedef double Float;

class Derived: public Base {
public:
    Derived();
    ~Derived();
    void func(Float i);
    void funcp(Float* i);
    void funcr(Float& i);
};

В этом примере из-за оператора typedef double Float;, а Derived методы классов func, funcp, и funcr иметь double аргументы во время Base методы классов с таким же именем имеют float аргументы. Поэтому вы не можете получить доступ к Base методы классов с использованием Derived объект класса.

Дефект появляется в методе, который скрывает метод базового класса. Чтобы найти, какой метод базового класса скрыт:

  1. Перейдите к определению базового класса. На панели Source щелкните правой кнопкой мыши имя базового класса и выберите Go To Definition.

  2. В определении базового класса идентифицируйте virtual метод, имя которого совпадает с именем метода производного класса.

Коррекция - метод Unhide Base Class

Одной из возможных коррекций является использование того же типа аргументов для базового и производного методов классов для включения переопределения. В противном случае, если вы хотите вызвать Base методы классов с float аргументы с использованием Derived class object, добавить строку используя основа:: method_name на Derived объявление класса.

class Base {
public:
    Base();
    virtual ~Base();
    virtual void func(float i);
    virtual void funcp(float* i);
    virtual void funcr(float& i);
};

typedef double Float;

class Derived: public Base {
public:
    Derived();
    ~Derived();
    using Base::func;
    using Base::funcp;
    using Base::funcr;
    void func(Float i);
    void funcp(Float* i);
    void funcr(Float& i);
};
Коррекция - задайте метод производного класса при помощи override

Другая коррекция состоит в том, чтобы явным образом задать методы производного класса как методы переопределения с помощью спецификатора override. Таким образом, очевидно, что вы намерены переопределить методы базового класса в производном классе. Если методы переопределения имеют другие списки параметров, чем их аналоги базовых классов, код не компилируется. В результате методы производного класса не могут скрыть методы базового класса.

class Base {
public:
    Base();
    virtual ~Base();
    virtual void func(float i);
    virtual void funcp(float* i);
    virtual void funcr(float& i);
};

typedef double Float;

class Derived: public Base {
public:
    Derived();
    ~Derived();
//   Compilation error
//  void func(Float i) override;
//  void funcp(Float* i) override;
//  void funcr(Float& i) override;

    void func(float i) override;
    void funcp(float* i) override;
    void funcr(float& i) override;
};

Определения закомментированных методов имеют различные списки параметров по сравнению с их аналогами базовых классов. Поскольку методы производного класса объявлены при помощи спецификатора override, различные списки параметров не скрывают методы базовых классов. Вместо этого код не компилируется. Использование override спецификатор применяет правило, согласно которому виртуальные методы в базовых и производных классах должны иметь одинаковые списки параметров.

namespace Missing_Const {
class Base {
public:
    virtual void func(int) const ;
    virtual ~Base() ;
} ;

class Derived : public Base {
public:
    virtual void func(int) ;

} ;
}

В этом примере Derived::func не имеет const квалификатор, но Base::func делает. Поэтому Derived::func не переопределяет Base::func.

Коррекция - Добавить const Квалификатор метода производного класса

Чтобы включить переопределение, добавьте const квалификатор для объявления метода производного класса.

namespace Missing_Const {
class Base {
public:
    virtual void func(int) const ;
    virtual ~Base() ;
} ;

class Derived : public Base {
public:
    virtual void func(int) const;

} ;
}

Чтобы избежать скрытия методов базового класса или превращения виртуальных методов в невиртуальные методы непреднамеренно:

  • Объявить виртуальные методы в базовом классе при помощи спецификатора virtual.

  • Объявить виртуальные методы в нефинальном производном базовом классе с помощью спецификатора override.

  • Объявить виртуальные методы в конечном классе при помощи спецификатора final.

namespace Missing_Ref {

class Obj {
    int data;
};

class Base {
public:
    virtual void func(Obj& o);
    virtual ~Base() ;
} ;

class Derived : public Base {
public:
    virtual void func(Obj o) ;

} ;
}

В этом примере Derived::func принимает Obj параметр по значению, но Base::func принимает Obj параметр по ссылке. Поэтому Derived::func не переопределяет Base::func.

Коррекция - Используйте ссылку для параметра метода производного класса

Чтобы включить переопределение, передайте параметр метода производного класса по ссылке.

namespace Missing_Ref {

class Obj {
    int data;
};

class Base {
public:
    virtual void func(Obj& o);
    virtual ~Base() ;
} ;

class Derived : public Base {
public:
    virtual void func(Obj& o) ;

} ;
}

Чтобы избежать скрытия методов базового класса или превращения виртуальных методов в невиртуальные методы непреднамеренно:

  • Объявить виртуальные методы в базовом классе при помощи спецификатора virtual.

  • Объявить виртуальные методы в нефинальном производном базовом классе с помощью спецификатора override.

  • Объявить виртуальные методы в конечном классе при помощи спецификатора final.

Информация о результатах

Группа: Объектно-ориентированная
Язык: C++
По умолчанию: On для рукописного кода, off для сгенерированного кода
Синтаксис командной строки: VIRTUAL_FUNC_HIDING
Влияние: Средний
Введенный в R2015b