一、友元函数的使用
如果一个函数在类外想要访问类内
p
r
i
v
a
t
e
private
private定义的成员,就需要将其声明为友元函数。
如下的代码无法访问类内
p
r
i
v
a
t
e
private
private成员:
class Men{
friend void func(int,int);
private:
void funcmen() const {
std::cout<<"funcmen调用了!\n";
}
};
void func(int val1, int val2){
Men mymen;
mymen.funcmen(); //访问失败
}
我们需要加上加上对其的友元函数声明:
f
r
i
e
n
d
v
o
i
d
f
u
n
c
(
i
n
t
,
i
n
t
)
;
friend \ void \ func(int,int);
friend void func(int,int);
f r i e n d v o i d friend \ void friend void和 v o i d f r i e n d void \ friend void friend两种写法都行。
二、函数模板的某个实例成为友元函数
如果使用函数模板,我们可以选择让它的其中一个实例化版本成为友元函数,而其他实例化版本不能访问。
如下,我们指定
f
u
n
c
<
i
n
t
,
i
n
t
>
func<int,int>
func<int,int>类型作为特定的友元函数类型,所以只有函数模板为这个类型,才能成为友元,其他类型将被拒绝访问:
//前项声明
template<typename U,typename V>
void func(U,V);
class Men{
//让func的一个实例成为友元函数
void friend func<int,int>(int,int);
private:
void funcmen() const {
std::cout<<"funcmen调用了!\n";
}
};
template<typename U,typename V>
void func(U val1, V val2){
Men mymen;
mymen.funcmen();
}
void Test1(){
//特定实例能访问
//三种都行
func<int,int>(1,2);
func<>(1,2);
func(1,2);
//不是特定实例访问失败
func<int,long>(1,2LL);
}
同样的,如果 M e n Men Men是一个类模板,我们也可以相应的使用友元函数来让其特定的实例化的类成为友元函数,如下:
//让函数模板成为某个类模板的友元函数
template<typename U, typename V>
void func2(U, V);
template<typename T>
class Men2 {
void friend func2<double, double>(double, double);
//把func3这个函数模板作为友元函数模板
template<typename U, typename V>
void friend func3(U, V);
//friend void 和 void friend都可以
private:
T data;
void funcmen2() {
std::cout << "funcmen2调用了!\n";
}
};
注意也是要前向声明以下函数模板。
调用如下:
void Test2() {
func2<double, double>(1.0, 1.0);
func2<>(1.0, 1.0);
func2(1.0, 1.0);
}
三、友元模板
我们让函数模板所有的类型都成为另一个类的友元函数,那么我们可以称其为友元模板。
实现代码如下,我们在
M
e
n
2
Men2
Men2中加入了一个
f
u
n
c
3
func3
func3的友元类:
//友元函数模板
template<typename T>
class Men2 {
//把func3这个函数模板作为友元函数模板
template<typename U, typename V>
void friend func3(U, V);
//friend void 和 void friend都可以
private:
T data;
void funcmen2() {
std::cout << "funcmen2调用了!\n";
}
};
template<typename U, typename V>
void func3(U, V) {
Men2<int> men;
men.funcmen2();
}
void Test3() {
func3<int, double>(1, 1.0);
func3<int, char>(1, '1');
}
此时不需要前向声明了。
注意的是,对于泛化版本中有的友元模板(友元函数模板),特化后也是存在的。这里我们对 M e n 2 Men2 Men2类中的友元模板 f u n c 3 func3 func3进行全特化:
//函数模板的全特化也会存在友元函数
template<>
void func3(float val1, double val2) {
Men2<int>men;
men.funcmen2();
}
void Test4() {
func3<float, double>(1.0f, 1.0);
func3<>(1.0f, 1.0);
}
仍然是能够成功访问到 M e n 2 Men2 Men2中的 p r i v a t e private private成员的。
三、在类模板中定义友元类
这是一个特殊的语法,我们可以在类内直接定义(不是声明)一个友元类,然后在类外可以直接调用它。
注意下面代码,我们需要传入一个同类型的变量
M
e
n
3
Men3
Men3,然后使用它调用
M
e
n
3
Men3
Men3类内的成员:
//在类模板中直接定义友元类
template<typename T>
class Men3 {
//直接在类内定义友元函数
friend void func4(Men3<T>& men) { //传入自身相同的类
men.funcmen4();
}
private:
void funcmen4() {
std::cout << "funcmen4调用了!\n";
}
};
void Test5() {
Men3<double>mymen;
func4(mymen);
Men3<int>mymen2;
func4(mymen2);
}
值得注意的是,这样写的友元函数应该被看做是全局函数,不受类模板的限制。
使用
d
u
m
p
b
i
n
dumpbin
dumpbin工具可以发现,在编译期间就已经生成了相应的函数(
m
a
i
n
main
main函数中没有调用):