一.友元函数
友元函数可以是普通函数或者类成员函数。
先看普通函数声明为友元函数:
如下所示:
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
|
#include <iostream> #include <cmath> using namespace std; class Point { //普通函数声明为类的友元函数 friend double TwoPointsDistant( const Point& pnt1, const Point& pnt2); public : Point( double x=0, double y=0) :_x(x), _y(y) {} double getPointXAxis() const { return this ->_x; } double getPointYAxis() const { return this ->_y; } private : double _x; double _y; }; //计算两点的距离 double TwoPointsDistant( const Point& pnt1, const Point& pnt2) { return sqrt ( pow ((pnt1._x - pnt2._x), 2) + pow ((pnt1._y - pnt2._y), 2) ); } int main() { Point point1(1.1,2.2); Point point2(3.3, 4.4); cout << TwoPointsDistant(point1, point2) << endl; system ( "pause" ); return 0; } |
这里说明一点:TwoPointsDistant()函数必须在Point类的定义下面
,至于原因,很简单,你若放在Point上面,Point的数据成员_x和_y都没定义呢,你用个锤子。
再看类成员函数声明为友元函数:
还以上面的类为例,现在加一个_PointMove_类,它有一个成员函数_PointAxisAddOne,_作用是将点的坐标都加1。如下:
1
2
3
4
5
|
class PointMove { public : void PointAxisAddOne(Point& pnt); }; |
这里就出现了一个问题:_Point_和_PointMove_哪个放在前面?先给出答案,应该把_PointMove_放在前面,并且是必须的,如下:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
|
class Point; //前向声明Point class PointMove { public : void PointAxisAddOne(Point& pnt); }; class Point { //普通函数声明为类的友元函数 friend double TwoPointsDistant( const Point& pnt1, const Point& pnt2); //类成员函数声明为友元 friend void PointMove::PointAxisAddOne(Point& pnt); /*这里同前*/ }; //类成员函数的定义 void PointMove::PointAxisAddOne(Point& pnt) { pnt._x = pnt._x + 1; pnt._y = pnt._y + 1; } |
这里注意,对于类的成员函数,声明为其他类的友元函数时需要加上类的作用域,即指出该函数属于哪个类。如上面的_PointMove::_。
同时,需要说明的是,PointAxisAddOne()函数的定义是必须放在Point类定义后面的,这和普通函数的道理是一样的。
最后说明
1.一个函数Func被声明为类A的友元函数,那么是不能直接使用this指针来访问类A的数据成员的(当然,若Func是类B的成员函数,它可以通过this访问类B的数据成员),这和成员函数不同。
2.一个函数Func为什么要声明为某个类A的友元,就是因为函数的参数类型为类A类型,我想访问这个类对象的数据成员
,所以被声明为类A的友元函数的参数类型必定为类A,如friend Func(A& obj);
二.友元类
若是将一个类C都声明为另一个类A的友元类,则类C中的成员函数均可访问类A中的私有数据成员。如下:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
|
class Point { //友元类 friend class PointInfo; ... } class PointInfo { public : //打印点所处象限 void PrintQuadrant( const Point& pnt) const { if (pnt._x > 0 && pnt._y > 0) cout << "点" << "(" << pnt._x << "," << pnt._y<< ")" << "处于第一象限" << endl; } }; |
当然,你也可以把_PointInfo_写在_Point_前,只是函数_PrintQuadrant()_的定义就不能在类内实现了,只能在_Point_后实现,原因和前面一样,不再赘述。
三.完整示例:
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
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
|
#include <iostream> #include <cmath> using namespace std; class Point; class PointMove { public : void PointAxisAddOne(Point& pnt); }; class PointInfo { public : //打印点所处象限 void PrintQuadrant( const Point& pnt) const ; }; class Point { friend class PointInfo; friend double TwoPointsDistant( const Point& pnt1, const Point& pnt2); friend void PointMove::PointAxisAddOne(Point& pnt); public : Point( double x=0, double y=0) :_x(x), _y(y) {} double getPointXAxis() const { return this ->_x; } double getPointYAxis() const { return this ->_y; } void PrintAxis( const Point& pnt) const { } private : double _x; double _y; }; //打印点所处象限 void PointInfo::PrintQuadrant( const Point& pnt) const { if (pnt._x > 0 && pnt._y > 0) cout << "点" << "(" << pnt._x << "," << pnt._y<< ")" << "处于第一象限" << endl; } void PointMove::PointAxisAddOne(Point& pnt) { pnt._x = pnt._x + 1; pnt._y = pnt._y + 1; } double TwoPointsDistant( const Point& pnt1, const Point& pnt2) { return sqrt ( pow ((pnt1._x - pnt2._x), 2) + pow ((pnt1._y - pnt2._y), 2) ); } int main() { Point point1(1.1,2.2); Point point2(3.3, 4.4); cout << TwoPointsDistant(point1, point2) << endl; PointInfo pf; pf.PrintQuadrant(point1); system ( "pause" ); return 0; } |
VS2015打印结果:
四.同一个类(class)的类对象(object)互为友元
还以上面给出的例子为基础,现在在_Point_类加一个成员函数func(const Point& pnt),它返回点的x轴和y轴的和。如下所示。
1
2
3
4
5
6
7
8
9
10
11
|
class Point { /*这里同上*/ double func( const Point& pnt) { return pnt._x + pnt._y; } private : double _x; double _y; }; |
现在我生成两个对象,并作如下操作:
1
2
3
|
Point point1(1.1,2.2); Point point2(3.3, 4.4); cout << point1.func(point2) << endl; |
最后的结果是打印出7.7。看到这里不知道你有没有疑问:为什么可以通过point1直接访问point2的私有数据成员,而没有将func()声明为友元函数?侯捷老师是这么解释的:相同class的各个objects之间互为友元。
所以对于一个类A,若有一个成员函数Fun(A& arg),可以通过arg直接访问A的私有数据成员。
总结
本篇文章就到这里了,希望能够给你带来帮助,也希望您能够多多关注服务器之家的更多内容!
原文链接:https://blog.csdn.net/weixin_43744293/article/details/123327548