Есть ли смысл использовать `override` при переопределении чистой виртуальной функции?
Например:
class Base {
virtual void my_function() = 0;
};
class Derived : Base {
void my_function() override;
};
Из того, что я читал, ключевое слово override
используется, чтобы убедиться, что у нас есть правильная подпись в функции, которую мы переопределяем, и это, по-видимому, единственное ее использование.
Однако в случае чистой виртуальной функции компилятор выдает ошибку, если мы использовали неправильную подпись в классе Derived (или базовый класс, в зависимости от того, как вы видите вещи). Итак, есть ли смысл добавить override
в конец объявления Derived::my_function()
?
Ответы
Ответ 1
Однако в случае чистой виртуальной функции компилятор выдает ошибку, если мы использовали неправильную подпись в классе Derived
Нет, это компилируется:
class Base {
virtual void my_function() = 0;
};
class Derived : Base {
void my_function(int);
// ^^^ mistake!
};
Пока это не так:
class Base {
virtual void my_function() = 0;
};
class Derived : Base {
void my_function(int) override;
};
error: void Derived::my_function(int)
отмечен override
, но не переопределяет
Ошибка, о которой вы говорите, возникает только тогда, когда экземпляр Derived
- override
позволяет вам поймать ошибку раньше и делает определение Derived
более четким/читаемым.
Ответ 2
Да, рекомендуется использовать ключевое слово override
последовательно как защитную практику.
Рассмотрим редизайн, когда автор Base
решает, что my_function
больше не будет чистым виртуальным, а также что он должен принять новый параметр. С override
на месте компилятор поймает эту проблему; без override
ваш класс Derived
будет продолжать компилироваться.
Ответ 3
Да!
Улучшает ясность кода:
override
предотвращает двусмысленность и передает смысл переопределения метода базового класса.
Предотвращает возможное непреднамеренное использование:
В будущем, если подпись метода изменения базового класса (здесь virtual
), он принудительно меняет класс. (с ошибкой компилятора). В противном случае (без ключа override
) его можно считать method overload
, который не предназначен.
Ответ 4
Обычно не беспокоит override
, просто перемещает ошибку. Я нахожу место, где вы получаете ошибку лучше - в точке, где вы определяете метод, который не может переопределить, а не когда вы создаете экземпляр класса.
Но для этого существует способ защиты от ошибки времени выполнения.
struct Base {
virtual void foo(int x = 0) = 0;
void foo(double d) {
foo( (int)d );
}
};
inline void Base::foo(int x) { std::cout << "Default foo(" << x << ")\n"; }
struct Derived:Base {
using Base::foo;
virtual void foo() { // oops, no int!
std::cout << "Derived::foo()\n";
Base::foo();
}
};
struct Derived2:Derived {
virtual void foo(int x=0) override {
std::cout << "Derived2::foo()\n";
Derived::foo(x);
}
};
здесь мы намерены для каждого foo
вызвать его родительский foo
. Но поскольку Derived::foo
не переопределяет ту же подпись, что и Base::foo
, она не вызывается.
Добавьте override
после foo()
в Derived
, и мы получим ошибку времени компиляции.
И да, я реализовал чистую виртуальную функцию Base::foo
.