C++ Primer Plus 书之--C++ 模板类深究2--模板类和友元

模板类和友元

模板类声明也可以有友元, 模板的友元分为3类:

1.非模板友元

2.约束模板友元, 即友元的类型取决于类被实例化时的类型

3.非约束模板友元, 即友元的所有具体化都是类的每一个具体化的友元.

1.模板类的非模板友元函数:

在模板类中将一个常规函数声明为友元:

template 
class HasFriend
{
public:
	friend void counts();
};

上述声明使counts()函数称为模板所有实例化的友元. 例如: 它将是类HasFriend和HasFriend的友元.

counts()函数不是通过对象调用的(它是友元, 不是成员函数)

假设要为友元函数提供模板类参数, 看如下的声明:

friend void report(HasFriend &);

这个声明是错误的, 因为不存在HasFriend这样的对象, 而只有特定的具体化如:HasFriend, HasFriend, 要提供模板类参数, 必须知名具体化, 例如可以这么写:

template
class HasFriend
{
	friend void report(HasFriend &);
};

注意report()本身并不是模板函数, 而只是使用了一个模板作为参数

来看一个完整的例子:

// 模板类的非模板友元函数例子
// frnd2tmp.cpp
#include 
using std::cout;
using std::endl;

template
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 &);
};

template
int HasFriend::ct = 0;

// 非模板友元函数, 所有HasFriend都有该函数
void counts()
{
	cout << "int count: " << HasFriend::ct << "; ";
	cout << "double count: " << HasFriend::ct << endl;
}

// 非模板友元函数, 对应于HasFriend class
void reports(HasFriend & hf)
{
	cout << "HasFriend: " << hf.item << endl;
}

// 非模板友元函数, 对应于HasFriend class
void reports(HasFriend & hf)
{
	cout << "HasFriend: " << hf.item << endl;
}

int main()
{
	cout << "No objects declared: ";
	counts();
	HasFriend hfi1(10);
	cout << "After hfi1 declared: ";
	counts();
	HasFriend hfi2(20);
	cout << "After hfi2 declared: ";
	counts();
	HasFriend hfi3(10.1);
	cout << "After hfi3 declared: ";
	counts();
	reports(hfi1);
	reports(hfi2);
	reports(hfi3);
	return 0;
}

程序运行结果为:

C++ Primer Plus 书之--C++ 模板类深究2--模板类和友元_第1张图片

需要注意的地方都写注释了

 

2.模板类的约束模板友元函数

在上面这个示例基础上加以修改, 要使类的每一个具体化都获得与友元匹配的具体化, 需要以下三步:

1.在类定义的前面声明每个模板函数:

template void counts();
template void report(T &);

2.在函数中再次将模板声明为友元. 这些语句根据类模板参数的类型声明具体化:

template 
class HasFriendT
{
...
	friend void counts();
	friend void report<>(HasFriendT &);
};

声明中的<>指出这是模板具体化, 对于report(), <>可以为空, 因为可以从函数参数推断出如下模板类型参数:

HasFriendT

然而也可以使用:

friend void report>(HasFriendT &);

但counts()函数没有参数, 因此必须使用模板参数语法来指明其具体化.

3.为友元提供模板定义.

下面看一个完整的例子:

// 模板类的约束模板友元函数
// tmp2tmp.cpp
#include 
using std::cout;
using std::endl;

// 在类定义前面要声明每个模板函数原型
template void counts();
template void report(T &);

// 模板类
template
class HasFriendT
{
private:
	TT item;
	// 静态成员, 每个类的具体化都会有自己的静态成员
	static int ct;
public:
	HasFriendT(const TT & i):item(i){ct++;}
	~HasFriendT() {ct--;}
	friend void counts();
	friend void report<>(HasFriendT &);
};


template
// 记得这里一定要写成HasFriendT, 不能只写HasFriendT, 因为不存在HasFriendT这个类
int HasFriendT::ct = 0;

// 模板友元函数定义
template 
void counts()
{
	cout << "template size: " << sizeof(HasFriendT) << ";";
	cout << "template counts() : " << HasFriendT::ct << endl;
}

template
void report(T & hf)
{
	cout << hf.item << endl;
}

int main()
{
	counts();
	HasFriendT hf1(10);
	HasFriendT hf2(20);
	HasFriendT hf3(10.1);
	report(hf1);
	report(hf2);
	report(hf3);
	cout << "counts output: " << endl;
	counts();
	cout << "counts() output: " <();
	return 0;
}

程序运行结果为:

C++ Primer Plus 书之--C++ 模板类深究2--模板类和友元_第2张图片

3.模板类的非约束模板友元函数

约束模板友元函数是在类外面声明的模板的具体化, int类具体化获得int函数具体化, 以此类推. 通过在类内部声明模板, 可以创建非约束友元函数, 即每个函数具体化都是每个类具体化的友元. 对于非约束友元, 友元模板类型参数和模板类类型参数是不同的:

template
class ManyFriend
{
	template friend void show2(C &, D &);
}

来看一个demo:

// 非约束模板友元
// manyfrnd.cpp
#include 
using std::cout;
using std::endl;

template
class ManyFriend
{
private:
	T item;
public:
	ManyFriend(const T & i): item(i){}
	// 非约束模板友元
	template friend void show2(C &, D &);
};

template void show2(C & c, D & d)
{
	cout << c.item << ", " << d.item << endl;
}

int main()
{
	ManyFriend hf1(10);
	ManyFriend hf2(20);
	ManyFriend hf3(10.1);
	cout << "hf1, hf2: ";
	show2(hf1, hf2);
	cout << "hf3, hf2: ";
	show2(hf3, hf2);
	return 0;
}

程序运行结果为:

 

模板别名

可以使用typedef为模板具体化指定别名:

格式如下:

template using arrtype = std::array;

这将arrtype定义为一个模板别名, 可使用其来指定类型例如:

// 实际为std::array这种类型
arrtype gallons;

// 实际为std::array这种类型
arrtype days;

// 实际为std::array这种类型
arrtype months;

C++允许将语法using = 用于非模板, 用于模板时, 这种语法与常规typedef等价

 

你可能感兴趣的:(C++)