C++: абстрактные классы Печать
Добавил(а) microsin   

Ключевое слово abstract определяет абстрактный тип (класс), от которого не может быть создан экземпляр, однако этот тип может использоваться в качестве базового класса.

Чисто-виртуальная (pure virtual) функция это такая виртуальная функция, декларатор которой имеет следующий синтаксис:

declarator virt-specifier(не обязательно) =0

Здесь специальная последовательность =0 известна как pure-specifier, и она появляется либо сразу после декларатора, либо после опционального virt-specifier (override или final [2, 3]).

pure-specifier не может появляться в определении функции-члена класса.

struct Base { virtual int g(); virtual ~Base() {} };
 
struct A : Base
{
   // OK: декларируется дерево виртуальных функций, две из которых
   // чисто виртуальные (pure virtual)
   virtual int f() = 0, g() override = 0, h();
   // OK: деструктор также может быть pure
   ~A() = 0;
   // Ошибка: pure-specifier в определении функции
   virtual int b()=0 {}
};

Абстрактный класс это такой класс, который определяет или наследует как минимум одну функцию, для которое конечный переопределитель является чистым виртуальным (pure virtual).

[В чем смысл abstract?]

Абстрактные классы используются для представления общей концепции (например фигура Shape, животное Animal), которая может использоваться как базовые классы для образования конкретных, уточняющих производных классов (например окружность Circle, собака Dog).

От абстрактных классов нельзя создавать объекты (кроме как от суб-объектов базового класса, производного от него), и в абстрактном классе нельзя декларировать нестатические элементы данных.

Абстрактные типы не могут использоваться как типы параметров, как типы возвращаемых из функции значений, или как тип явного преобразования (обратите внимание, что это проверяется в точке определения и вызова функции, поскольку в точке объявления функции параметр и тип возврата могут быть неполными).

Можно декларировать указатели и ссылки на абстрактный класс.

struct Abstract
{
   virtual void f() = 0; // чисто виртуальная функция (pure virtual)
}; // "Abstract" это абстрактный класс
 
struct Concrete : Abstract
{
   void f() override {} // non-pure virtual
   virtual void g();    // non-pure virtual
}; // "Concrete" не абстрактный класс
 
struct Abstract2 : Concrete
{
   void g() override = 0; // pure virtual переопределитель
}; // "Abstract2" это абстрактный класс
 
int main()
{
   // Abstract a;         // Ошибка: абстрактный класс
   Concrete b;          // OK
   Abstract& a = b;     // OK для ссылки на абстрактный базовый класс
   a.f();               // virtual-перенаправление на Concrete::f()
   // Abstract2 a2;       // Ошибка: абстрактный класс (конечный переопределитель
                          // g() обладает свойством pure)
}

Определение чисто виртуальной функции (pure virtual) может предоставляться (и должно предоставляться, если это чисто виртуальный деструктор): функции-члены производного класса могут свободно вызывать чисто виртуальную функцию абстрактного базового класса, используя квалифицированный идентификатор функции. Это определение должно быть предоставлено вне тела класса (синтаксис декларации функции не позволяет использовать одновременно pure-спецификатор =0 вместе с определением тела функции).

Виртуальный вызов чисто-виртуальной функции из конструктора или деструктора абстрактного класса приведет к неопределенному поведению (независимо от того, есть ли определение этой функции, или нет).

struct Abstract
{
   virtual void f() = 0;   // pure virtual
   virtual void g() {}     // non-pure virtual
   ~Abstract()
   {
      g();                 // OK: вызов Abstract::g()
      // f();                // не определенное поведение
      Abstract::f();       // OK: вызов не виртуальной функции
   }
};
 
// Определение чисто виртуальной (pure virtual) функции
void Abstract::f() { std::cout << "A::f()\n"; }
 
struct Concrete : Abstract
{
   void f() override {
      Abstract::f();       // OK: вызов pure virtual функции
   }
   void g() override {}
   ~Concrete() {
      g();                 // OK: вызов Concrete::g()
      f();                 // OK: вызов Concrete::f()
   }
};

[Ссылки]

1. abstract classes site:cppreference.com.
2. C++: спецификатор override.
3. C++: спецификатор final.