zurück zum Artikel

Die speziellen Freundschaften von Templates

Rainer Grimm

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.

Die speziellen Freundschaften von Templates

Bevor ich ĂŒber die Regeln zu friend fĂŒr Templates schreibe, möchte ich die allgemeinen Regeln zur Freundschaft vorstellen.

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.

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.

Die speziellen Freundschaften von Templates

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."};

};

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).

Die speziellen Freundschaften von Templates


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).

Die speziellen Freundschaften von Templates

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