Methodenzeiger

Ein Methodenzeiger wird bei objektorientierter Programmierung verwendet, um auf eine Methode einer Klasse oder einer Objektinstanz zu verweisen. Er ähnelt einem Funktionszeiger (einem Zeiger auf eine Funktion). In manchen Programmiersprachen ist es üblich, einen Methodenzeiger als Methode oder Referenz auf eine Methode zu bezeichnen. Es wird zwischen gebundenen und ungebundenen Methodenzeigern unterschieden, je nachdem wann der self- oder this-Parameter bestimmt wird.

Gebundene Methodenzeiger

Bei gebundenen Methoden (bound method in Python) enthält der Methodenzeiger einen Zeiger auf eine Methode und einen Zeiger auf eine Objektinstanz. Solche Methodenzeiger lassen sich als Rückruffunktion (callback function) nutzen, um Aktionen bei Ereignissen (engl.: Events) auszulösen.

Ungebundene Methodenzeiger

Bei ungebundenen (auch: freien) Methoden (unbound method in Python, Method in Java) enthält der Methodenzeiger einen Verweis auf eine Methode, aber keinen Verweis auf eine Objektinstanz. Einem ungebundenen Methodenzeiger muss beim Aufruf eine passende Objektinstanz übergeben werden.

In C++ existieren ebenfalls ungebundene Methodenzeiger. Diese zeigen auf eine Methode einer Klasse und werden beim Aufruf an ein Objekt gebunden. Hierfür existieren die Operatoren .* und ->*. Intern ist ein Methodenzeiger eine Nummer, welche einen Eintrag in der Methodentabelle der Klasse referenziert.

Auch Objective-C bietet ungebundene Methodenzeiger des Typs IMP. Wegen ihrer fehlenden Objektorientierung werden sie allerdings nur selten zur Verbesserung des Laufzeitverhaltens eingesetzt. Ansonsten wird das überlegene Konzept der Selektoren verwendet.

Beispiel in C++

#include <iostream>

class Auto {
public:
    // 4 "member functions" = "Methoden"
    void starten() {
        std::cout << "Starten..." << std::endl;
    }

    void beschleunigen(double beschleunigung);
    void bremsen(double verzoegerung);
    void ausschalten();
};

int main() {
    Auto a;

    // erzeuge method_ptr und initialisiere ihn mit Auto::starten
    void (Auto::*method_ptr)() = &Auto::starten;

    // rufe Methode, auf die method_ptr zeigt. in dem Falle: a.starten()
    (a.*method_ptr)();

    // FEHLER: Falscher Methodentyp, da Auto::beschleunigen einen Parameter
    // erwartet
    method_ptr = &Auto::beschleunigen;

    return 0;
}

Verwandte Konzepte

Delegates

In .NET-Sprachen wie C#, VB.NET oder D werden Delegate-Variablen für die Erstellung typsicherer Methodenzeiger verwendet. Zusätzlich unterstützen .NET-Delegates weitere Operationen.

Delegates in spät bindenden Sprachen

In spät bindenden Sprachen wie Objective-C ist zwischen der Nachricht („Methodenaufruf“) und der Methode zu unterscheiden. Der Compiler übersetzt eine Methode und deren Aufruf nicht in einen Index für eine vtab. Vielmehr bleibt die Nachricht unverändert bestehen. Die Liste der Methoden eines Objektes ist ein assoziatives Array, enthält also einen Verweis von Nachrichtenname auf Methode. Daher ist es möglich, erst zur Laufzeit anhand der Nachrichten zu entscheiden, welche Methode ausgeführt werden soll. Als Folge davon ist es nicht notwendig, die Klasse des Empfängers zu kennen oder dass die Methode bereits in einer bekannten Superklasse wenigstens abstrakt definiert ist.

// Instanz beliebiger (unbekannter) Klasse
id myDelegate;
// Nachrichtenname
SEL messageSelector = @selector(sender:doSomethingWithObject:);

if ([myDelegate respondsToSelector:messageSelector]) {
    [myDelegate sender:self doSomethingWithObject:anObject];
}

Es ist zu beachten, dass durch die Verwendung von id jede Instanz jeder beliebigen Klasse als Empfänger angenommen werden kann. Da Delegates nicht alle Methoden implementieren müssen, wird zur Laufzeit abgefragt, ob eine entsprechende Implementierung vorliegt. Delegating ist also ein Angebot, keine Pflicht. Es dient der Vermeidung von Ableitungen (White-Boxing) und Herstellung einer definierten API zur Funktionsspezialisierung. Implementierungsseitig lässt sich das Vorhandensein von Methodenimplementierung vortäuschen und auf diese Weise eine Nachricht weiterleiten (Forward-Invocation, Proxy).

Weblinks