Абстрактные классы и чисто виртуальные функции

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

Класс, содержащий хотя бы одну чисто виртуальную функцию, является абстрактным. Поэтому, классы, производные от абстрактного класса, должны реализовать все его чисто виртуальные функции, иначе они также будут абстрактными классами.

Виртуальная функция объявляется как "чистая" с помощью синтаксиса спецификатора-чистоты. Рассмотрим в качестве примера класс CAnimal, который создаётся только для того, чтобы предоставлять общие функции – сами объекты типа CAnimal имеют слишком общий характер для практического применения. Таким образом, класс CAnimal является хорошим кандидатом в абстрактный класс:

class CAnimal
  {
public:
                      CAnimal();     // конструктор
   virtual void       Sound() = 0;   // чисто виртуальная функция
private:
   double             m_legs_count;  // количество ног животного
  };

Здесь функция Sound() является чисто виртуальной, потому что она объявлена со спецификатором чисто виртуальной функции PURE (=0).

Чисто виртуальными функциями являются только такие виртуальные функции, для которых указан спецификатор чистоты  PURE, а  именно: (=NULL) или (=0). Пример объявления и использования абстрактного класса:

class CAnimal
  {
public:
   virtual void       Sound()=NULL;   // PURE method, должен быть переопределён в потомке, сам класс CAnimal стал абстрактным и не может быть создан
  };
//--- потомок от абстрактного класса
class CCat : public CAnimal
 {
public:
  virtual void        Sound() { Print("Myau"); } // PURE переопределён, класс CCat не абстрактный и может быть создан
 };
 
//--- примеры неправильного использования
new CAnimal;         // ошибка 'CAnimal' - компилятор выдаст ошибку "cannot instantiate abstract class"
CAnimal some_animal; // ошибка 'CAnimal' - компилятор выдаст ошибку "cannot instantiate abstract class"
 
//--- примеры правильного использования
new CCat;  // ошибки нет - класс CCat не абстрактный
CCat cat;  // ошибки нет - класс CCat не абстрактный

 
Ограничения на использование абстрактных классов

При вызове конструктором абстрактного класса чистой виртуальной функции (прямо или косвенно) результат будет неопределённым.

//+------------------------------------------------------------------+
//| Абстрактный базовый класс                                        |
//+------------------------------------------------------------------+
class CAnimal
  {
public:
   //--- чисто виртуальная функция
   virtual void      Sound(void)=NULL;
   //--- функция
   void              CallSound(void) { Sound(); }
   //--- конструктор
   CAnimal()
    {
     //--- явный вызов виртуального метода
     Sound();
     //--- неявный вызов (через третью функцию)
     CallSound();
     //--- в конструкторе и/или деструкторе всегда вызываются свои функции,
     //--- несмотря на виртуальность и переопределение вызываемой функции в потомке
     //--- если вызываемая функция чисто виртуальная, то
     //--- вызов приведёт к критической ошибке выполнения: "pure virtual function call"
    }
  };

Однако конструкторы и деструкторы абстрактных классов могут вызывать другие функции-члены.