C++-Programmierung/ OOP/ Abstrakte Klassen

Aus Wikibooks

Wechseln zu: Navigation, Suche


[Bearbeiten] Einleitung

Abstrakte Klassen sind Klassen:

  • die nur aus einer Deklaration bestehen können.
  • von denen niemals Objekte erstellt werden. Keine Instantiierung möglich.
  • die oft als sog. Schnittstellen in umfangreichen Anwendungen verwendet werden.
  • die oft als Startpunkt(e) einer Vererbungshierarchie gedacht sind.

[Bearbeiten] Deklarieren

Eine Klasse wird dadurch abstrakt, indem man eine ihre Mitgliedsmethoden als rein virtuell deklariert. Dazu schreiben Sie =0 hinter die Deklaration einer virtuellen Methode.

Crystal Clear app terminal.png
class StatusAusgeber
{
public:
        virtual void printStatus(void) = 0;     // Rein virtuelle Deklaration
};

Der Versuch, eine Instanz von dieser Klasse zu erstellen, schlägt fehl:

Crystal Clear action button cancel.png
int main (void)
{
        StatusAusgeber instanz;  //Instanz von abstrakter Klasse kann nicht erstellt werden
        return 0;
};

[Bearbeiten] Verwenden

Nun beschreiben wir die Verwendung von abstrakten Klassen anhand eines Beispiels. Dazu verwenden wir die abstrakte Klasse StatusAusgeber aus dem vorigen Abschnitt.

An gewissen Stellen Ihrer Programme wollen Sie Funktionalität einer Klasse sicherstellen und diese Funktionalität verwenden, ohne auf Funktionalitäten abgeleiteter Klassen eingehen zu müssen.

Wir deklarieren die Klassen Drucker und Bildschirm.

Crystal Clear app terminal.png
class Drucker : public StatusAusgeber
{
        unsigned int m_nDruckeAusgefuehrt;
        unsigned int m_nLuefterAnzahl;
        // Diverse druckerspezifische Attribute
public:
        // Diverse druckerspezifische Methoden
        void printStatus(void)
        {
                std::cout
                        << "Geraet: Drucker"
                        << std::endl
                        << "Drucke ausgefuehrt: " << m_nDruckeAusgefuehrt
                        << std::endl
                        << "Verbaute Luefteranzahl: " << m_nLuefterAnzahl
                        << std::endl;
        }
};

class Bildschirm : public StatusAusgeber
{
        unsigned int m_nLeistungsaufnahmeWatt;
        unsigned int m_nDiagonaleAusdehnungZoll;
        // Diverse bildschirmspezifische Attribute
public:
        // Diverse bildschirmspezifische Methoden
        void printStatus(void)
        {
                std::cout
                        << "Geraet: Bildschirm"
                        << std::endl
                        << "Leistungsaufnahme (Watt): " << m_nLeistungsaufnahmeWatt
                        << std::endl
                        << "Bildschirmgroesse diagonal (Zoll): " << m_nDiagonaleAusdehnungZoll
                        << std::endl;
        }
};

Vorteil dieser Vorgehensweise ist die spätere Verwendung von Methoden der Basisklasse, bei denen die Implementierung erzwungen wurde. Der Verwender der abgeleiteten Klasse kann sich darauf verlassen, dass die Methode implementiert wurde, ohne die weiteren Teile der Hierarchie zu kennen.

Wir deklarieren die Klasse GeraeteMitStatusSpeicher

Crystal Clear app terminal.png
class GeraeteMitStatusSpeicher  : std::vector<StatusAusgeber*>
{
        static const char * _Trennzeile;        // Trennzeile zwischen den Statusangaben
public:
        void speichern(StatusAusgeber * GeraetMitStatus)
        {
                this->push_back(GeraetMitStatus); // Gerätezeiger im Vektor speichern
        }
        void printStatus(void)
        {
                std::vector<StatusAusgeber*>::const_iterator it = this->begin();
                while (it != this->end()) // Solange der Iterator nicht auf das Ende verweist
                { // Iteration über den gesamten Inhalt
                        (*it)->printStatus(); // Iterator dereferenzieren, enthaltenen Zeiger verwenden
                        std::cout << _Trennzeile << std::endl; // Trennzeile ausgeben
                        it++; // Nächsten möglichen Inhalt auswählen
                }
        }
};
const char * GeraeteMitStatusSpeicher::_Trennzeile = "---------------"; // statisch in GeraeteMitStatusSpeicher

GeraetMitStatusSpeicher ist von std::vector<StatusAusgeber*> abgeleitet, speichert Zeiger auf StatusAusgeber-Objekte.

Symbol opinion vote.svg
Hinweis

Dies ist möglich, da Zeiger eine feste Größe haben. Speicherung von Objekten abstrakter Klassen ist hier nicht möglich, da an dieser Stelle unmöglich die Größe der effektiven Objekte zu erkennen ist, auf die diese Zeiger verweisen. Genau das war uns ja von vornherein klar, weil wir nur an der printStatus()-Methode interessiert sind, deren Existenz durch die abstrakte Basisklasse sichergestellt wird. Egal ob hier ein Drucker, Monitor oder irgendein anderes Objekt hineingerät, das von StatusAusgeber abgeleitet wurde, wir können den Status ausgeben.

  • speichern(StatusAusgeber *) speichert einen Zeiger auf ein StatusAusgeber-Objekt
  • printStatus() ruft die Methode printStatus() für alle gespeicherten Zeiger auf StatusAusgeber-Objekte auf


Persönliche Werkzeuge