当一个类包含一个友元声明时,类与友元各自是否是模板是相互无关的。如果一个类模板包含一个非模板友元,则友元被授权可以访问所有模板实例。如果友元自身是模板,类可以授权给所有友元模板实例,也可以只授权给特定实例。
1. 一对一友好关系
类模板与另一个(类或函数)模板间友好关系的最常见形式是建立对应实例及其友元间的友好关系。例如,我们的 Blob 类应该讲 BlobPtr 类和一个模板版本的 Blob 相等运算符定义为友元。
为了引用(类或函数) 模板的一个特定实例,我们必须首先声明模板自身。一个模板声明包括模板参数列表:
//前置声明,在 Blob 中声明友元所需要的 template <typename> class BlobPtr; template <typename> class Blob; //运算符==中的参数所需要的 template <typename T> bool operator == (const Blob<T>&, const Blob<T>&); template <typename T> class Blob { //每个Blob实例将访问权限授予用相同类型实例化的BlobPtr和相等运算符 friend class BlobPtr<T>; friend bool operator ==<T> (const Blob<T>&, const Blob<T>&); };
我们首先将Blob、BlobPtr和Operator== 声明为模板。这些声明时 operator==函数的参数声明以及 Blob 中的友元声明所需要的。
友元的声明用 Blob 的模板形参作为它们自己的模板形参。因此,友好关系被限定在用相同类型实例化的 Blob 与 BlobPtr 相等运算符之间:
Blob<char> ca; //BlobPtr<char>和 operator==<char>都是本对象的友元 Blob<int> ia; //BlobPtr<int>和 operator==<int>都是本对象的友元
BlobPtr<char>的成员可以访问 ca (或任何其他 Blob<char>对象)的非 Public 部分,但 ca 对 ia (或任何其他 Blob<int> 对象) 或 Blob 的任何其他实例都没有特殊访问权。
2. 通用和特定的模板友好声明
//前置声明,在将模板的一个特定实例声明为友元时要用到 template<typename T> class Pal; class C { //C 是一个普通的非模板类 friend class Pal<C>; //用类C 实例化的Pal是C 的一个友元 template <typename T> friend class Pal2; //Pal2 的所有实例都是C 的友元;这种情况无须前置声明 }; template <typename T> class C2 {//C2 本身是一个模板类 // C2 的每个实例将相同实例化的 Pal 声明为友元 friend class Pal<T>; // Pal 的模板声明必须在作用域内 // Pal2 的所有实例都是 C2 的每个实例的友元,不需要前置声明 template <typename X> friend class Pal2; // Pal3 是一个模板类,它是 C2 所有实例的友元 friend class Pal3; //不需要 Pal3 的前置声明 };
为了让所有实例成为友元,友元声明中必须使用与模板本身不同的模板参数。