发表一点自己对 《C++ Primer 5th》模板那块的理解, 欢迎指正
一对一友好关系
在类模板与另一个模板(模板类或模板函数)间建立对应实例及其友好关系,为了在类模板中引用另一个类模板或函数的一个特定实例,必须先声明另一个模板:
方便理解和叙述,将含友元的类称为主类,将要做友元类的模板类称为客类
//为了在类里面引用 BlobPtr<T> 和 poerator==<T> 现在类之前声明
template <typename> class BlobPtr;
template <typename> class Blob;
template <typename T>
bool operator==(const Blob<T>&, const Blob<T>&);
template <typename T>
class Blob{
friend class BlobPtr<T>; //客类
friend bool operator==<T>; //主类
(const Blob<T>&, const Blob<T>&);
....
};
//模板类友元运算符重载函数定义:
template <typename T>
bool operator==<T>(const Blob<T>& lhs, const Blob<T>& rhs)
{
...
}
也就是说只有 BlobPtr<int> operator==<int>
才是 Blob<int>
的友元.而 BlobPtr<std::string>
不是 Blob<int>
的友元
通用和特定的模板友好关系
- 将客类的每个实例都声明为主类的友元
- 将客类的特定实例声明为主类的友元
对于第一种情况不需要在模板类前置声明
template <typename T>
class C1
{
//C1每个实例将拥有相同实例化的Pal声明为友元
friend class Pal<T>;
//Pal2所有实例都是 C1 的每个实例的友元 不需前置声明
template <typename X> friend class Pal2;
};
Pal2<int>, Pal2<std::string>
都是 C1<int>
或者 C1<std::string>
的友元
第二种情况需要前置声明
template <typename T> class Pal;
class C2 //C2不是模板类
{
//C2每个实例将 用C1类型实例化的Pal 声明为友元
friend class Pal<C1>;
};
总结:
- 如果想将客类的所有实例作为主类每个实例的友元,那么不需要再主类前声明客类模板,也不需要声明友元时加,并且在主类内部声明客类为主类友元之前要加上客类的模板参数列表,而且还不能和主类参数名一样,如:
template<typename T> class 主类
{
template <typename X> //模板参数和主类不一样
friend 客类;
};
- 如果只想将拥有和主类相同实例的客类或模板函数作为主类的友元,那就先在主类前声明客类(带模板参数列表template), 然后在主类中声明客类
friend
(带模板参数,不带template)并且模板参数<T>
需要和主类的参数名相同。
template<typename > class 客类;
template<typename T> class 主类
{
friend 客类<T>; //模板参数和主类一致
};