#include
using namespace std;
template<typename T>class A{
T num;
public:
A(){
num=T(5.5);
}
template<typename T> //声明为友元时也要加上template
friend void show(const A<T>&a);
};
//函数模板
template<typename T> void show(const A<T>&a){
cout<<a.num<<endl;
}
int main(){
A<int> a;
show<int>(a);
}
这种方法需要前置申明函数模板,考察如下程序。
#include
using namespace std;
template<typename T>class A; //这里是为了下一句用到A时,声明类A,同时说明其为模板类
template<typename T>void show(const A<T>&a);//这里是对友元的提前声明为模板,说明T的含义
template<typename T>class A{
T num;
public:
A(){
num=T(5.5);
}
friend void show<T>(const A<T>&a);//如果这里没有用template提前说明该友元为模板,则需要提前声明
};
template<typename T> void show(const A<T>&a){
cout<<a.num<<endl;
}
int main(){
A<int> a;
show<int>(a);
}
这种情况只能在模板类内部一起把函数的定义写出来,不能在外部实现,因为外部需要类型参数,而需要类型参数就是模板了。其实这种情况相当于一般的模板类的成员函数,也相当于一个函数模板。考察如下代码。
#include
using namespace std;
template<typename T>class A{
T num;
public:
A(){
num=T(5.5);
}
friend void show(const A<T>&a){//这个并没有用template说明,因为他直接定义在模板类内部,声明和实现在模板类内部
cout<<a.num<<endl;
}
};
int main(){
A<int> a;
show(a);
getchar();
}
程序正常编译运行并输出5。当然,将友元函数的定义改为:
template<typename T> void show(const A<T>&a){//相当于函数模板
cout<<a.num<<endl;
}
也是完全可以的,如果将函数模板放在类模板外定义的话,和第一种方式相同。由于无论是江友元函数申明为一个使用了模板类的普通函数,还是一个函数模板,由于将友元函数直接定义在类模板体内,所以不会出现申明和定义见的不一致型。
把类模板声明为类模板的友元可以有两种方式。
这里要注意是对实例化后的模板类将其申明为类模板的友元,而不是类模板。因此实例化类模板时,类模板需要前置申明。考察如下程序。
#include
using namespace std;
template<typename T>class B; //类模板前置申明
template<typename T>class A{
T num;
public:
A(){
num=T(5.5);
}
friend class B<T>;
};
template<typename T>class B{
public:
static void show(const A<T>& a){
cout<<"a.num:"<<a.num<<endl;
}
};
int main(){
A<int> a;
B<int>::show(a);
}
这里要注意是直接将类模板申明为类模板的友元,而不是实例化后的模板咧,要与上面区别对待。这里就不需要将类模板B提前申明了,在类模板A中将B申明为:
template< class T>friend class B;
同样可以将类模板B申明为类模板A的友元。
不过,这两种方式在概念上还是有一些差异。第一种方式,类模板B的实例化依赖于类模板A的参数T。也就是说,对于一个特定的模板类A< t>来说,只有一个B的实例B< t>是它的友元类。而在第二中方式中,对于一个特定的类模板A< t>来说,B的任何实例B< u>都是它的友元类。