C++ Tutorial

friend Funktionen & Klassen

Manchmal kann es notwendig sein, dass Klassen oder Funktionen Zugriff auf die geschützten Member einer anderen Klasse haben. Einen dieser Fällen haben wir beim Überladen der Operatoren << und >> für die Ein-/Ausgabe kennengelernt.

Sehen wir uns einen weiteren Fall an. Angenommen, wir haben eine Klasse Matrix, die eine Tabelle enthält, und eine Klasse Vektor mit einem 1-dimensionalen Feld. Nun sollen alle Werte der Zeile n in der Tabelle Matrix mit dem Faktor Vektor[n] multipliziert werden.

1: // Jede Zeile des Feldes Matrix::aMatrix ist mit
2: // dem Faktor des Feldes Vektor::aVektor zu
3: // multiplizieren, also aMatrix[i][0..2] *= aVektor[i]
4: // Definition von Matrix
5: class Matrix
6: {
7:    short aMatrix[3][3];
8:    ...
9: };
10: // Definition von Vector
11: class Vektor
12: {
13:    short aVektor[3];
14:    ...
15: };

Da die Daten der Tabelle und des Vektors in der Regel in der private-Sektion ihrer Klasse definiert sind, hat die Klasse Matrix keinen Zugriff auf die Faktoren in der Klasse Vektor und umgekehrt. Wir könnten zwar die Eigenschaften als public deklarieren, würden damit aber den Zugriff auf die Eigenschaften generell freigeben. Eine Möglichkeit das Problem zu lösen ist der Einsatz von friend-Klassen.

friend-Klassen

Damit eine Klasse A Zugriff auf alle Member einer Klasse B erhält, wird die Klasse A als friend-Klasse der Klasse B deklariert. Hierzu wird innerhalb der Klassendefinition der Klasse, die ihren 'Schutz' aufgibt, folgende Anweisung eingefügt:

friend class FCLASS;

FCLASS ist die Klasse, die uneingeschränkten Zugriff auf alle Member der Klasse erhalten soll. Im nachfolgenden Beispiel erhält die Klasse Matrix Zugriff auf alle Member der Klasse Vektor.

1: // Definition von Matrix
2: class Matrix
3: {
4:    short aMatrix[3][3];
5:    ...
6: };
7: // Definition von Vektor
8: // Erlaubt Matrix Zugriff auf alle Member
9: class Vektor
10: {
11:    friend class Matrix;
12:    short aVektor[3];
13:    ...
14: };

Da Matrix nun auf alle Member von Vektor zugreifen kann, könnte die notwendige Routine zur Multiplikation der Matrixdaten wie folgt aussehen.

1: // Vorwärtsdeklaration von Vektor
2: class Vektor;
3: // Definition von Matrix
4: class Matrix
5: {
6:    short aMatrix[3][3];
7:    void Multi(const Vektor& vect);
8: ...
9: };
10: // Definition von Vektor
11: // Erlaubt Matrix Zugriff auf alle Member
12: class Vektor
13: {
14:    friend class Matrix;
15:    short aVektor[3];
16:    ...
17: };
18: // Definition von Matrix::Multi
19: void Matrix::Multi(const Vektor& vect)
20: {
21:    for (auto row=0; row<3; row++)
22:       for (auto col=0; col<3; col++)
23:          aMatrix[row][col] *= vekt.aVektor[row];
24: }

Dabei ist zu beachten, dass Vektor vor Matrix per Vorwärtsdeklaration deklariert ist, da die Methode Multi() als Parameter eine Referenz auf die Klasse Vektor erhält. Eine Definition der Klasse Vektor vor Matrix ist nicht möglich, da innerhalb von Vektor die Klasse Matrix als friend-Klasse deklariert wird. Zudem kann die endgültige Definition der Methode Multi() erst nach der Definition der Klasse Vektor erfolgen, da innerhalb der Methode auf die Eigenschaft aVektor von Vektor zugegriffen wird.

Die friend-Eigenschaft einer Klasse wird niemals vererbt. Würde von der Klasse Matrix eine weitere Klasse SMatrix abgeleitet, hätte SMatrix keinen Zugriff auf die geschützten Eigenschaften von Vektor.

Außerdem gilt die friend-Eigenschaft nicht für den Umkehrfall, d.h. ist die Klasse Matrix friend-Klasse von Vektor, ist Vektor nicht automatisch friend-Klasse von Matrix. Dieser Fall ist explizit zu spezifizieren.

friend-Funktionen

Um eine Funktion als friend-Funktion einer Klasse zu deklarieren, wird wieder innerhalb der Klasse, die ihren 'Schutz' aufgibt, folgende Anweisung eingefügt:

friend RTYP FName([PARAM]);

RTYP ist der Returntyp der Funktion FName. Die Definition der Funktion erfolgt wie gewohnt, d.h. ohne Angabe der friend-Beziehung zu einer Klasse.

1: // Klassendefinition
2: class Base
3: {
4:    ...
5:    friend void DoAnything();
6: };
7: // Definition der friend-Funktion
8: void DoAnything()
9: {
10:    ... // Voller Zugriff auf Klasse Base
11: }

Bezüglich Ableitung von Klassen und friend-Funktionen gilt das Gleiche wie bei friend-Klassen. Ist eine Funktion Func() friend-Funktion der Klasse Base und ist von Base eine Klasse Any abgeleitet, ist Func() nicht automatisch friend-Funktion von Any. Auch dies ist ebenfalls explizit anzugeben.

Einsatz von friend-Funktionen

Obwohl friend-Funktionen so weit wie möglich vermieden werden sollten, gibt es Fälle, wo es ohne friend-Funktion nicht geht. So wurde z.B. in einem vorangegangenen Kapitel der Plus-Operator '+' der Klasse CString überladen, um folgende Anweisungen schreiben zu können:

stringObj3 = stringObj1 + stringObj2;
stringObj3 = stringObj1 + "any text";
1: // Klassendefinition
2: class CString
3: {
4:    ...
5:    CString& operator + (const CString& op2);
6:    CString& operator + (const char* pT);
7: };

D.h., zu einem CString-Objekt konnte entweder ein CString-Objekt oder ein C-String hinzugefügt werden. Was bisher nicht möglich war, ist folgende Operation:

stringObj3 = "any text" + stringObj2;

Der Grund hierfür ist, dass der überladene Operator '+' als Methode des linken Operanden const char* aufgerufen wird, was die Definition einer Methode unmöglich macht. Damit diese Operation durchgeführt werden kann, wird eine friend-Funktion eingesetzt, die im ersten Parameter den const char-Zeiger erhält und im zweiten Parameter eine Referenz auf das CString-Objekt.

1: // Klassendefinition
2: class CString
3: {
4:    ...
5:    CString operator + (const char *pT);
6:    CString operator + (const CString& op2);
7:    friend CString operator + (const char* pT,
8:    const CString& op2);
9: };
10: // Definition der friend-Funktion
11: CString operator + (const char* pT, const CString& op2)
12: {
13:    CString temp(pT);
14:    temp = temp + op2;
15:    return temp;
16: }

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