• C++友元函数


    友元——让函数或者类作为另外一个类的朋友,则可以访问当前类的private或者protected

    友元friend机制允许一个类授权其他的函数访问它的非公有成员

    友元声明以关键字friend开头,它只能出现在类的声明中,它们不受其在类体中的public、private和protected区的影响

    一、友元函数可分为以下三种类型:

    1、外部函数友元

    一个普通函数作为类的友元,那么在当前函数中就可以通过对象访问类的私有或者保护成员

    注意:这个函数只能在外部定义,在当前类中引用即可

    1. class A
    2. {
    3. public:
    4. A(int i=0):m_i(i){}
    5. int GetI()const
    6. {
    7. return m_i;
    8. }
    9. friend void Add(A& a, A& b);
    10. protected:
    11. //friend void Add(A& a, A& b);//将Add函数作为类A的友元,在内部并不能定义
    12. private:
    13. //friend void Add(A& a, A& b);//在保护和私有都能正确运行
    14. int m_i;
    15. };
    16. //想在Add函数中访问私有数据成员,又不想通过接口(共有函数)
    17. void Add(A& a, A& b)
    18. {
    19. cout << a.m_i << endl;
    20. cout << b.m_i << endl;
    21. cout << a.m_i + b.m_i << endl;
    22. //cout << a.GetI() + b.GetI() << endl;
    23. }
    24. void main()
    25. {
    26. A a(5);
    27. A b(8);
    28. Add(a, b);
    29. }

    函数不止能作为一个类的友元

    1. class B;//前向引用声明
    2. class A
    3. {
    4. public:
    5. A(int i=0):m_i(i){}
    6. friend int Sum(A& a, B& b);//在这之前未定义class B,需进行声明
    7. private:
    8. int m_i;
    9. };
    10. class B
    11. {
    12. public:
    13. B(int j = 0) :m_j(j) {}
    14. friend int Sum(A& a, B& b);//一般情况下放在共有里面
    15. private:
    16. int m_j;
    17. };
    18. int Sum(A& a, B& b)
    19. {
    20. return a.m_i + b.m_j;
    21. }
    22. void main()
    23. {
    24. A a(20);
    25. B b(20);
    26. cout << Sum(a, b) << endl;
    27. }

    2、成员函数友元

    一个类的成员函数作为另一个类的友元

    注意:成员函数建议放在类外定义

    1. class A;
    2. class B
    3. {
    4. public:
    5. B(int j = 0) :m_j(j) {}
    6. void Sub(A& a);
    7. void Print(A& a);
    8. private:
    9. int m_j;
    10. };
    11. class A
    12. {
    13. public:
    14. A(int i = 0) :m_i(i) {}
    15. friend void B::Sub(A& a);//
    16. friend void B::Print(A& a);
    17. private:
    18. int m_i;
    19. };
    20. void B::Sub(A& a)
    21. {
    22. cout << a.m_i - m_j << endl;
    23. }
    24. void B::Print(A& a)
    25. {
    26. cout << a.m_i << endl;
    27. }
    28. void main()
    29. {
    30. A a(40);
    31. B b(20);
    32. b.Sub(a);
    33. }

    3、类友元

    一个类A作为另外一个类B的友元类,则A的所有的成员函数就可以访问B的私有数据成员或者保护

    整个类可以是另一个类的友元。友元类的每个成员函数都是另一个类的友元函数,都可以访问另一个类中的所有成员,公有、保护或私有数据成员。 

    1. class B;
    2. class A
    3. {
    4. public:
    5. A(int a=0):m_a(a){}
    6. void print(B& b);
    7. void test(B& b);
    8. void show(B& b);
    9. private:
    10. int m_a;
    11. };
    12. class B
    13. {
    14. public:
    15. B(int b=0):m_b(b)
    16. friend class A;
    17. private:
    18. int m_b;
    19. };
    20. void A::print(B& b)
    21. {
    22. cout <<"print"<< b.m_b << endl;
    23. }
    24. void A::test(B& b)
    25. {
    26. cout << "test"<
    27. }
    28. void A::show(B& b)
    29. {
    30. cout << "show"<
    31. }
    32. void main()
    33. {
    34. B b(30);
    35. A a(40);
    36. a.print(b);
    37. a.show(b);
    38. a.test(b);
    39. }

    总结:

    1、 友元函数不是类的成员函数,在函数体中访问对象的成员,必须用对象名加运算符"."加对象成员名。但友元函数可以访问类中的所有成员,一般函数只能访问类中的公有成员。

    2、友元函数不受类中的访问权限关键字限制,可以把它放在类的公有、私有、保护部分,但结果都一样。

    3、某类的友元函数的作用域并非该类作用域。如果该友元函数是另一类的成员函数,则其作用域为另一类的作用域,否则与一般函数相同。

    二、友元特点:

    1、友元是单向的:A是B的友元,并不意味B是A的友元

    1. class B;
    2. class A
    3. {
    4. public:
    5. A(int a=0):m_a(a){}
    6. void print(B& b);
    7. void test(B& b);
    8. void show(B& b);
    9. friend class B;
    10. private:
    11. int m_a;
    12. };
    13. class B
    14. {
    15. public:
    16. B(int b=0):m_b(b){}
    17. friend class A;
    18. void Print(A& a);//
    19. private:
    20. int m_b;
    21. };
    22. void B::Print(A& a)
    23. {
    24. cout << a.m_a << endl;//友元是单向的,需在A中再次声明friend B
    25. }
    26. void A::print(B& b)
    27. {
    28. cout <<"print"<< b.m_b << endl;
    29. }
    30. void A::test(B& b)
    31. {
    32. cout << "test"<
    33. }
    34. void A::show(B& b)
    35. {
    36. cout << "show"<
    37. }
    38. void main()
    39. {
    40. B b(30);
    41. A a(40);
    42. a.print(b);
    43. a.show(b);
    44. a.test(b);
    45. b.Print(a);
    46. }

    2、友元是不能传递的:A是B的友元,B是C的友元,但A不是C的友元

     BB是AA的朋友,CC是BB的朋友,如果CC没有作为AA的友元类,则CC和AA没有关系——友元不能传递

    1. class BB;
    2. class CC;
    3. class AA
    4. {
    5. public:
    6. AA(int a=0):m_a(a){}
    7. friend class BB;
    8. private:
    9. int m_a;
    10. };
    11. class BB
    12. {
    13. public:
    14. friend class CC;
    15. void Show(AA& a);
    16. private:
    17. int m_b;
    18. };
    19. class CC
    20. {
    21. public:
    22. void print(BB& b);
    23. void test(AA& a);
    24. };
    25. void BB::Show(AA& a)
    26. {
    27. cout << a.m_a << endl;
    28. }
    29. void CC::print(BB& b)
    30. {
    31. cout << b.m_b << endl;
    32. }
    33. void CC::test(AA& a)
    34. {
    35. cout << a.m_a << endl;//error CC不是AA的朋友(友元不能传递)
    36. }
    37. void main()
    38. {
    39. }

    3、友元是不能继承的:Base类型继承Object类型,如果Object类型是A的友元,但Base类型不是A友元。

    三、友元函数在运算符重载中的应用

    1、不同类型对象,但数据成员个数与类型一致,重载+

    1. class B;
    2. class A
    3. {
    4. public:
    5. A(int i=0):m_i(i){}
    6. int operator+(B& b);
    7. private:
    8. int m_i;
    9. };
    10. class B
    11. {
    12. public:
    13. B(int j=0):m_j(j){}
    14. friend int A::operator+(B& b);
    15. private:
    16. int m_j;
    17. };
    18. int A::operator+(B& b)
    19. {
    20. return m_i + b.m_j;
    21. }
    22. void main()
    23. {
    24. A a(10);
    25. B b(20);
    26. cout << a + b << endl;//a.+(b) +(a,b)
    27. }

    2、 重载成员函数调用可以省略一个参数

    重载友元函数不能省略

    1. class A
    2. {
    3. public:
    4. A(int i=0):m_i(i){}
    5. void print()
    6. {
    7. cout << m_i << endl;
    8. }
    9. A operator+(A& b)//this
    10. {
    11. return m_i + b.m_i;
    12. }
    13. friend A operator-(A& a, A& b);
    14. A operator++(int)//a++值返回
    15. {
    16. int t = m_i;
    17. m_i = m_i + 1;
    18. return t;
    19. }
    20. friend A& operator++(A& a);
    21. private:
    22. int m_i;
    23. };
    24. A operator-(A& a, A& b)
    25. {
    26. return a.m_i - b.m_i;
    27. }
    28. A& operator++(A& a)
    29. {
    30. ++a.m_i;
    31. return a;
    32. }
    33. void main()
    34. {
    35. A a(5);
    36. A b(10);
    37. (a + b).print();
    38. (a - b).print();
    39. (a++).print();
    40. (++b).print();
    41. }

    3、重载输出运算符(输出对象(即输出对象中的数据成员))

    cout——ostream类的对象

    cin——istream类的对象

    cout<

    一般情况下运算符可以解析成下面两种形式:

    1、cout.<<(a)  ostream类中重载了<<,程序员不能修改

    2、<<(cout,a)  可以在程序员自己定义的类中将<<重载成友元

    cout<

    cout<

    (cout<

    friend ostream& operator<<(ostream &out,A &a)

    1. class A
    2. {
    3. public:
    4. A(int i=0):m_i(i){}
    5. friend ostream& operator<<(ostream& out, A& a);
    6. private:
    7. int m_i;
    8. };
    9. //cout<
    10. ostream& operator<<(ostream& out, A& a)
    11. {
    12. out << a.m_i;
    13. return out;
    14. }
    15. void main()
    16. {
    17. A a(5);
    18. cout << a;//cout<<(a) <<(cout,a)
    19. }

    练习: 

    输出值为:0,8,5

    1. class Magic
    2. {
    3. double x;
    4. public:
    5. Magic(double d=0.00):x(fabs(d)){}
    6. Magic operator+(Magic c)
    7. {
    8. return Magic(sqrt(x * x + c.x));
    9. }
    10. friend ostream& operator<<(ostream& os, Magic c);
    11. };
    12. ostream& operator<<(ostream& os, Magic c)
    13. {
    14. return os << c.x;
    15. }
    16. void main()
    17. {
    18. Magic ma;
    19. cout << ma << "," << Magic(-8) << "," << ma + Magic(-3) + Magic(-4);
    20. }

  • 相关阅读:
    [libopenh264 @ 0x563c78392040] Incorrect library version loaded
    高级运维学习(十三)三表五链
    Djiango 模版系统详解(ORM数据模型-使用mysql数据库增删改查)
    Spring – 记录传入请求
    数字藏品系统开发,基于区块链智能合约技术
    Linux命令从入门到实战 ---- 用户管理命令
    Go常见错误第15篇:interface使用的常见错误和最佳实践
    【算法】选择排序
    从 min 到 max 的随机数
    Eureka: Netflix开源的服务发现框架
  • 原文地址:https://blog.csdn.net/weixin_59179454/article/details/127574320