Является ли ключевое слово override просто проверкой переопределенного виртуального метода?

Насколько я понимаю, введение override Ключевое слово в C++11 является не чем иным, как проверкой, чтобы убедиться, что реализуемая функция является overrideиз virtual функция в базовом классе.

Это оно?

6 ответов

Решение

Это действительно идея. Дело в том, что вы четко понимаете, что имеете в виду, так что в противном случае молчаливая ошибка может быть диагностирована:

struct Base
{
    virtual int foo() const;
};

struct Derived : Base
{
    virtual int foo()   // whoops!
    {
       // ...
    }
};

Приведенный выше код компилируется, но это не то, что вы могли иметь в виду (обратите внимание на отсутствующий const). Если бы вы сказали вместо этого, virtual int foo() override, тогда вы получите ошибку компилятора, что ваша функция на самом деле ничего не переопределяет.

Цитата из Википедии:

Специальный идентификатор переопределения означает, что компилятор проверит базовый класс (ы), чтобы увидеть, существует ли виртуальная функция с этой точной сигнатурой. И если нет, компилятор выдаст ошибку.

http://en.wikipedia.org/wiki/C%2B%2B11

Редактировать (пытаясь немного улучшить ответ):

Объявление метода как "переопределить" означает, что этот метод предназначен для перезаписи (виртуального) метода в базовом классе. Переопределяющий метод должен иметь ту же сигнатуру (по крайней мере, для входных параметров), что и метод, который он намеревается переписать.

Почему это необходимо? Хорошо, предотвращены следующие два распространенных случая ошибок:

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

  2. забывают объявить метод в суперклассе как "виртуальный", но все же пытаются переписать его в подклассе. Хотя это, очевидно, будет принято, поведение будет не совсем таким, как предполагалось: метод не является виртуальным, поэтому доступ через указатели к суперклассу закончится вызовом старого (суперкласс ') метода вместо нового (подкласс') метода.

Добавление "override" однозначно устраняет это: с помощью этого мы сообщаем компилятору, что ожидаются три вещи:

  1. в суперклассе есть метод с таким же именем
  2. этот метод в суперклассе объявлен как "виртуальный" (то есть предназначен для переписывания)
  3. метод в суперклассе имеет ту же сигнатуру (input*), что и метод в подклассе (метод перезаписи)

Если какой-либо из них является ложным, то сообщается об ошибке.

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

Найденное "переопределение" полезно, когда кто-то обновил сигнатуру виртуального метода базового класса, например, добавил необязательный параметр, но забыл обновить сигнатуру метода производного класса. В этом случае методы между базовым и производным классом больше не являются полиморфными отношениями. Без объявления переопределения трудно обнаружить такую ​​ошибку.

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

http://en.wikipedia.org/wiki/C%2B%2B11

Проект стандарта C++17

Пройдя через все override попадает в черновик стандарта C++17 N4659, единственная ссылка, которую я могу найти на override идентификатор:

5 Если виртуальная функция помечена с помощью переопределения virt-спецификатора и не переопределяет функцию-член базового класса, программа имеет неверный формат. [ Пример:

struct B {
  virtual void f(int);
};

struct D : B {
  virtual void f(long) override; // error: wrong signature overriding B::f
  virtual void f(int) override;  // OK
}

- конец примера]

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

Чтобы прояснить все о виртуальном (раз уж я с этим сталкивался неоднократно!).

  • предназначен для того, чтобы сообщить производным классам, что функция может быть переопределена
    • Нет необходимости использовать в производных классах. Если функция имеет такое же имя / список типов параметров / cv-qual / ref-qual, она будет автоматически использоваться правильно.
    • (на самом деле, используя virtual в производных классах могут создавать тонкие ошибки, см. ниже)
  • - необязательный спецификатор для обнаружения ошибок и кода документа :
    • Сообщает компилятору: «Убедитесь, что есть ТОЧНАЯ виртуальная функция, которую я заменяю»
      • Избегает создания ДРУГОЙ сигнатуры функции по ошибке, которая могла бы вызвать небольшую ошибку (т.е. 2 немного разные функции, которые должны быть одинаковыми)
      • Сообщает кодировщикам, что это переопределяет виртуальную функцию.

Так дано:

      class base
{
public:
    virtual int foo(float x);
};

Вот как будут работать некоторые другие переопределения:

      // AUTOMATIC virtual function (matches original, no keywords specified)
int foo(float x) { ; } 

// Re-specifying "virtual" uselessly (+ see pitfalls below)
virtual int foo(float x) { ; } 

// Potential issues: it is unknown if the author intended this to be a 
//    virtual function or not. Also, if the author DID intend a match but 
//    made a mistake (e.g. use "int" for the parameter), this will create
//    a subtle bug where the wrong function is called with no warning anywhere:

int foo(int x) { ; }         // SUBTLE, SILENT BUG! int instead of float param
virtual int foo(int x) { ; } // SUBTLE, SILENT BUG! int instead of float param


// Better approach: use the 'override' identifier to 
//    make sure the signature matches the original virtual function,
//    and documents programmer intent.

int foo(float x) override { ; }        // Compiler checks OK + tells coder this is virtual
int foo(int x)  override { ; }         // COMPILE ERROR, caught subtle bug
virtual int foo(int x)  override { ; } // COMPILE ERROR, caught subtle bug
                                       // (and redundant use of "virtual")

Наконец (!) final спецификатор может использоваться вместо overrideпо тем же причинам, но в случае, если вы не хотите никаких дополнительных переопределений в производных классах.

Другие вопросы по тегам