Die speziellen Freundschaften von Templates
Ein Freund hat uneingeschrÀnkten Zugang zu den Mitgliedern einer Klasse. Deshalb sollte die Freundschaft mit Bedacht vergeben werden. In Bezug auf Templates verhÀlt sich die Freundschaft besonders.
Ein Freund hat uneingeschrÀnkten Zugang zu den Mitgliedern einer Klasse. Deshalb sollte die Freundschaft mit Bedacht vergeben werden. In Bezug auf Templates verhÀlt sich die Freundschaft besonders.
Bevor ich ĂŒber die Regeln zu friend fĂŒr Templates schreibe, möchte ich die allgemeinen Regeln zur Freundschaft vorstellen.
- Die
friendDeklaration kann an jeder beliebigen Stelle in der Klasse erfolgen. - Bei der
friendDeklaration werden die Zugriffsrechte in der Klasse nicht berĂŒcksichtigt. - Freundschaft wird nicht vererbt. Wenn eine Klasse
Baseeiner KlasseDerivedFreundschaft gewÀhrt, ist eine vonDerivedabgeleitete Klasse nicht automatisch ein Freund vonBase. - Freundschaft ist nicht transitiv. Wenn die Klasse
Bmit der KlasseAbefreundet ist und die KlasseCmit der KlasseBbefreundet ist, ist die KlasseCnicht automatisch mit der KlasseAbefreundet.
Eine Klasse oder ein Klassen-Template kann mit einer Klasse oder einem Klassen-Template, einer Funktion oder einem Funktions-Template oder einem Typ befreundet sein.
Allgemeine Freundschaft
Eine Klasse oder ein Klassen-Template kann jeder Instanz eines Klassen-Templates oder Funktions-Template Freundschaft gewÀhren.
// generalFriendship.cpp
#include <iostream>
template <typename T> // (1)
void myFriendFunction(T);
template <typename U> // (2)
class MyFriend;
class GrantingFriendshipAsClass {
template <typename U> friend void myFriendFunction(U);
template <typename U> friend class MyFriend;
std::string secret{"Secret from GrantingFriendshipAsClass."};
};
template <typename T>
class GrantingFriendshipAsClassTemplate{
template <typename U> friend void myFriendFunction(U);
template <typename U> friend class MyFriend;
std::string secret{"Secret from GrantingFriendshipAsClassTemplate."};
};
template <typename T> // (3)
void myFriendFunction(T){
GrantingFriendshipAsClass myFriend;
std::cout << myFriend.secret << '\n';
GrantingFriendshipAsClassTemplate<double> myFriend1;
std::cout << myFriend1.secret << '\n';
}
template <typename T> // (4)
class MyFriend{
public:
MyFriend(){
GrantingFriendshipAsClass myFriend;
std::cout << myFriend.secret << '\n';
GrantingFriendshipAsClassTemplate<T> myFriend1;
std::cout << myFriend1.secret << '\n';
}
};
int main(){
std::cout << '\n';
int a{2011};
myFriendFunction(a);
MyFriend<double> myFriend;
std::cout << '\n';
}
(1) und (2) deklarieren das Funktions-Template myFriendFunction und das Klassen-Template MyFriend. Das Funktions-Template myFriendFunction wird in (3) und das Klassen-Template MyFriend in (4) definiert. Die Klassen GrantingFriendshipAsClass und GrantingFriendshipAsClassTemplate gewÀhren dem Funktions-Template myFriendFunction und dem Klassen-Template MyFriend Freundschaft. Aufgrund der Freundschaft können beide Templates die private Variable secrete der Klasse und des Klassen-Templates direkt aufrufen.
Bei dem Klassen-Template GrantingFriendShipAsClassTemplate gibt es einen Fallstrick: Normalerweise heiĂt der erste Typparameter eines Templates T. Wer - wie im folgenden Codeschnipsel - denselben Typparameternamen fĂŒr das Klassen-Template und das Funktions-Template myFriendFunction oder das Klassen-Template MyFriend verwendet, erhĂ€lt eine Fehlermeldung. Der Bezeichner T von myFriendFunction oder MyFriend verdeckt den Bezeichner T des Klassen-Templates GrantingFriendshipAsClassTemplate.
Das folgende Codeschnipsel stellt den Fallstrick dar.
template <typename T>
class GrantingFriendshipAsClassTemplate{
template <typename T> friend void myFriendFunction(T);
template <typename T> friend class MyFriend;
std::string secret{"Secret from GrantingFriendshipAsClassTemplate."};
};
Besondere Freundschaft
Eine besondere Freundschaft ist eine Freundschaft, die vom Typ des Template-Parameter abhÀngt.
// specialFriendship.cpp
#include <iostream>
template <typename T> void myFriendFunction(T);
template <typename U> class MyFriend;
class GrantingFriendshipAsClass {
friend void myFriendFunction<>(int); // (1)
friend class MyFriend<int>; // (2)
private:
std::string secret{"Secret from GrantingFriendshipAsClass."};
};
template <typename T>
class GrantingFriendshipAsClassTemplate {
friend void myFriendFunction<>(int);
friend class MyFriend<int>;
friend class MyFriend<T>; // (3)
private:
std::string secret{"Secret from GrantingFriendshipAsClassTemplate."};
};
template <typename T>
void myFriendFunction(T) {
GrantingFriendshipAsClass myFriend;
std::cout << myFriend.secret << '\n'; // (4)
GrantingFriendshipAsClassTemplate<T> myFriend1;
std::cout << myFriend1.secret << '\n'; // (5)
}
template <typename T> // (6)
class MyFriend {
public:
MyFriend() {
GrantingFriendshipAsClass myFriend;
std::cout << myFriend.secret << '\n';
GrantingFriendshipAsClassTemplate<int> myFriendInt;
std::cout << myFriendInt.secret << '\n';
GrantingFriendshipAsClassTemplate<T> myFriendT;
std::cout << myFriendT.secret << '\n';
}
};
int main() {
std::cout << '\n';
int a{2011};
myFriendFunction(a);
MyFriend<int> myFriend;
std::cout << '\n';
}
Die Klasse GrantingFriendshipAsClass gewĂ€hrt Freundschaft fĂŒr die vollstĂ€ndige Spezialisierung des Funktions-Template myFriendFunction fĂŒr int (1) und des Klassen-Template MyFriend fĂŒr int (2). Dasselbe gilt fĂŒr das Klassen-Template GrantingFrandshipAsClassTemplate. (3) ist besonders, weil sie der vollstĂ€ndigen Spezialisierung fĂŒr MyFriend Freundschaft gewĂ€hrt, die denselben Typparameter hat wie das Klassen-Template GrantingFrandshipAsClassTemplate. Folglich kann das Funktions-Template myFriendFunction secret der Klasse GrantingFriendshipAsClass aufrufen, wenn myFriendFunctions eine vollstĂ€ndige Spezialisierung fĂŒr int ist (4) oder GrantingFriendshipAsClassTemplate den gleichen Typ wie myFriendFunction besitzt (5). Die entsprechende Argumentation gilt fĂŒr das Klassen-Template MyFriend (6).
Freund zu Typen
Ein Klassen-Template kann seine Freundschaft auch an einen Typparameter vergeben.
// typeFriendship.cpp
#include <iostream>
template <typename T>
class Bank {
std::string secret{"Secret from the bank."};
friend T;
};
class Account{
public:
Account() {
Bank<Account> bank;
std::cout << bank.secret << '\n'; // (1)
}
};
int main(){
std::cout << '\n';
Account acc;
std::cout << '\n';
}
Die Klasse Bank gewÀhrt ihrem Typparameter T Freundschaft. Daher kann ein Account auf das secret der Bankinstanz zugreifen: Bank<Account> (1).
Wie geht's weiter?
In meinem nĂ€chsten Beitrag schreibe ich ĂŒber einen der anspruchsvollen Bereiche von Templates: dependent names. ( [1])
URL dieses Artikels:
https://www.heise.de/-6205933
Links in diesem Artikel:
[1] mailto:rainer@grimm-jaud.de
Copyright © 2021 Heise Medien