C++ Tutorial

Anhang J: Memberzeiger

Während 'normale' Zeiger auf eine Variable, ein Objekt oder eine Funktion verweisen, verweisen Memberzeiger auf ein Member innerhalb der Klasse. Da aber ein Zugriff auf Member (fast) immer nur über ein Objekt erfolgen kann, benötigt ein Memberzeiger ein Objekt als Referenz.

Schnittstellenzeiger (Zeiger auf Methoden)

Beginnen wir mit Zeiger auf Methoden, dem sogenannten Schnittstellenzeiger. Nachfolgend die Ausgangsklasse für das Beispiel zur Anwendung eines Schnittstellenzeigers.

1: class State
2: {
3: public:
4:    void Init();
5:    void State1();
6:    void State2();
7:    void State3();
8:    void Execute();
9: };

Die Klasse enthält die Methode Init() zur Initialisierung der Eigenschaften und drei weitere Methoden StateX(), die später über einen Schnittstellenzeiger in der Methode Execute() aufgerufen werden.

Zunächst gilt es, den Schnittstellenzeiger innerhalb der Klasse zu definieren.

RTYP (KLASSE::*PNAME)([PARAMETER]);

RTYP ist der Returntyp der über den Schnittstellenzeiger aufzurufenden Methode, KLASSE ist die Klasse der Methode und PNAME der Name des Schnittstellenzeigers. Besitzt die aufzurufende Methode Parameter, so sind zumindest deren Datentypen PARAMETER in der Parameterklammer aufzuführen.

Eleganter geht es mithilfe des decltype() Spezifizierers. Hier ist nur der Name MEMFUNC der aufzurufenden Methode anzugeben.

decltype (&KLASSE::MEMFUNC) PNAME;

Nachfolgend wurde der Klasse State der Schnittstellenzeiger pfnState hinzugefügt, über den später die Methoden StateX() aufgerufen werden können.

1: class State
2: {
3: public:
4:    void Init();
5:    void Execute();
6: private:
7:    void State1();
8:    void State2();
9:    void State3();
10:   // Definition des Schnittstellenzeigers
11:   decltype(&State::State1) pfnState;
12:   // Alternativ: Definition ohne decltype()
13:   // void (State::*pfnState)();
14: };

Um einem Schnittstellenzeiger die "Adresse" einer Methode zuzuweisen, wird zuerst der Adressoperator & angegeben, gefolgt vom voll qualifizierten Namen der Methode.

1: void State::Init()
2: {
3:    pfnState = &State::State1;
4: }

Wird ein Schnittstellenzeiger bei seiner Definition initialisiert, vereinfacht sich dessen Definition, da der Datentyp mittels auto bestimmt werden kann.

auto pfnState = &State::State1;

Bleibt noch der Aufruf der Methode übrig, auf die der Schnittstellenzeiger verweist.

1: void State::Execute()
2: {
3:    (this->*pfnState)();
4: }

Dieser Aufruf enthält zwei Neuerungen. Zum einen wird hier der Zeiger this verwendet und zum anderen der Operator ->*. Der Zeiger this wird später genauer beschrieben, vorab nur so viel dazu: Er enthält die Adresse des Objekts, in dessen Kontext die Methode aufgerufen wurde. Und der Operator ->* dient einzig und allein zum Zugriff auf Member über Memberzeiger.

Die Definition eines Schnittstellenzeigers außerhalb einer Klasse ist mit der innerhalb einer Klasse identisch. Beachten werden muss dabei, dass über den Schnittstellenzeiger nur auf die public-Methoden zugegriffen werden kann.

Beim Aufruf einer Methode über den Schnittstellenzeiger ist zuerst das Objekt anzugeben, dessen Methode aufgerufen werden soll. Anschließend folgt der Operator .* und der Schnittstellenzeiger. Soll die Methode über einen Objektzeiger aufgerufen werden, ist anstelle des Operators .* der Operator ->* zu verwenden.

1: // Klassendefinition
2: class State
3: {
4:    ...
5: };
6: ...
7: // Definition zweier Objekte
8: State myState, yourState;
9:
10: int main()
11: {
12:   // Offset der Methode im Zeiger ablegen
13:   auto pfnMember = &State::State2;
14:   // Methode für myState-Objekt aufrufen
15:   (myState.*pfnMember)();
16:   // Methode für yourState-Objekt aufrufen
17:   (yourState.*pfnMember)();
18:   ...
19:   // Zeiger auf Objekt definieren und initial.
20:   auto pObj = &myState;
21:   // Methode über Objektzeiger aufrufen
22:   (pObj->*pfnMember)();
23: };

Eigenschaftszeiger (Datenzeiger)

Sehen wir uns an, wie über Zeiger auf die Eigenschaften einer Klasse zugegriffen werden kann. Die Definition des Eigenschaftszeigers erfolgt ebenfalls durch Voranstellen des Klassennamens vor dem Zeigernamen. Auch die Zuweisung einer Eigenschaft an einen solchen Zeiger erfolgt auf die gleich Weise wie beim Schnittstellenzeiger, d.h. zuerst kommt der Adressoperator, dann der Klassenname, dann der Operator :: und zum Schluss der Name der Eigenschaft.

Um über diesen Zeiger auf die Eigenschaft der Klasse zuzugreifen, werden ebenfalls die Operatoren .* bzw. ->* verwendet.

1: // Klassendefinition
2: class State
3: {
4: public:
5:    ...
6:    int data;
7: };
8:
9: // Definition des Memberzeigers
10: decltype(&State::data) pData; // oder: int State::*pData;
11:
12: int main()
13: {
14:   // State-Objekt definieren
15:   State myState;
16:   // Objektzeiger initialisieren
17:   auto pAnyState = &myState;
18:   // Memberzeiger auf Datum (Offset!)
19:   pData = &State::data;
20:   // Datum im ersten Objekt setzen
21:   myState.*pData = 10;
22:   // Datum über Zeiger auslesen
23:   auto var = pAnyState->*pData;
24:   ...
25: }

Copyright 2024 © Wolfgang Schröder
E-Mail mit Fragen oder Kommentaren zu dieser Website an: info@cpp-tutor.de
Impressum & Datenschutz