Подтвердить что ты не робот

Требование переопределения виртуальной функции для использования ключевого слова override

С++ 11 добавлен override, чтобы гарантировать, что функции-члены, которые вы пишете, вы намереваетесь переопределить виртуальные функции базового класса, фактически (или не будут компилироваться).

Но в иерархии больших объектов иногда можно случайно создать функцию-член, которая переопределяет виртуальный класс базового класса, когда вы этого не намерены! Например:

struct A {
    virtual void foo() { }  // because obviously every class has foo().
};

struct B : A { ... };

class C : B {
private:
    void foo() {
        // was intended to be a private function local to C
        // not intended to override A::foo(), but now does
    }
};

Есть ли какой-либо флаг/расширение компилятора, который по крайней мере выдаст предупреждение на C::foo? Для удобочитаемости и правильности, я просто хотел бы обеспечить, чтобы все переопределения использовали override.

4b9b3361

Ответ 1

Похоже, что релиз GCC 5.1 добавил именно warning Я искал:

-Wsuggest-override
      Предупреждение о переопределении виртуальных функций, которые не отмечены ключевым словом переопределения.

Компиляция с -Wsuggest-override -Werror=suggest-override затем обеспечит выполнение всеми переопределениями override.

Ответ 2

Есть две вещи, которые вы можете сделать.

Во-первых, Clang 3.5 и выше имеют предупреждение -Winconsistent-missing-override (вызванное -Wall). Это не совсем подходит для вашего примера, но только если вы добавите void foo() override {} в class B, а не в class C. Вы действительно хотите -Wmissing-override, чтобы найти все отсутствующие override, а не просто несогласованные. В настоящее время это не предусмотрено, но вы можете жаловаться на список рассылки Clang, и они могут добавить его.

Во-вторых, вы используете трюк Howard Hinnant, чтобы временно добавить final в функцию члена базового класса и перекомпилировать. Затем компилятор найдет все последующие производные классы, которые пытаются переопределить функцию базового члена virtual. Затем вы можете исправить недостающие. Это немного больше работы и требует частого перепроверки, когда расширяется иерархия классов.

Ответ 3

GCC и Clang покрываются другими ответами. Здесь же для VС++ из моего другого ответа:

Ниже приведены соответствующие номера предупреждений в VС++:

C4263 (level 4) 'function': member function does not override any base class virtual member function
C4266 (level 4) 'function': no override available for virtual member function from base 'type'; function is hidden

Чтобы включить эти два предупреждения, вы можете использовать одну из следующих опций:

  • Установите уровень предупреждения на 4 в настройках проекта, а затем отключите предупреждения, которые вы не хотите. Это мой предпочтительный путь. Чтобы отключить нежелательные предупреждения уровня 4, перейдите к настройкам проектa > C/С++ > Дополнительно, а затем введите номера предупреждений в поле Отключить конкретные предупреждения.
  • Включить более двух предупреждений с помощью кода.

    #pragma warning(default:4263)
    #pragma warning(default:4266)
    
  • Включите два предупреждения в настройках проектa > C/С++ > Командная строка, а затем введите /w 34263/w34266. Здесь/wNxxxx опция означает включение предупреждений xxxx в Уровне N (N = 3 - уровень по умолчанию). Вы также можете сделать /wdNxxxx, который отключает предупреждение xxxx на уровне N.

Ответ 4

Проблема, которую я вижу с помощью -Werror=suggest-override, заключается в том, что она не позволяет вам написать следующее:

void f() final {...}

Даже если здесь есть неявный override. -Werror=suggest-override не игнорирует это (как и должно быть, поскольку override в этом случае избыточно)

Но это сложнее, чем это... Если вы пишете

virtual void f() final {...}

Это означает совершенно другую вещь, чем

virtual void f() override final {...}

В первом случае не нужно ничего переопределять! Второй делает.

Итак, я предполагаю, что проверка GCC реализована таким образом (например, иногда принимать избыточную override), чтобы получить последний случай права. Но это плохо работает, например. с clang-tidy, который будет корректно удалять переопределение, когда окончание будет достаточным (но тогда компиляция GCC завершится неудачно...)