Konstruktoren und Destruktoren

Als Konstruktoren und Destruktoren (aus dem Englischen auch kurz ctor bzw. dtor genannt) werden in der Programmierung spezielle Prozeduren oder Methoden bezeichnet, die beim Erzeugen bzw. Auflösen von Objekten und Variablen aufgerufen werden. Konstruktoren können mit Parametern versehen werden, während Destruktoren in der Regel argumentfrei sind.

Durch Konstruktoren und Destruktoren bleibt der Anschein der Atomarität der Erstellung bzw. des Abbaus gewahrt. Gleichzeitig können bereits bei der Deklaration durch Übergabe von bestimmten Parametern die Regeln zur Erstellung und Auflösung von Variablen des betreffenden Typs formuliert werden.

Konstruktoren und Destruktoren kommen zwar in manchen objektorientierten Programmiersprachen vor, sind aber ein von der objektorientierten Programmierung (OOP) unabhängiges Konzept, das weder Voraussetzung für OOP ist, noch auf die OOP beschränkt ist. So kommen Konstruktoren und Destruktoren beispielsweise auch in prozeduralen Programmiersprachen vor.

Konstruktoren

Die Aufgabe von Konstruktoren ist, Objekte in einen definierten Anfangszustand zu bringen und so benötigte Ressourcen zu reservieren, sofern diese zum Zeitpunkt der Objekterstellung bereits bekannt sind.

Konstruktortypen

nullary constructor ist ein Konstruktor ohne Parameter:

class MyClass
{
    MyClass()
}

In den Programmiersprachen Java und C# wird eine Klasse, die keinen expliziten Konstruktor hat, implizit mit einem parameterlosen Konstruktor (default constructor) versehen.

Ein copy constructor dient der Erzeugung einer Objektkopie und hat den eigenen Objekttyp als Parameter (vergleiche flache Kopie vs. tiefe Kopie):

class MyClass
{
    MyClass(MyClass object) { }
}

Ein forwarding constructor (auch constructor forwarding genannt) gibt die Parameter an einen anderen Konstruktor weiter und verwendet Standardwerte für die fehlenden Parameter. Dies ist insbesondere für Programmiersprachen relevant, die keine Standardwerte unterstützen (z. B. Java). Dieses Konstrukt ist zu unterscheiden von einer Initialisierungsliste, in der wirklich Werte gesetzt werden, während der forwarding constructor nur Werte weitergibt.

class MyClass
{
    MyClass(int value): this(value, 0) { }
    MyClass(int value1, int value2) { }
}

Beispiele

Java

class Beispiel
{
    // Konstruktor ohne Parameter
    public Beispiel() { }

    // Konstruktor mit Parameter
    public Beispiel(String text)
    {
        System.out.println(text);
    }

    // Hauptmethode
    public static void main(String[] args)
    {
        Beispiel beispiel1 = new Beispiel();  // Keine Ausgabe
        Beispiel beispiel2 = new Beispiel("Zweiter Konstruktor");  // Ausgabe: Zweiter Konstruktor
    }
}

C++

class Beispiel
{
public:
    // Konstruktor ohne Parameter
    Beispiel() { }

    // Konstruktor mit Parameter
    Beispiel(int i)
    {
        std::cout << i << std::endl;
    }
};

C#

class Beispiel
{
	// Konstruktor ohne Parameter, der den anderen Konstruktor mit this(..., ...) aufruft
	public Beispiel() : this("Heute ist der ", DateTime.Today)
	{
	}
	
	// Konstruktor mit zwei Parametern
	public Beispiel(string text, DateTime datum)
	{
		Console.WriteLine(text + datum.ToShortDateString());
	}
	
    // Hauptmethode
	public static void Main(string[] args)
	{
		Beispiel beispiel1 = new Beispiel("Morgen ist der ", DateTime.Today.AddDays(1));
		// Aufruf des ersten Konstruktors
		// Ausgabe: Morgen ist der {dd.MM.yyyy}
		
		Beispiel beispiel2 = new Beispiel();
		// Aufruf des zweiten Konstruktors
		// Ausgabe: Heute ist der {dd.MM.yyyy}
	}
}

PHP

/**
 * @see: https://www.php.net/manual/en/language.oop5.decon.php
 */
class Foobar
{
    // Konstruktor mit Parameter und Defaultwert
    public function __construct($text = null)
    {
        if ($text !== null)
        {
            echo $text;
        }
    }

    public function Foobar()
    {
        // wird in PHP 5.3.0-5.3.2 als Konstruktor behandelt
        // wird in PHP 5.3.3 und höher als reguläre Methode behandelt
    }
}

Destruktoren

Destruktoren sind in der Regel dafür verantwortlich, vom Objekt benutzte Ressourcen freizugeben. Programmiersprachen wie C++ garantieren die Ausführung von Destruktoren, wann immer der Gültigkeitsbereich der Variablen verlassen wird (siehe RAII), sofern die Grundregel eingehalten wird, dass ein Destruktor den Kontrollfluss nicht durch Werfen einer Ausnahme (throw) unterbricht. Deshalb werden mitunter Konstruktoren und Destruktoren eingesetzt, deren einziger Zweck die Sicherstellung korrekter Ressourcenbilanz im gegebenen Kontext ist, in C++ beispielsweise bei dem Klassen-Template unique_ptr.

Unterschied zur Finalisierung

Programmiersprachen wie Java oder Python und die Entwicklungsplattform .NET verwenden das zu Destruktoren alternative Konzept der Finalisierung, bei der Aufräumarbeiten nicht zum frühest möglichen Zeitpunkt, sondern erst mit dem nächsten Lauf der automatischen Speicherbereinigung (engl. garbage collection) durchgeführt werden. Die Prozedur, die dies erledigt, nennt sich Finalisierungsroutine oder Finalisierer. Finalisierer haben im Vergleich zu Destruktoren einige Einschränkungen. So dürfen beispielsweise Finalisierer im Allgemeinen nicht auf andere Objekte verweisen, da es sein kann, dass diese bereits abgebaut wurden.

Siehe auch

Literatur

  • Bjarne Stroustrup: Die C++ Programmiersprache. 4. aktualisierte und erweiterte Auflage. Addison-Wesley, 2000, ISBN 3-8273-1660-X