经验首页 前端设计 程序设计 Java相关 移动开发 数据库/运维 软件/图像 大数据/云计算 其他经验
当前位置:技术经验 » 程序设计 » C++ » 查看文章
一篇文章详细解释C++的友元(friend)
来源:jb51  时间:2022/3/8 12:55:24  对本文有异议

一.友元函数

友元函数可以是普通函数或者类成员函数。

先看普通函数声明为友元函数:

如下所示:

  1. #include <iostream>
  2. #include <cmath>
  3. using namespace std;
  4. class Point
  5. {
  6. //普通函数声明为类的友元函数
  7. friend double TwoPointsDistant(const Point& pnt1, const Point& pnt2);
  8. public:
  9. Point(double x=0, double y=0)
  10. :_x(x), _y(y)
  11. {}
  12. double getPointXAxis() const { return this->_x; }
  13. double getPointYAxis() const { return this->_y; }
  14. private:
  15. double _x;
  16. double _y;
  17. };
  18. //计算两点的距离
  19. double TwoPointsDistant(const Point& pnt1, const Point& pnt2)
  20. {
  21. return sqrt( pow((pnt1._x - pnt2._x), 2) + pow((pnt1._y - pnt2._y), 2) );
  22. }
  23. int main()
  24. {
  25. Point point1(1.1,2.2);
  26. Point point2(3.3, 4.4);
  27. cout << TwoPointsDistant(point1, point2) << endl;
  28. system("pause");
  29. return 0;
  30. }

这里说明一点:TwoPointsDistant()函数必须在Point类的定义下面,至于原因,很简单,你若放在Point上面,Point的数据成员_x和_y都没定义呢,你用个锤子。

再看类成员函数声明为友元函数:

还以上面的类为例,现在加一个_PointMove_类,它有一个成员函数_PointAxisAddOne,_作用是将点的坐标都加1。如下:

  1. class PointMove
  2. {
  3. public:
  4. void PointAxisAddOne(Point& pnt);
  5. };

这里就出现了一个问题:_Point_和_PointMove_哪个放在前面?先给出答案,应该把_PointMove_放在前面,并且是必须的,如下:

  1. class Point;//前向声明Point
  2. class PointMove
  3. {
  4. public:
  5. void PointAxisAddOne(Point& pnt);
  6. };
  7. class Point
  8. {
  9. //普通函数声明为类的友元函数
  10. friend double TwoPointsDistant(const Point& pnt1, const Point& pnt2);
  11. //类成员函数声明为友元
  12. friend void PointMove::PointAxisAddOne(Point& pnt);
  13. /*这里同前*/
  14. };
  15. //类成员函数的定义
  16. void PointMove::PointAxisAddOne(Point& pnt)
  17. {
  18. pnt._x = pnt._x + 1;
  19. pnt._y = pnt._y + 1;
  20. }

这里注意,对于类的成员函数,声明为其他类的友元函数时需要加上类的作用域,即指出该函数属于哪个类。如上面的_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. class Point
  2. {
  3. //友元类
  4. friend class PointInfo;
  5. ...
  6. }
  7. class PointInfo
  8. {
  9. public:
  10. //打印点所处象限
  11. void PrintQuadrant(const Point& pnt) const
  12. {
  13. if (pnt._x > 0 && pnt._y > 0)
  14. cout << "点"<<"(" << pnt._x << "," << pnt._y<<")" <<"处于第一象限" << endl;
  15. }
  16. };

当然,你也可以把_PointInfo_写在_Point_前,只是函数_PrintQuadrant()_的定义就不能在类内实现了,只能在_Point_后实现,原因和前面一样,不再赘述。

三.完整示例:

  1. #include <iostream>
  2. #include <cmath>
  3. using namespace std;
  4. class Point;
  5. class PointMove
  6. {
  7. public:
  8. void PointAxisAddOne(Point& pnt);
  9. };
  10. class PointInfo
  11. {
  12. public:
  13. //打印点所处象限
  14. void PrintQuadrant(const Point& pnt) const;
  15. };
  16. class Point
  17. {
  18. friend class PointInfo;
  19. friend double TwoPointsDistant(const Point& pnt1, const Point& pnt2);
  20. friend void PointMove::PointAxisAddOne(Point& pnt);
  21. public:
  22. Point(double x=0, double y=0)
  23. :_x(x), _y(y)
  24. {}
  25. double getPointXAxis() const { return this->_x; }
  26. double getPointYAxis() const { return this->_y; }
  27. void PrintAxis(const Point& pnt) const
  28. {
  29. }
  30. private:
  31. double _x;
  32. double _y;
  33. };
  34. //打印点所处象限
  35. void PointInfo::PrintQuadrant(const Point& pnt) const
  36. {
  37. if (pnt._x > 0 && pnt._y > 0)
  38. cout << "点"<<"(" << pnt._x << "," << pnt._y<<")" <<"处于第一象限" << endl;
  39. }
  40. void PointMove::PointAxisAddOne(Point& pnt)
  41. {
  42. pnt._x = pnt._x + 1;
  43. pnt._y = pnt._y + 1;
  44. }
  45. double TwoPointsDistant(const Point& pnt1, const Point& pnt2)
  46. {
  47. return sqrt( pow((pnt1._x - pnt2._x), 2) + pow((pnt1._y - pnt2._y), 2) );
  48. }
  49. int main()
  50. {
  51. Point point1(1.1,2.2);
  52. Point point2(3.3, 4.4);
  53. cout << TwoPointsDistant(point1, point2) << endl;
  54. PointInfo pf;
  55. pf.PrintQuadrant(point1);
  56. system("pause");
  57. return 0;
  58. }

VS2015打印结果:

打印结果

四.同一个类(class)的类对象(object)互为友元

还以上面给出的例子为基础,现在在_Point_类加一个成员函数func(const Point& pnt),它返回点的x轴和y轴的和。如下所示。

  1. class Point
  2. {
  3. /*这里同上*/
  4. double func(const Point& pnt)
  5. {
  6. return pnt._x + pnt._y;
  7. }
  8. private:
  9. double _x;
  10. double _y;
  11. };

现在我生成两个对象,并作如下操作:

  1. Point point1(1.1,2.2);
  2. Point point2(3.3, 4.4);
  3. cout << point1.func(point2) << endl;

最后的结果是打印出7.7。看到这里不知道你有没有疑问:为什么可以通过point1直接访问point2的私有数据成员,而没有将func()声明为友元函数?侯捷老师是这么解释的:相同class的各个objects之间互为友元。

所以对于一个类A,若有一个成员函数Fun(A& arg),可以通过arg直接访问A的私有数据成员。

总结

本篇文章就到这里了,希望能够给你带来帮助,也希望您能够多多关注w3xue的更多内容!

 友情链接:直通硅谷  点职佳  北美留学生论坛

本站QQ群:前端 618073944 | Java 606181507 | Python 626812652 | C/C++ 612253063 | 微信 634508462 | 苹果 692586424 | C#/.net 182808419 | PHP 305140648 | 运维 608723728

W3xue 的所有内容仅供测试,对任何法律问题及风险不承担任何责任。通过使用本站内容随之而来的风险与本站无关。
关于我们  |  意见建议  |  捐助我们  |  报错有奖  |  广告合作、友情链接(目前9元/月)请联系QQ:27243702 沸活量
皖ICP备17017327号-2 皖公网安备34020702000426号