C++Primer Plus 第十四章代码重用:模板类和友元14.4.9
提示:这里可以添加系列文章的所有文章的目录,目录需要自己手动添加
例如:模板类和友元14.4.9
提示:写完文章后,目录可以自动生成,如何生成可参考右边的帮助文档
模板类和友元14.4.9
模板类声明也可以有友元。模板的友元分3类:
非模板友元;约束(bound)模板友元,即友元的类型取决于类被实例化时的类型;非约束(unbound)模板友元,即友元的所有具体化都是类的每一个具体化的友元。
下面分别介绍它们。
1.模板类的非模板友元函数
在模板类中将一个常规函数声明为友元:
template <class T>
class HasFriend
public:
friend void counts();//friend to all HasFriend instantiations
...
上述声明使 counts()函数成为模板所有实例化的友元。例如,它将是类 hasFriend和 HasFriend的友元。
counts()函数不是通过对象调用的(它是友元,不是成员函数),也没有对象参数,那么它如何访问HasFriend对象呢?有很多种可能性。它可以访问全局对象;可以使用全局指针访问非全局对象;可以创建自己的对象:可以访问独立于对象的模板类的静态数据成员。
假设要为友元函数提供模板类参数,可以如下所示来进行友元声明吗?
friend void report(HasFriend &);// possible?
答案是不可以。原因是不存在 HasFriend 这样的对象,而只有特定的具体化,如 HasFriend。要提供模板类参数,必须指明具体化。例如,可以这样做:
template <class T>
class HasFriend
friend void report(HasFriend<T>&);//bound template friend
为理解上述代码的功能,想想声明一个特定类型的对象时,将生成的具体化:
HasFriend<int> hf;
编译器将用int替代模板参数T,因此友元声明的格式如下:
Class HasFriend<int>
friend void report(HasFriend<int>&);// bound template friend
也就是说,带 HasFriend参数的 repor( )将成为 HasFriend类的友元。同样,带 HasFriend参数的report( )将是report( )的一个重载版本–它是 Hasfriend类的友元。注意,repor()本身并不是模板函数,而只是使用一个模板作参数。这意味着必须为要使用的友元定义显式具体化:
void report(HasFriend<short>&)(...);//explicit specialization for shortvoid report(HasFriend<int>&)(...);//explicit specialization for int
程序清单 14.22 说明了上面几点。HasFriend 模板有一个静态成员 ct。这意味着这个类的每一个特定的具体化都将有自己的静态成员。count()方法是所有 HasFriend 具体化的友元,它报告两个特定的具体化(HasFriend和 HasFriend)的 ct的值。该程序还提供两个repon()函数,它们分别是某个特定 HasFriend 具体化的友元。
程序清单14.22 frnd2tmp.cpp
// frnd2tmp.cpp -- template class with non-template friends
#include <iostream>
using std::cout;
using std::endl;
template <typename T>
class HasFriend
{
private:
T item;
static int ct;
public:
HasFriend(const T & i) : item(i) {ct++;}
~HasFriend() {ct--; }
friend void counts();
friend void reports(HasFriend<T> &); // template parameter
};
// each specialization has its own static data member
template <typename T>
int HasFriend<T>::ct = 0;
// non-template friend to all HasFriend<T> classes
void counts()
{
cout << "int count: " << HasFriend<int>::ct << "; ";
cout << "double count: " << HasFriend<double>::ct << endl;
}
// non-template friend to the HasFriend<int> class
void reports(HasFriend<int> & hf)
{
cout <<"HasFriend<int>: " << hf.item << endl;
}
// non-template friend to the HasFriend<double> class
void reports(HasFriend<double> & hf)
{
cout <<"HasFriend<double>: " << hf.item << endl;
}
int main()
{
cout << "No objects declared: ";
counts();
HasFriend<int> hfi1(10);
cout << "After hfi1 declared: ";
counts();
HasFriend<int> hfi2(20);
cout << "After hfi2 declared: ";
counts();
HasFriend<double> hfdb(10.5);
cout << "After hfdb declared: ";
counts();
reports(hfi1);
reports(hfi2);
reports(hfdb);
// std::cin.get();
return 0;
}