非模板友元
声明一个常规友元
template
class HasFriend
{
public:
friend void counts();
}
上边的声明使counts()函数成为模板所有实例化的友元
counts()函数不是通过对象调用的(它是友元,不是成员函数),也没有对象参数,那么它如何访问HasFriend对象的呢
有很多种可能性。它可以访问全局对象;可以使用全局指针访问非全局对象;可以创建自己的对象;可以访问独立对象的模板类
的静态数据成员。
如果要为友元函数提供械板类参数,可以如下所示来进行友元声明。要提供模板类参数,必须指明基体化
template
class HasFriend
{
friend void report(HasFriend &);
}
report()本身并不是模板函数,而只是使用一个模板作参数。这意味着必须要使用的友元定义显式基体化:
void report(HasFriend &){....}
void report(HasFriend &){...};
也就是说report(HasFriend &)将成为HasFriend类的友元。
复制代码
includeusing std::cout;using std::cin;using std::endl;
templateclass HasFriendT{private:
TT item;static int ct;public:
HasFriendT(const TT & i):item(i){ct++;};~HasFriendT(){ct--;};friend void counts();friend void report(HasFriendT &);};
template int HasFriendT::ct = 0;
void counts(){
cout<<"int count: "<::ct<<";";cout<<"double count:"<::ct<}
void report(HasFriendT & hf){
cout<}
void report(HasFriendT & hf){
cout<}int main(){
counts();HasFriendT hfi1(10);counts();
HasFriendT hfdb(10.5);report(hfi1);HasFriendT hfi2(20);
report(hfi2);report(hfdb);
counts();cin.get();}
//int count: 0;double count:0//int count: 1;double count:0//10//20//10.5//int count: 2;double count:1复制代码
约束模板友元函数友元的类型取决于类被实例化时的类型
可以修改上边的示例,使友元函数本身成为模板。具体的说,为约束模板友元作准备,要使类的每一个基体
化都获得与友元匹配的基体化。这需要3部
1首先,在类定义的前面声明每个模板函数
template void counts()
template void report(T &);
2然后,在函数中再次将模板声明为友元。这些语句根据类模板参数的类型声明具体化:
template
class HasFriendT
{
friend void counts();
friend void report<>(HasFriendT &);
};
声明中的<>指出这是模板具体化。对于report(),<>可以为空,因为可以从函数参数推断出如下模板类型参数:
HasFriendT
然而也可以使用:
report>(HasFriendT &)
但是counts()函数没有参数,因此必须使用模板参数语法()来指明其基体化。还需要注意的是,
TT是HasFriendT类的参数类型。
同样,理解这些声明的最佳方式也是设想声明一个特定具体化的对象时,它们将变成什么样子。例如,
假设声明了这样一个对象
HasFriendT squack;
编译器将用int替换TT,并生成下面的类定义
class HasFriendT
{
friend void counts();
friend void report<>(HasFriendT &);
}
3第三个条件是为友元提供模板定义
看例子:
复制代码
includeusing std::cout;using std::cin;using std::endl;template void counts();template void report(T &);
templateclass HasFriendT{private:
TT item;static int ct;public:
HasFriendT(const TT & i):item(i){ct++;};~HasFriendT(){ct--;};friend void counts();friend void report<>(HasFriendT &);};
template int HasFriendT::ct = 0;
templatevoid counts(){
cout<<"template size: "<)<<";";cout<<"template counts():"<::ct<}templatevoid report(T & hf){
cout<}int main(){
counts();HasFriendT hfi1(10);HasFriendT hfi2(20);HasFriendT hfdb(10.5);report(hfi1);report(hfi2);report(hfdb);cout<<"counts output:n";counts();cout<<"counts() output:n";counts();cin.get();}
//template size: 4;template counts():0//10//20//10.5//counts output://template size: 4;template counts():2//counts() output://template size: 8;template counts():1复制代码counts 和couts 报告的模板大小不同,这样每种T类型都有自己的友元函数count();
非约束模板友元
友元的所有具体化都是类的每一个具体化的友元
上边说的约束模板友元函数是在类外面声明的模板的具体化。int类型具体化获得int函数具体化,
依此类推。通过在类内部声明模板,可以创建非约束友元函数,即每个函数具体化都是每个类具体化的友元。
对于非约束友元,友元模板类型参数与模板类类型参数是不同的:
template
{
template
friend void Show2(C &,D &)
}
上边是一个使用非约束友元函数的例子,其中,函数调用show2(hfi1,hfi2)与下面的具体化匹配:
void Show2 &,ManyFriend &>(ManyFriend & c,ManyFriend & d);
因为它是所有ManyFriend 具体化的友元,所以能够访问所有具体化的item成员,但它只访问了ManyFriend对象。
同样Show2(hfd,hfd2)与下面具体化匹配:
void Show2(ManyFirend &,ManyFirend &>(ManyFirend & c,ManyFirend & d);
它也是所有ManyFriend具体化的友元,并访问了ManyFirend 对象的item成员和ManyFriend对象的item成员
复制代码
includeusing std::count;using std::cout;using std::endl;
templateclass ManyFriend{private:
T item;public:
ManyFriend(const T & i):item(i){};templatefriend void Show2(C &,D &);};
templatevoid Show2(C & c,D & d){
cout<}
int main(){
ManyFriend hfi1(10);ManyFriend hfi2(20);ManyFriend hfdb(10.5);
cout<<"hfi1, hfi2";Show2(hfi1,hfi2);cout<<"hfdb,hfi2: ";
Show2(hfdb,hfi2);std::cin.get();}
//hfi1, hfi210,20//hfdb,hfi2: 10.5,20