exponenta event banner

Несовместимые типы запрещают переопределение

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

Описание

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

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

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

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

Риск

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

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

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

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

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

В противном случае добавьте строку using 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. Перейдите к определению базового класса. На панели «Источник» щелкните правой кнопкой мыши имя базового класса и выберите «Перейти к определению».

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

Исправление - метод скрытого базового класса

Одной из возможных корректировок является использование одного и того же типа аргумента для базового и производного методов класса для включения переопределения. В противном случае, если вы хотите вызвать Base методы класса с помощью float аргументы с использованием Derived объект класса, добавьте строку using Base::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++
По умолчанию: Вкл для рукописного кода, выкл для сгенерированного кода
Синтаксис командной строки: VIRTUAL_FUNC_HIDING
Воздействие: среднее
Представлен в R2015b