Abstrakte Klassen und rein virtuelle Funktionen

Abstrakte Klassen sind für die Erstellung generalisierter Entitäten bestimmt, aufgrund deren später konkretere abgeleitete Klassen erstellt werden. Eine abstrakte Klasse ist die Klasse, die nur als Basisklasse für eine andere Klasse genutzt werden kann. Aus diesem Grund kann man kein Objekt vom Typ abstrakter Klasse erstellen

Eine Klasse, die mindestens eine rein virtuelle Funktion enthält, gilt als abstrakt. Deswegen müssen Klassen, die von einer abstrakten Klasse abgeleitet wurden, alle ihre rein virtuellen Funktionen umsetzen, sonst werden sie auch als abstrakte Klassen gelten.

Eine virtuelle Funktion wird als "reine" mit der Syntax des Reinheit-Spezifikators deklariert. Schauen wir uns die CAnimal-Klasse an, die nur für die Gewährleistung allgemeiner Funktionen erstellt wird - Objekte vom Typ CAnimal sind zu allgemein für eine praktische Anwendung. So ist die CAnimal-Klasse ein guter Kandidat für abstrakte Klasse:

class CAnimal
  {
public:
                      CAnimal();     // Konstruktor
   virtual void       Sound() = 0;   // rein virtuelle Funktion
private:
   double             m_legs_count;  // Anzahl der Pfoten
  };

Die Sound()-Funktion ist hier rein virtuell, weil sie mit dem Spezifikator der rein virtuellen PURE-Funktion (=0) deklariert wurde.

Als rein virtuelle werden nur die virtuellen Funktionen bezeichnet, für welche der PURE-Spezifikator angegeben wurde, und zwar: (=NULL) oder (=0). Beispiel der Deklaration und Anwendung abstrakter Klassen:

class CAnimal
  {
public:
   virtual void       Sound()=NULL;   // PURE method, muss in der abgeleiteten Klasse umdefiniert werden, die CAnimal Klasse selbst ist abstrakt geworden und kann nicht erstellt werden
  };
//--- abgeleitet von der abstrakten Klasse
class CCat : public CAnimal
 {
public:
  virtual void        Sound() { Print("Myau"); } // PURE umdefiniert, die CCat Klasse ist nicht abstrakt und kann erstellt werden
 };
 
//--- Beispiele für falsche Anwendung
new CAnimal;         // Fehler 'CAnimal' - der Compiler zeigt die Fehlermeldung "cannot instantiate abstract class" an
CAnimal some_animal; // Fehler 'CAnimal' - der Compiler zeigt die Fehlermeldung "cannot instantiate abstract class" an
 
//--- Beispiele für richtige Anwendung
new CCat;  // kein Fehler - die CCat Klasse ist nicht abstrakt
CCat cat;  // kein Fehler - die CCat Klasse ist nicht abstrakt

 
Begrenzungen für Anwendung abstrakter Klasse

Wenn der Konstruktor einer abstrakten Klasse die rein virtuelle Funktion (direkt oder indirekt) aufruft, wird das Ergebnis undefiniert sein.

//+------------------------------------------------------------------
//| Abstrakte Basisklasse                                  |
//+------------------------------------------------------------------
class CAnimal
  {
public:
   //--- rein virtuelle Funktion
   virtual void      Sound(void)=NULL;
   //--- Funktion
   void              CallSound(void) { Sound(); }
   //--- Konstruktor
   CAnimal()
    {
     //--- impliziter Aufruf einer virtuellen Methode
     Sound();
     //--- expliziter Aufruf (über eine dritte Funktion)
     CallSound();
     //--- Konstruktor bzw. Destruktor ruft immer seine eigenen Funktionen auf,
     //--- trotz der Virtualität und Umdefinierung der aufgerufenen Funktion in einer abgeleiteten Klasse
     //--- wenn diese Funktion rein virtuell ist,
     //--- führt der Aufruf zum kritischen Ausführungsfehler: "pure virtual function call"
    }
  };

Jedoch können Konstruktoren und Destruktoren abstrakter Klassen andere Memberfunktionen aufrufen.