• C语言日记 37 类的友元(1)(全局函数做友元)


    (1):全局函数做友元 

    根据36 类和对象-友元-全局函数做友元_哔哩哔哩_bilibili复现出如下代码:

    一、(只是)访问(公开)内部成员:

    1. #include
    2. using namespace std;
    3. class Building
    4. {
    5. private:
    6. int ws;//卧室
    7. public:
    8. int kt;//客厅
    9. Building();
    10. };
    11. Building::Building()//构造函数赋初值
    12. {
    13. int ws = 1;
    14. int kt = 2;
    15. }
    16. int visit(Building b)
    17. {
    18. cout << "客厅=" << b.kt << endl;
    19. return 0;
    20. }
    21. int main()
    22. {
    23. Building b1;
    24. visit(b1);
    25. }

    在这里,实际上,我们也可以把构造函数写在类里面,实现同样的效果:

    1. class Building
    2. {
    3. private:
    4. int ws;//卧室
    5. public:
    6. int kt;//客厅
    7. Building()//构造函数赋初值
    8. {
    9. int ws = 1;
    10. int kt = 2;
    11. }
    12. };

     结果:

    为什么我写了半天,最后返回的是一个随机值呢?

    根本原因,就在于构造函数的格式不对,构造函数在赋初值时,类里面的变量(成员)前不应该(不能)有类型说明

    C语言日记 33 构造函数_宇 -Yu的博客-CSDN博客中,就有构造函数定义和声明的使用格式)

    如果没有类型说明,那么构造函数相当于还在给类的(公有,私有)成员变量赋初值,

    而加上了类型说明,那么相当于构造函数在给函数内自定义的变量赋初值,和类里面的成员没有关系,而类的成员实际上并没有被赋值,输出时返回的自然就是一个随机值;所以,我们应将程序改为:(通过实参形参调用传值)

    1. #include
    2. using namespace std;
    3. class Building
    4. {
    5. private:
    6. int ws;//卧室
    7. public:
    8. int kt;//客厅
    9. Building();
    10. };
    11. Building::Building()//构造函数赋初值
    12. {
    13. ws = 1;
    14. kt = 2;
    15. }
    16. int visit(Building b)
    17. {
    18. cout << "客厅=" << b.kt << endl;
    19. return 0;
    20. }
    21. int main()
    22. {
    23. Building b1;
    24. visit(b1);
    25. }

    结果:

    修改为36 类和对象-友元-全局函数做友元_哔哩哔哩_bilibili源程序所设计的各个模块的样子:

    1. #include
    2. using namespace std;
    3. class Building
    4. {
    5. private:
    6. int ws;//卧室
    7. public:
    8. int kt;//客厅
    9. Building()//构造函数赋初值
    10. {
    11. ws = 1;
    12. kt = 2;
    13. }
    14. };
    15. //
    16. int visit(Building b)
    17. {
    18. cout << "客厅=" << b.kt << endl;
    19. return 0;
    20. }
    21. void test()
    22. {
    23. Building b1;
    24. visit(b1);
    25. }
    26. int main()
    27. {
    28. test();
    29. }

    我们可以通过实参形参调用传值,也可以用指针,引用的方式传值:

    指针:

    1. int visit(Building* b)
    2. {
    3. cout << "客厅=" << b->kt << endl;
    4. return 0;
    5. }
    6. void test()
    7. {
    8. Building b1;
    9. visit(&b1);
    10. }

    注解:

    (1):这里的“->”,表示:通过指针来访问结构体变量(的具体内容)C语言日记 28 结构体类型_宇 -Yu的博客-CSDN博客

    (2):

    visit(&b1);

    中,&表示取(地)址,不能改为*(如果改为*,则表示访问该指针指向的目标对象的具体内容)

    如果一定不想这样写的话,可以改写为:

    1. void test()
    2. {
    3. Building b;
    4. Building *b1=&b;
    5. visit(b1);
    6. }

    引用:

    1. int visit(Building &b)
    2. {
    3. cout << "客厅=" <
    4. return 0;
    5. }
    6. void test()
    7. {
    8. Building b;
    9. visit(b);
    10. }

    注解:

    (1):引用访问,就和对象访问自身的内容属性引用,不能用“->”;(“->”只能用于指针)

    (2):

    	visit(b);

    只能这么写,不能在前面加“*”(加了表求指向目标的值),也不能加“&”(加了表求指向目标的地址)

    二、访问内部私有成员(这就要用到友元了)

    这时,既然我们想要让全局函数访问内部私有成员,只要在前面的基础上

    在visit()函数中写一个输出私有函数的语句:

        cout << "卧室=" << b.ws << endl;

    并且在类的成员声明里面加(上)一个友元函数的声明:

        friend void visit(Building b);

    值得注意的是:

    这里的友元函数的声明加在类(体)的任意处都可以:

    友元函数不是成员函数,无论是放在private私有成员说明中:

    1. #include
    2. using namespace std;
    3. class Building
    4. {
    5. private:
    6. int ws;//卧室
    7. friend void visit(Building b);
    8. public:
    9. int kt;//客厅
    10. Building()//构造函数赋初值
    11. {
    12. ws = 1;
    13. kt = 2;
    14. }
    15. };
    16. //
    17. void visit(Building b)
    18. {
    19. cout << "客厅=" << b.kt << endl;
    20. cout << "卧室=" << b.ws << endl;
    21. }
    22. void test()
    23. {
    24. Building b1;
    25. visit(b1);
    26. }
    27. int main()
    28. {
    29. test();
    30. }

    还是放在成员说明之外:

    1. #include
    2. using namespace std;
    3. class Building
    4. {
    5. friend void visit(Building b);
    6. private:
    7. int ws;//卧室
    8. public:
    9. int kt;//客厅
    10. Building()//构造函数赋初值
    11. {
    12. ws = 1;
    13. kt = 2;
    14. }
    15. };
    16. //
    17. void visit(Building b)
    18. {
    19. cout << "客厅=" << b.kt << endl;
    20. cout << "卧室=" << b.ws << endl;
    21. }
    22. void test()
    23. {
    24. Building b1;
    25. visit(b1);
    26. }
    27. int main()
    28. {
    29. test();
    30. }

    最终结果都可以访问类的内部私有成员:

    例8-14 使用普通函数计算两点间的距离。

    源程序:

    1. #include
    2. #include
    3. using namespace std;
    4. class Point //Point 类定义
    5. {
    6. private://私有数据成员
    7. int x, y;
    8. public://外部接口
    9. Point(int x = 0, int y = 0) :x(x), y(y) { }
    10. int getX() { return x; }
    11. int getY() { return y; }
    12. friend float dist(Point& a, Point& b); //友元函数是一个普通函数
    13. };
    14. float dist(Point& a, Point& b)//普通函数的定义
    15. {
    16. double x = a.x - b.x;
    17. double y = a.y - b.y;
    18. return(float)sqrt(x * x + y * y);
    19. }
    20. //
    21. int main()
    22. {
    23. Point p1(3, 5), p2(11, 6);
    24. cout << "The distance is:";
    25. cout << dist(p1, p2) << endl;
    26. //调用普通友元函数
    27. return 0;
    28. }

    结果:

    The distance is:8.06226

    (1):#include :相当于#include (C语言),当然这里不写也无所谓,如同:C语言日记 8 C++语句_宇 -Yu的博客-CSDN博客:#include <math.h>//可有可无

    (2):其中的: friend float dist(Point &a, Point &b); 只是一个用引用作为函数参数的形式,可以改(写)为:(实参形参传递数据)

    friend float dist(Point a, Point b);  

    详见书P105(当然,像这样用实参形参传递数据,采用的是值传递的传值的方式);

    也可以改(写)为:(指针传递数据)

    1. #include
    2. #include
    3. using namespace std;
    4. class Point //Point 类定义
    5. {
    6. private://私有数据成员
    7. int x, y;
    8. public://外部接口
    9. Point(int x = 0, int y = 0) :x(x), y(y) { }
    10. int getX() { return x; }
    11. int getY() { return y; }
    12. friend float dist(Point* a, Point* b); //友元函数是一个普通函数
    13. };
    14. float dist(Point* a, Point* b)//普通函数的定义
    15. {
    16. double x = a->x - b->x;
    17. double y = a->y - b->y;
    18. return(float)sqrt(x * x + y * y);
    19. }
    20. //
    21. int main()
    22. {
    23. Point p1(3, 5), p2(11, 6);
    24. cout << "The distance is:";
    25. cout << dist(&p1, &p2) << endl;
    26. //调用普通友元函数
    27. return 0;
    28. }

     当然,改写为指针传递数据的方式的修改过程,比起其他两种情况要更为复杂一些:

    改动处:

    (1):形参a和b改为指针

    (2):“->”改为"."

    (3):调用dist函数时,里面的实参p1,p2改为取(地)址“&p1,&p2”

    (3):另外,(如果)我们想要在类中(里面)定义该友元函数(不用分开声明,直接一次性定义完成就行了)最终结果也一样:

    1. #include
    2. using namespace std;
    3. class Point //Point 类定义
    4. {
    5. private://私有数据成员
    6. int x, y;
    7. public://外部接口
    8. Point(int x = 0, int y = 0) :x(x), y(y) { }
    9. int getX() { return x; }
    10. int getY() { return y; }
    11. friend float dist(Point a, Point b)//友元函数是一个普通函数
    12. {
    13. double x = a.x - b.x;
    14. double y = a.y - b.y;
    15. return(float)sqrt(x * x + y * y);
    16. }
    17. };
    18. //
    19. int main()
    20. {
    21. Point p1(3, 5), p2(11, 6);
    22. cout << "The distance is:";
    23. cout << dist(p1, p2) << endl;
    24. //调用普通友元函数
    25. return 0;
    26. }

    而在这里我们可以看到,实际上想要访问本类的内部私有成员,根本还用不着什么友元函数,

    直接设立一个公有的类函数直接访问调用私有成员就可以:

    1. #include
    2. #include
    3. using namespace std;
    4. class Point //Point 类定义
    5. {
    6. private://私有数据成员
    7. int x, y;
    8. public://外部接口
    9. Point(int x = 0, int y = 0) :x(x), y(y) { }
    10. int getX() { return x; }
    11. int getY() { return y; }
    12. float dist(Point* a, Point* b)//普通函数的定义
    13. {
    14. double x = a->x - b->x;
    15. double y = a->y - b->y;
    16. return(float)sqrt(x * x + y * y);
    17. }
    18. };
    19. //
    20. int main()
    21. {
    22. Point p1(3, 5), p2(11, 6);
    23. cout << "The distance is:";
    24. cout << dist(&p1, &p2) << endl;
    25. //调用普通友元函数
    26. return 0;
    27. }

    结果:

    为什么???

    调用类中定义的函数必须用对象(才能调用):(这里用p1,p2都可以)

    1. #include
    2. #include
    3. using namespace std;
    4. class Point //Point 类定义
    5. {
    6. private://私有数据成员
    7. int x, y;
    8. public://外部接口
    9. Point(int x = 0, int y = 0) :x(x), y(y) { }
    10. int getX() { return x; }
    11. int getY() { return y; }
    12. float dist(Point* a, Point* b)//普通函数的定义
    13. {
    14. double x = a->x - b->x;
    15. double y = a->y - b->y;
    16. return(float)sqrt(x * x + y * y);
    17. }
    18. };
    19. //
    20. int main()
    21. {
    22. Point p1(3, 5), p2(11, 6);
    23. cout << "The distance is:";
    24. cout << p1.dist(&p1, &p2) << endl;
    25. //调用普通友元函数
    26. return 0;
    27. }

     (2):成员函数做友元

     例8-15 使用其他类的成员函数实现两点间距离的计算。

    源程序:

    1. #include
    2. using namespace std;
    3. class Point;//声明 Point 类
    4. class Dist//Dist 类定义
    5. {
    6. public:
    7. float dist(Point& a, Point& b);
    8. };
    9. class Point//Point 类定义
    10. {
    11. private://私有数据成员
    12. int x, y;
    13. public://外部接口
    14. Point(int x = 0, int y = 0) :x(x), y(y) {}
    15. int getx() { return x; }
    16. int getY() { return y; }
    17. friend float Dist::dist(Point& a, Point& b);
    18. //友元函数是Dist的成员函数
    19. };
    20. float Dist::dist(Point& a, Point& b) //友元函数的定义
    21. {
    22. double x = a.x - b.x;
    23. double y = a.y - b.y;
    24. return (float)sqrt(x * x + y * y);
    25. }
    26. int main()
    27. {
    28. Point p3(10, 8), p4(4, 12);
    29. Dist d;
    30. cout << "The distance is:"; cout << d.dist(p3, p4) << endl;
    31. //调用成员友元函数
    32. return 0;
    33. }

    The distance is:7.2111

     ​​

    (3):友元类

    见下一篇日记

    (其实是下一篇日记太短,而这篇日记太长,把这个内容换一个位置,调整一下两篇的篇幅)

  • 相关阅读:
    机器学习06|两万字:决策树 【jupyter代码详解篇】
    C++ 手动实现单向循环链表(课后作业版)
    Pytoch随笔(光速入门篇)
    【送书活动】Photoshop——神秘生物的艺术创造与文化探索
    不就是Java吗之Object类
    迁移学习的概念
    git4:git整合IDEA和国内代码托管中心码云(自建代码托管平台)
    【AI视野·今日Robot 机器人论文速览 第六十五期】Mon, 30 Oct 2023
    【经验模态分解】2.EMD的3个基本概念
    【推理引擎】从源码看ONNXRuntime的执行流程
  • 原文地址:https://blog.csdn.net/Zz_zzzzzzz__/article/details/127973183