Во-первых, мы можем остановить переопределение только в том случае, если они могут быть переопределены . Так что final
имеет смысл только для виртуальных функций.
Тем не менее, final
, примененное к виртуальной функции одного класса, может казаться довольно бессмысленным. Но если вы рассмотрите более сложную иерархию, материя изменится:
class Parent
{
public:
virtual ~Parent() = default;
virtual void f();
};
class Child : public Parent
{
public:
void f() final; // f IS virtual already...
};
class GrandChild : public Child
{
// cannot override f any more – while Child still could!
};
Дополнительно учтите следующее:
class Base
{
public:
virtual ~Base() = default;
void f(); // non-virtual! (i. e. cannot be overridden)
};
class Derived : public Base
{
public:
void f(); // does not override, but HIDEs Base::f!!!
};
Объявление Base::f
как виртуальным, так и финальным также предотвратит сокрытие (но не более загрузка ).
На самом деле, снова этот сценарий имеет смысл, если Base
сам уже унаследован от другого полиморфного класса. Если нет и Base
не предназначен для наследования, я бы вообще не вводил никаких виртуальных функций (вызовы виртуальных функций обходятся дороже, чем обычные вызовы функций!). Если тогда пользователь все еще наследует и скрывает функцию - ну, это его ответственность ...