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

227

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

Это оно?

aiao
источник
50
Да.⁣⁣⁣⁣⁣⁣⁣⁣⁣⁣⁣
Р. Мартиньо Фернандес
13
Это не двойная проверка, хотя. Это единственная проверка.
Никос К.
13
эй, переопределение не является ключевым словом, это своего рода грамматический сахар. int override = 42; // ОК
KAlO2
2
Это дополнительно улучшает читабельность, объясняя, что объявленная функция переопределена;)
mots_g
5
Итак ... Когда C ++ 11 станет достаточно стандартным, чтобы они начали преподавать такие вещи на моем местном 4-м курсе? Когда они узнают ?!
Cinch

Ответы:

264

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

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

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

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

Керрек С.Б.
источник
74
+1: Хотя, к сожалению, это немного красная сельдь, когда люди предполагают, что новая overrideфункция «исправляет» это; Вы должны помнить, чтобы использовать его, так же, как вы должны были помнить, чтобы написать const;)
Гонки Легкости на Орбите
Я просто понял, что explicitопределения классов не попали в C ++ 11. Да.
aschepler
1
@aschepler А что будет explicitделать определение класса? Никогда не слышал об этом вообще.
Кристиан Рау
18
@LightnessRacesinOrbit: Да, это не доказательство; однако, помнить общее правило (безумно писать, overrideкогда кто-то намеревается это сделать) более вероятно, чем запоминание угловых случаев, т. е. нет универсальности в копировании функций различных прототипов, только нарушения, такие как отсутствие constили запись charвместо intи т. д.
legends2k
1
@Light, лучший вариант использования overrideспецификатора упоминается в этом ответе , который является скорее футуристическим, чем немедленным. Ответ предполагает , что, сохранить overrideс virtualметодом. В будущем, когда кто-то по ошибке меняет подпись, его полезность начинает
действовать
36

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

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

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

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

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

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

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

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

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

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

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

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

user1284631
источник
31

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

user3792211
источник
1
+1. Хотя overrideэто отличный способ для выявления таких проблем, хорошее тестирование юнит-тестов также должно помочь.
Разочарован
1
Именно поэтому я так взволнован этим новым спецификатором. Единственная проблема заключается в том, что эта функция уже должна применяться, чтобы предотвратить ошибки, вызванные изменениями в базовых классах. ;-)
Вольф
5

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

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

RonaldBarzell
источник
2

Проект стандарта 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
}

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

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

Сиро Сантилли 郝海东 冠状 病 六四 事件 法轮功
источник