模板类的友元函数有三类:
非模板友元
:友元函数不是模板函数
,而是利用模板类参数生成的函数,只能在类内实现。约束模板友元
:模板类实例化时,每个实例化的类对应一个友元函数。- 非约束模板友元:模板类实例化时,如果实例化了n个类,也会实例化n个友元函数,每个实例化的类都拥有n个友元函数。(实际开发Y一般不用)
示例代码:
#include <iostream>
using namespace std;
template <class T1, class T2>
class AA {
private:
T1 m_x;
T2 m_y;
public:
// friend void show();
AA(const T1 x, const T2 y): m_x(x), m_y(y) {}
};
AA<int, string> a(123, "哈哈哈");
void show() {
cout << "x = " << a.m_x << ", y = " << a.m_y << endl;
}
int main() {
show();
return 0;
}
上面这段示例代码,编译会报错,原因在于:不可以在类的外部访问类的私有成员。把代码中的注释:// friend void show();
取消,把全局函数show()
设置为模板类AA
的友元函数
(如果忘记友元知识点,点击查看),即可成功编译运行,结果如下:
x = 123, y = 哈哈哈
这种为模板类设置友元函数的方法,在语法上没有任何问题。但是,要用模板类创建全局对象:AA<int, string> a(123, "哈哈哈");
这种写法略显笨拙。
#include <iostream>
using namespace std;
template <class T1, class T2>
class AA {
private:
T1 m_x;
T2 m_y;
public:
friend void show(const AA<int, string>& a);
AA(const T1 x, const T2 y): m_x(x), m_y(y) {}
};
void show(const AA<int, string>& a) {
cout << "x = " << a.m_x << ", y = " << a.m_y << endl;
}
int main() {
AA<int, string> a(666, "哈哈哈");
show(a);
return 0;
}
运行结果如下:
x = 666, y = 哈哈哈
现在模板类AA
再创建一个对象b
,数据类型改为char
。AA<char, string> b('x', "嘿嘿嘿");
用当前的代码肯定会报错,因为数据类型不匹配。此时,重载一个show()
函数即可。代码如下:
#include <iostream>
using namespace std;
template <class T1, class T2>
class AA {
private:
T1 m_x;
T2 m_y;
public:
friend void show(const AA<int, string>& a);
friend void show(const AA<char, string>& a);
AA(const T1 x, const T2 y): m_x(x), m_y(y) {}
};
void show(const AA<int, string>& a) {
cout << "x = " << a.m_x << ", y = " << a.m_y << endl;
}
void show(const AA<char, string>& a) {
cout << "x = " << a.m_x << ", y = " << a.m_y << endl;
}
int main() {
AA<int, string> a(666, "哈哈哈");
show(a);
AA<char, string> b('x', "嘿嘿嘿");
show(b);
return 0;
}
运行结果如下:
x = 666, y = 哈哈哈
x = x, y = 嘿嘿嘿
目前这种方式可以解决问题,但是要为模板类的每一个实例化版本都准备一个友元函数。
非模板友元
C++提供了一种解决方案:利用模板类的参数,自动生成友元函数。代码如下:
#include <iostream>
using namespace std;
template <class T1, class T2>
class AA {
private:
T1 m_x;
T2 m_y;
public:
AA(const T1 x, const T2 y): m_x(x), m_y(y) {}
friend void show(const AA<T1, T2>& a) {
cout << "x = " << a.m_x << ", y = " << a.m_y << endl;
}
};
int main() {
AA<int, string> a(555, "哈哈哈");
show(a);
AA<char, string> b('w', "嘿嘿嘿");
show(b);
return 0;
}
其实就是把show()
函数的定义放到模板类内部,前面加一个friend
关键字修饰,再把参数类型换成通用参数类型T1
和T2
。运行结果如下:
x = 555, y = 哈哈哈
x = w, y = 嘿嘿嘿
注意,虽然编译器利用模板参数帮助我们生成了友元函数,但是friend void show(const AA<T1, T2>& a)
不是模板函数。可以通过编译下面这段代码,证明这一点:
#include <iostream>
using namespace std;
template <class T1, class T2>
class AA {
private:
T1 m_x;
T2 m_y;
public:
AA(const T1 x, const T2 y): m_x(x), m_y(y) {}
friend void show(const AA<T1, T2>& a) {
cout << "x = " << a.m_x << ", y = " << a.m_y << endl;
}
friend void show(const AA<int, string>& a);
friend void show(const AA<char, string>& a);
};
void show(const AA<int, string>& a) {
cout << "x = " << a.m_x << ", y = " << a.m_y << endl;
}
void show(const AA<char, string>& a) {
cout << "x = " << a.m_x << ", y = " << a.m_y << endl;
}
int main() {
AA<int, string> a(555, "哈哈哈");
show(a);
AA<char, string> b('w', "嘿嘿嘿");
show(b);
return 0;
}
此段代码编译会报错,编译器会告诉你出现了重定义。原因就是:friend void show(const AA<T1, T2>& a)
并不是函数模板。这对写程序有什么影响?如果想为某种数据创建特别版本的友元函数(具体化),这种方法是做不到的。还有,用这种方法生成的友元函数只能用于这个模板类,不能用于其它模板类。
约束模板友元
这种友元函数模板是模板函数,可用于多个模板类
,可以具体化
。
为模板类AA
设置友元函数的步骤如下:
- 在模板类的定义前面,声明友元函数模板。目的是为了让模板类AA知道友元函数模板的存在。
- 在模板类中,再次声明友元函数模板。目的是为了让编译器知道需要实例化的友元函数模板。
- 友元函数模板的定义。
示例代码如下:
#include <iostream>
using namespace std;
// 1.在模板类的定义前面,声明友元函数模板。目的是为了让模板类AA知道友元函数模板的存在。
template <typename T>
void show(T& a);
template <class T1, class T2>
class AA {
friend void show<> (AA<T1, T2>& a); // 2.在模板类中,再次声明友元函数模板。
// 目的是为了让编译器知道需要实例化的友元函数模板。
T1 m_x;
T2 m_y;
public:
AA(const T1 x, const T2 y): m_x(x), m_y(y) {}
};
template <typename T> // 3.友元函数模板的定义。
void show(T& a) {
cout << "通用版本 x = " << a.m_x << ", y = " << a.m_y << endl;
}
// 友元函数是函数模板,可以有具体化版本。
template <> // 友元函数模板的具体化
void show(AA<int, string>& a) {
cout << "具体化版本 x = " << a.m_x << ", y = " << a.m_y << endl;
}
int main() {
AA<int, string> a(999, "hi~");
show(a);
AA<char, string> b('q', "hello");
show(b);
return 0;
}
运行结果如下:
具体化版本 x = 999, y = hi~
通用版本 x = q, y = hello
非约束模板友元
示例代码如下:
template <class T1, class T2>
class AA {
template <typename T> friend void show(T& a);
T1 m_x;
T2 m_y;
public:
AA(const T1 x, const T2 y): m_x(x), m_y(y) {}
};
template <typename T> void show(T& a) {
cout << "通用版本 x = " << a.m_x << ", y = " << a.m_y << endl;
}
template <> void show(AA<int, string> &a) {
cout << "具体版本 x = " << a.m_x << ", y = " << a.m_y << endl;
}
int main() {
AA<int, string> a(000, "hi~");
show(a);
AA<char, string> b('v', "hello");
show(b);
return 0;
}
运行结果如下:
具体版本 x = 0, y = hi~
通用版本 x = v, y = hello
感谢浏览,一起学习!