C++. Ограничения виртуальных функций. Спецификатор final

Ограничения виртуальных функций. Спецификатор final

Данная тема есть продолжением темы:


Содержание


Поиск на других ресурсах:

1. Ограничения виртуальных функций

На виртуальные функции накладываются следующие общие ограничения:

  • виртуальные функции нужно использовать только в классах, образующих иерархию наследования;
  • виртуальные функции не могут применяться как обычные функции, которые не взяты в оболочку класса;
  • глобальные функции не могут быть виртуальными;
  • виртуальные функции в классе не могут быть объявлены статическими с использованием ключевого слова static.

 

2. Ограничения на использование виртуальных функций. Спецификатор final

В языке C++ можно ограничить внедрение виртуальных функций в иерархии классов. Если необходимо запретить использование имени виртуальной функции в унаследованных классах, то для этого используется спецификатор final. Если функции в иерархии классов объявляются как невиртуальные (без спецификатора virtual), попытка использовать спецификатор final приведет к ошибке компиляции.

Объявление виртуальной функции со спецификатором final может быть рассмотрено в контексте двух приложений:

  • когда функция объявляется с ключевым словом virtual. Синтаксис языка C++ позволяет объявить виртуальную функцию и, в то же время, запрещает использование имени этой функции в унаследованных классах;
  • когда функция объявляется с ключевым словом override. Это случай, когда функция переопределяет одноименную функцию базового класса. Синтаксисом допускается переопределение одноименной функции базового класса без ключевого слова override.

В случае объявления функции с ключевым словом virtual в классе, общий вид такой функции следующий

virtual return_type FuncName(parameters) final
{
  // ...
}

здесь

  • FuncName – имя виртуальной функции, которое запрещается использовать в унаследованных классах;
  • parameters – параметры функции;
  • return_type – тип возврата из функции.

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

return_type FuncName(parameters) override final
{
  // ...
}

или без использования ключевого слова override

return_type FuncName(parameters) override final
{
  // ...
}

 

3. Пример использования ограничения на функцию, объявленную со спецификатором virtual

Ниже представлен пример двух классов A и B, которые образуют иерархию наследования. Класс A является базовым классом, класс B является производным (унаследованным).

В классе A объявляется виртуальная функция Print() с ключевым словом virtual. В то же время, эта функция объявляется как final. Такое объявление приведет к тому, что во всех унаследованных классах будет запрещено использовать имя Print().

// Базовый класс
class A
{
public:
  // Здесь объявляется виртуальная функция со спецификатором final
  virtual void Print() final
  {
    cout << "A.Print()" << endl;
  }
};

// Производный (унаследованный) класс
class B :A
{
public:
  // Запрещено переопределять виртуальную функцию,
  // которая объявлена со спецификатором final
  void Print() // Здесь ошибка компиляции
  {
    cout << "B.Print()" << endl;
  }
};

 

4. Пример применения ограничения на виртуальную функцию, объявленную со спецификатором override

В примере объявляется три класса с именами A, B, C, которые образуют иерархию.
Класс A размещается в вершине иерархии. В классе A объявляется виртуальная функция с ключевым словом virtual, первая в цепочке виртуальных функций.
В классе B объявляется виртуальная функция с ключевым словом override, которая продолжает цепочку виртуальных функций. Эта функция объявляется со спецификатором final. Это означает, что в унаследованном классе C запрещено использовать имя виртуальной функции.

#include <iostream>
using namespace std;

// Базовый класс
class A
{
public:
  // Здесь объявляется виртуальная функция
  virtual void Print()
  {
    cout << "A::Print()" << endl;
  }
};

// Производный (унаследованный) класс
class B :A
{
public:
  // Здесь объявляется виртуальная функция,
  // которая ограничивает использование имени Print() в унаследованных классах
  void Print() override final
  {
    cout << "B::Print()" << endl;
  }
};

// Производный класс
class C :B
{
public:
  // Запрещено переопределять final-функцию B::Print()
  void Print() override // ошибка компиляции
  {
    cout << "C::Print()" << endl;
  }
};

 


Связанные темы