总结起来一共有这么几条:
- 如果一个类模板包含一个非模板友元,则友元被授权可以访问所有类模板实例。
- 如果一个非模板类包含一个模板友元,则所有友元实例被授权可以访问该类。
- 如果一个类模板与友元模板拥有相同的类型参数,则类与友元为一对一的友好关系。
- 如果一个类模板与友元模板拥有不同的类型参数,则类的每一个实例授权给所有模板实例。
一对一友好关系
类模板与另一个(类或函数)模板间友好关系的最常见形式是建立对应实例及其友元间的友好关系。例如,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==(const Blob<T>&, const Blob<T>&);
};
友元的声明用Blob模板形参作为他们自己的模板实参,因此,友元关系被限定在用相同类型实例化的Blob与BlobPtr相等运算符之间。
Blob<char> ca; //BlobPtr<char>和operator==<char>都是本对象的友元
Blob<int> ia; //BlobPtr<int>和operator==<int>都是本对象的友元
普通类与友元模板
class C {
friend class Pal<C>; //用类C实例化的Pal是C的一个友元
//Pal1的所有实例都是C的友元,且无须前置声明
template <typename T> friend class Pal1;
};
类模板与普通友元
template <typename T>
class C2 {
//Pal2是一个非模板类,它是C2所有实例的友元,不需要前置声明
friend class Pal2;
};
类模板与友元模板(多对多关系)
template <typename T>
class C2 {
//Pal3的所有实例都是C2的每个实例的友元,同样不需要前置声明
template <typename X> friend class Pal3;
};
令模板自己的类型参数成为友元
在新标准中,我们可以将模板类型参数声明为友元:
template <typename Type> class Bar {
friend Type; //将访问权限授予用来实例化Bar的类型
};
此处我们将用来实例化Bar的类型声明为友元。因此,对于某个类型名Foo,Foo将成Bar<Foo>的友元。