对于在一个类中声明一个函数或者一个类的友元,我们应该是十分熟悉了,但是这两天在做题的时候遇到一个问题,就是如何在一个类模板中声明一个模板函数与我们的模板类的友元关系?
刚开始遇到这个问题的时候,说实话我有点懵,因为之前根本没考虑到这一层,所以趁这次机会又将模板和友元相关的东西整理了一下,翻了下《C++Primer》,上网查了一下,我大致总结出如下:
模板类中可以出现的三种友元声明:
1.普通非模板类或函数的友元声明,将友元关系授予明确指定的类或函数;
2.类模板或函数模板的友元声明,授予对应的类模板或函数模板所有实例对我们的模板类所有实例中的所有成员的访问权;
3.只授予类模板或函数模板的特定实例对我们的模板类所有实例或对应实例中的所有成员的访问权的友元声明;
上面三点或许有点绕,下面来逐点解释:(以下均用函数模板的友元声明来举例,类模板的友元声明与之类似)
1.其实第一点挺简单的,没有什么好说的,例子如下:
template<class T>
class A
{
friend void fun();
friend class B;
private:
T _a;
};
void fun()
{
A<int> a1;
A<double> a2;
a1._a=1;
a2._a=1.0;
cout<<a1._a<<endl;
cout<<a2._a<<endl;
}
这个例子中,可以在fun函数中访问A任意实例中的私有或保护成员;
2.在模板类内声明友元的函数模板
template<typename T>
class A
{
template<class T1>
friend void fun();
private:
T _a;
};
template<typename T1>
void fun()
{
A<int> a1;
A<double> a2;
a1._a=1;
a2._a=1.0;
cout<<a1._a<<endl;
cout<<a2._a<<endl;
}
void funtest()
{
fun<int>();
fun<double>();
}
就如上面这个例子,在我们模板类A中声明了模板函数fun,两者拥有各自的模板形参T和T1,两者是互不影响的,所以在这里对于fun的所有实例(如fun<int>,fun<double>)对于A的所有实例(如A<int>,A<double>)中的私有或保护成员都可以进行访问;
3.在模板类中声明模板函数的某一特定实例的友元关系
template<class T1>
void fun();
template<typename T>
class A
{
friend void fun<int>();
private:
T _a;
};
template<typename T1>
void fun()
{
A<int> a1;
A<double> a2;
a1._a=1;
a2._a=1.0;
cout<<a1._a<<endl;
cout<<a2._a<<endl;
}
void funtest()
{
fun<int>();
//fun<double>();
}
int main()
{
funtest();
return 0;
}
上面这个例子,在模板类A中我们声明了模板函数fun实例化后的fun<int>的友元关系,因此我们在这里仅能够在fun<int>中对模板类A中的所有实例的私有或保护成员具有访问权限,而对于fun<double>则不是模板类A的友元函数,不具有访问其实例的私有或保护成员的权限(编译会出错)。
对于上面这个例子,我们可以做一点改动,将友元声明改为friend void fun<T>();
template<class T1>
void fun();
template<typename T>
class A
{
friend void fun<T>();
private:
T _a;
};
template<typename T1>
void fun()
{
A<int> a1;
A<double> a2;
a1._a=1;
a2._a=1.0;
cout<<a1._a<<endl;
cout<<a2._a<<endl;
}
void funtest()
{
fun<int>();
fun<double>();
}
int main()
{
funtest();
return 0;
}
将上面的例子拿去测试,我们发现对于fun<int>仅对模板类A的实例A<int>的私有或保护成员具有访问权限,对于A<double>则没有;而对于fun<double>则反之。总之,对于fun的实例只对与它的模板实参一致的A实例有友元关系。
这里需要注意一点,对于第三种友元,要对我们的函数模板进行前置声明(虽然在某些情况下,不加前置声明也不会报错)。
到这里应该大致明白类模板中可以进行的三种友元的声明了,对于第一种友元的声明,真的挺简单的,没有什么好说的,下面着重来讨论对于建立友元的函数的模板该如何进行定义声明。
1.封闭型
也就是将我们的函数模板的定义和友元声明均放在我们的类模板中,而因为在类内定义所以就会被看做内联函数,在所有成员函数定义之后被定义。
例如:
template<typename T>
class A
{
public:
A()
:_a(0)
{}
template<class T1>
friend void fun(const A<T1> a)
{
cout<<a._a<<endl;
}
private:
T _a;
};
但是想上述的第三种情况就不适用于这种方法了。
2.开放型
我们前面介绍三类友元的声明中的例子就是我们的开放型,也就是将函数模板的定义放在我们的类模板外。
尝试修改一下
参考链接:http://www.cppblog.com/unixfy/archive/2011/05/27/147448.html
http://blog.sina.com.cn/s/blog_7c2c21230100svc3.html