前言

友元是一种定义在类外部的普通函数或类,但它需要在类体内进行说明,为了与该类的成员函数加以区别,在说明时前面加以关键字friend。友元不是成员函数,但是它可以访问类中的私有成员。


正文

1
2
3
4
5
#pragma once
class Box{
int hp;
int mp;
};

老样子写个类。


友元函数

当类中成员没有声明是public的时候,即便你用类当参数模板,也是无法调用的。

1
2
3
void test(Box &b){
b.hp = 100;
}

结果就是无法访问。

而按照友元的逻辑,需要告诉这个类你有一个朋友,friend void test(Box &b);
这样你的朋友才能了解你的相关事物。

然后就不会报错了。

说明友元访问私有变量是没啥问题,还能访问私有函数

1
2
3
4
//Box.h
int getHp(){
return this->hp;
}
1
2
3
4
5
//main.cpp
void test(Box &b){
b.hp = 100;
std::cout << b.getHp();
}

结果都没问题,也就是说友元函数可以访问类的私有成员。


还有就是类和函数啥的因为都是顺序执行,所以当一个类中调用另一个类的时候,这个类如果在后面才定义,编译器也是会报错的。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
#pragma once
class Box{
int hp;
int mp;

int getHp(){
return this->hp;
}

friend void test(Box &b);
friend void getHP(Box &b1, Hz &h1);
};

class Hz{
int hp;
};

就拿这种情况,我们getHP参数调用Box本身和Hz,但是Hz在后面定义.

这个时候就要学习函数,将声明放置于顶部,定义放在后面。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
#pragma once
class Hz; //声明

class Box{
int hp;
int mp;

int getHp(){
return this->hp;
}

friend void test(Box &b);
friend void getHP(Box &b1, Hz &h1);
};

class Hz{
int hp;
};

这样就解决这个小毛病。


友元类

写法差不多,friend class 类名
作用就是可以创建这个类的对象,可以访问类中的私有成员

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
#pragma once

class Hz;
class Box{
int hp;
int mp;

int getHp(){
return this->hp;
}


friend void test(Box &b);
friend void getHP(Box &b1, Hz &h1);

friend class Hz; //声明友元类Hz
};

class Hz{
int hp;
int mp;

void getMp(){
Box b1;
std::cout << b1.getHp() << std::endl;
}
};

这里还涉及到人际关系,就是你拿它当朋友,但是它不一定拿你当朋友。
具体表现在类中,就是虽然你声明了一个友元类,它可以访问你了,但是你不能访问它。

1
2
3
4
void getMp(){
Hz h1;
h1. //一个成员都看不到。
}

还挺勾心斗角的。。。
这个解决方法在于双方都要声明,双认证一样。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
#pragma once
#include<iostream>

class Hz;
class Box{
int hp;
int mp;

int getHp(){
return this->hp;
}

void getMp(){
Hz h1;
h1.mp;
}

friend void test(Box &b);
friend void getHP(Box &b1, Hz &h1);

friend class Hz; //声明
};

class Hz{
int hp;
int mp;

void getMp(){
Box b1;
std::cout << b1.getHp() << std::endl;
}

friend class Box; //声明
};

但是显然这种逻辑关系很麻烦。


结语

但是要注意朋友的朋友不一定就是朋友
即A,有朋友B和C,但是B和C之间不一定就是朋友,因为友元不具备关系传递。

而且友元本质上会破坏类的封装性,所以只有万不得已的情况下才会选择友元,友元这种不是一种平等的关系。