类模板和友元简介:
当一个类被包含一个友元声明的时候,类和友元是否是模板是相互无关的。
如果一个类模板包含一个非模板友元,则友元被授权可以访问所有模板实例;
如果友元自身是模板,类可以授权给所有友元模板实例,也可以之授权给特定实例。
一、友元和类模板的一对一关系:
类模板与另一个(类或函数)模板间友好关系的最常见的形式是:
建立对应实例及其友元间的友好关系。
例如:
//前置声明,在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;
friend bool operator==<T>(const Blob<T>&, const Blob<T>&);
//operator==是针对某个实例化类型的,所以要也加一个<T>
//其他成员定义略。
}
首先将Blob、BlobPtr和operation== 声明为模板。这些声明是operation==函数的参数声明以及Blob中的友元声明所需要的。如果要把
友元的声明用Blob的模板形参作为他们自己的模板实参,因此,友元关系被限定在用相同类型实例化的Blob和BlobPtr。
实例化一下:
Blob<char> ca; //BlobPtr<char>和operator==<char>都是ca的友元
Blob<int> ia; //BlobPtr<int>和operator==<int>都是ia的友元
因此BlobPtr<char>
的成员可以访问ca(或任何其他Blob<char>
对象)的非public部分,但ca对ia(或其他任何Blob<int>
对象)或Blob的任何其他实例都没有特殊的访问权限。
二、通用和特定的模板的友好关系:
一个类可以将另一个类模板的每个实例都声明为自己的友元(即通用模板),或者限定特定的实例为友元(即特定模板):
//前置声明,在将模板的一个特定实例声明为友元时要用到
template<typename T> class Pal;
class C{//C为一个普通的非模板类
friend class Pal<C>;//pal本身是类模板,用C实例化后,pal的类型是C,
//C类型的pal又成为了非模板类C的友元
//Pal2的所有实例都是C的友元;这种情况无须前置声明
temlate<typename T> friend class Pal2;
};
比较来看,前者是限定了只有实例化为C类的Pal才是非模板类C的友元;
而对于Pal2来说,任何类型,包括int,double,string,C等等都是非模板类C的友元。
因此两者模板的定义方式也不一样,前者需要先在类外定义模板,因为类内就要限定实例化了,所以要提前准备好。
而后者则不然,为了让所有实例都成为友元,友元声明中必须使用域类模板本身不同的模板参数。
三、令模板自己的参数类型成为友元:
在新标准中,我们可以将模板类型参数声明为友元:
template<typename T>class B{
friend T; //将访问权限授予用来实例化Bar的类型
//......
};
此处我们将用来实例化Bar的类型声明为友元。因此,对于某个类型名F,F将成为B<F>
的友元,S成为B<S>
的友元,以此类推。
小结:
主要阐述了友元函数在类内的声明,其他模板类的友元和自身友元的定义