Ключевое слово final [1] указывает, что виртуальная функция [2] не может быть переопределена в производном классе, или что от этого класса не может быть наследования.
Когда ключевое слово final применяется к функции-члену класса, оно появляется сразу после декларатора функции внутри определения класса, или после определения функции внутри определения класса.
Когда ключевое слово final применяется к классу, оно появляется в начале определения класса, сразу после имени класса.
декларатор virt-spec-seq(*) pure-spec(*) (1) декларатор virt-spec-seq(*) тело-функции (2) class-key attr(*) class-head-name class-virt-spec(*) base-clause(*) (3)
(1) В декларации функции-члена класса внутри определения класса final может появляться в virt-spec-seq сразу после декларатора и перед pure-spec, если это используется. (2) В определении функции-члена класса внутри определения класса final может появляться в virt-spec-seq сразу после декларатора и перед телом функции. (3) В определении класса final может появляться в качестве class-virt-spec сразу после имени класса, непосредственно перед двоеточием, с которого начинается base-clause, если это используется.
Примечание (*): эта часть не обязательна (опциональна).
В случаях (1,2), virt-spec-seq, если используется, будет либо override [4], либо final, либо final override, либо override final. В случае (3), допускается только значение final в качестве class-virt-spec, если это используется.
[В чем смысл final?]
Когда ключевое слово final используется в декларации или определении виртуальной функции, оно гарантирует, что функция виртуальная, и указывает, что она не может быть переопределена в производных классах. Иначе в программе ошибка (при компиляции генерируется сообщение об ошибке).
Когда ключевое слово final используется в определении класса, оно указывает, что этот класс не может появляться в списке базовых классов определения другого класса (другими словами, final-класс не может наследоваться). Иначе в программе ошибка (при компиляции генерируется сообщение об ошибке). Ключевое слово final также может использоваться в определении объединения (union), в этом случае final не оказывает никакого эффекта (кроме как влияния на результат std::is_final, см. стандарт C++14), поскольку объединения не могут наследоваться.
Слово final получает свой специальный смысл, когда используется в декларации функции-члена класса, или в заголовке класса. В других контекстах final не резервируется как ключевое слово, и может использоваться для именования объектов и функций (что конечно добавляет путаницы и так сложный синтаксис C++).
Пример:
struct Base
{
virtual void foo();
};
struct A : Base
{
void foo() final; // Base::foo переопределена и A::foo это конечный переопределитель
void bar() final; // Ошибка: bar не может быть final, поскольку он не виртуальный
};
struct B final : A // struct B обладает свойством final
{
void foo() override; // Ошибка: foo не может быть переопределена, поскольку
// в A она определена как final.
};
struct C : B // Ошибка: B обладает свойством final
{
};
[Ссылки]
1. final specifier (since C++11) site:cppreference.com. 2. C++: ключевое слово virtual. 3. C++: производные классы (наследование). 4. C++: спецификатор override. |