C++ Tutorial

 Varianten

Eine Variante ist ein Sonderfall einer Klasse, deren Eigenschaften alle auf der gleichen Speicheradresse liegen. D.h., die Eigenschaften liegen sozusagen übereinander.

Definition

Die Definition einer Variante gleicht bis auf das Schlüsselwort union der bisherigen Definition einer Klasse und hat damit die folgende Syntax:

union [VariantName]
{
   // Eigenschaften und Memberfunktionen
} [variant1,...];

Die in Klammern stehenden Angaben sind optional. Alle Member einer Variante sind standardmäßig vom Typ public, dies kann aber durch Angabe des Zugriffsspezifizierers private: geändert werden.

Sehen wir uns dies an einem Beispiel an.

#include <iostream>
#include <format>

// Variante zum Abspeichern von Fahrzeugoptionen
union Options
{
private:
   // Bitfeld mit den einzelnen Fahrzeugoptionen
   struct
   {
      bool sunroof      : 1 = false;   // Schiebedach
      bool ledLights    : 1 = false;   // LED-Licht
      bool trafficAssist: 1 = false;   // Verkehrsassistent
      unsigned char     : 5;           // Raum fuer weitere Optionen
   };
   // Optionsschluessel, enthaelt alle Optionen bit-codiert
   unsigned char optKey;
public:
   // Schiebedach
   void SetRoof(bool sunr)
   {
      sunroof = sunr;
   }
   // LED-Licht
   void SetLights(bool lights)
   {
      ledLights = lights;
   }
   // Verkehrsassistent
   void trAssist(bool assist)
   {
      trafficAssist = assist;
   }
   // Options-Schluessel zurueckgeben
   unsigned char GetOptKey() const
   {
      return optKey;
   }
};

int main()
{
   Options myCar;          // Meine Auto-Optionen
   myCar.SetRoof(true);    // Schiebedach und
   myCar.SetLights(true);  // LED-Licht
   std::cout << std::format("Optionen: {:#x}\n",static_cast<int>(myCar.GetOptKey()));
   myCar.SetRoof(false);   // Schiebedach entfernen und
   myCar.trAssist(true);   // Verkehrsassisten hinzufuegen
   std::cout << std::format("Optionen: {:#x}\n",static_cast<int>(myCar.GetOptKey()));
}

Initialisierung einer Variante

Soll ein Variantenobjekt bei seiner Definition initialisiert werden, muss bis auf Weiteres der Datentyp des Initialwertes mit dem Datentyp des ersten Elements in der Variante übereinstimmen und der Initialisierungswert ist in einem Block einzuschließen.

#include <iostream>
#include <format>

// Variant fuer die Angabe eines Farbwertes
union Color
{
   // Struktur fuer Ablage der Farbanteile
   // rot, gruen und blau
   struct
   {
      unsigned char red;
      unsigned char green;
      unsigned char blue;
   };
   // Farbwert
   unsigned long RGB;
};

int main()
{
   // Farbwert setzen
   // Es muessen die Farbanteile rot, gruen und blau
   // angegeben werden, da die entsprechende Struktur
   // das erste Element in der Variante ist
   Color color1 {0x00, 0x88, 0xff};
   std::cout << std::format("Farbwert: {:#x}\n",color1.RGB);
   // Dies fuehrt ab zu einem Fehler!
   // Color color2 {0x112233ul};
}

Weitere Besonderheiten

Eine Variante darf

  • keine virtuelle Memberfunktion enthalten,
  • keine Referenz enthalten und
  • kann keine Basisklasse sein.

Was eine virtuelle Memberfunktion und eine Basisklasse ist, dazu kommen wir später noch.

Außerdem gibt es sogenannte anonyme Varianten, auf die aber in dieser Einführung nicht näher eingegangen werden soll.