【C++ 基础篇:21】:friend 友元四连问:什么是友元?友元类?友元函数?什么时候用友元?

本系列 C++ 相关文章 仅为笔者学习笔记记录,用自己的理解记录学习!C++ 学习系列将分为三个阶段:基础篇、STL 篇、高阶数据结构与算法篇,相关重点内容如下:

  1. 基础篇类与对象(涉及C++的三大特性等);
  2. STL 篇学习使用 C++ 提供的 STL 相关库
  3. 高阶数据结构与算法篇手动实现自己的 STL 库设计实现高阶数据结构,如 B树、B+树、红黑树等。

学习集:


本期内容:【C++ 基础篇:21】:友元四连问:什么是友元?友元类?友元函数?什么时候用友元?


目录:
1. 友元的基本认识
2. 友元函数
- - 2.1 友元函数基本使用情形
- - 2.2 cout / cin 的重载结构写法
- - 2.3 友元函数的使用注意点
3. 友元类
- - 3.1 友元类的基本认识
- - 3.2 示例 + 图示:说明友元类
4. 什么时候用友元?
5. 相关文章推荐


C++学习合集链接


1. 友元的基本认识

友元提供了一种突破封装的方式,有时提供了便利。但是友元会增加耦合度,破坏了封装,所以友元不宜多用。


友元分为:友元函数、友元类声明时的关键字:friend


2. 友元函数

2.1 友元函数基本使用情形
  • 多用于实现 「流输入/流输出」 重载 cout / cin

由于在重载 cout / cin 过程中,若重载在类的内部,类中第一个参数默认是 this 指针,在重载之后就会造成 this 指针作为左操作数,与实际的 cout / cin 用法向违背!

实际中,cout / cin 的第一个参数应该是形参对象!所以不能在类的内部声明定义对应的重载解决方式就是声明定义为全局函数
但是接踵而来的问题是:类外无法访问类中的成员变量!【此时,友元就起到了一个很好的作用!】


2.2 cout / cin 的重载结构写法

cout / cin 的重载结构写法如下:【注:由于使用频率高,通常会声明为内联函数】(后续会再讲,此处仅做了解)

// xxx.h
class A{
public:
    friend ostream& operator << (ostream& _cout, const A& a);
    friend istream& operator >> (istream& _cin, A& a);
};

inline ostream& operator<< (ostream& _cout, const A& a){
    _cout << ... << ... << ...;
    return _cout;
}
inline istream& operator>> (istream& _cin, A& a){
    _cin >> ... >> ... >> ...;
    return _cin;
}

2.3 友元函数的使用注意点

友元函数可以直接访问类的私有成员,它是定义在类外部的普通函数,不属于任何类,但需要在类的内部声明,声明时需要加friend关键字。


  1. 友元函数可访问类的私有和保护成员,但不是类的成员函数。
  2. 友元函数不能用 const 修饰。
  3. 友元函数可以在类定义的任何地方声明,不受类访问限定符限制。
  4. 一个函数可以是多个类的友元函数。
  5. 友元函数的调用与普通函数的调用原理相同。

3. 友元类
3.1 友元类的基本认识

友元类的所有成员函数都可以是另一个类的友元函数,都可以访问另一个类中的非公有成员。

  • 友元关系是单向的,不具有交换性。【比如 Time 类和 Date 类,在Time 类中声明 Date 类为其友元类,那么可以在 Date 类中直接访问 Time类的私有成员变量,但想在 Time 类中访问 Date 类中私有的成员变量则不行。】
  • 友元关系不能传递【如果 C 是 B 的友元, B 是 A 的友元,则不能说明C 时 A 的友元】
  • 友元关系不能继承,在继承位置再给大家详细介绍。

3.2 示例 + 图示:说明友元类

图示在代码后面!

#include<iostream>
using std::cout;
using std::endl;

class Time
{
    friend class Date;      // 声明日期类为时间类的友元类,则在日期类中就直接访问Time类中的私有成员变量
public:
    Time(int hour = 0, int minute = 0, int second = 0)
        : _hour(hour)
        , _minute(minute)
        , _second(second)
    {}
private:
    int _hour;
    int _minute;
    int _second;
    void PrintTime() {
        cout << _hour << ":" << _minute << ":" << _second << endl;
    }
};
class Date
{
public:
    Date(int year = 1900, int month = 1, int day = 1)
        : _year(year)
        , _month(month)
        , _day(day)
    {}
    void SetTimeOfDate(int hour, int minute, int second)
    {
        // 直接访问时间类私有的成员变量
        _t._hour = hour;
        _t._minute = minute;
        _t._second = second;
    }
    void PrintTime() {  
        _t.PrintTime();         // 直接访问 Time 类的成员函数
    }
private:
    int _year;
    int _month;
    int _day;
    Time _t;
};


int main() {
    // 直接构造一个默认的日期类
    Date d1;

    d1.PrintTime();

    d1.SetTimeOfDate(22, 21, 20);

    d1.PrintTime();

    return 0;
}

在这里插入图片描述

注:若不是友元关系,以上形式只能访问公有成员!即不存在图中的调用关系而直接报错!

在这里插入图片描述


4. 什么时候用友元?

回忆什么是友元,它的作用是?:友元提供了一种突破封装的方式,有时提供了便利。但是友元会增加耦合度,破坏了封装,所以友元不宜多用。


如上友元函数和友元类的示例简单总结:

  1. 需要重载 流输入 / 流输出 时!(cout / cin);
  2. 某个类需要访问另一个具有一定关系的类的成员变量时使用。【说白了就是要突破类封装的限制时使用】

5. 相关文章推荐

1. C++ 学习 ::【基础篇:05】:C++ 函数重载认识及使用、简单介绍:C++ 支持函数重载的原因
2. C++ 学习 ::【基础篇:09】:C++ 类的认识及基本声明定义;简单对比C++中类与结构体的区别
3. C++ 学习 ::【基础篇:10】:C++ 类的访问限定符介绍与说明(三种)及类封装(三大特性之一)的初步认识
4. C++ 学习 ::【基础篇:11】:C++ 类的基本使用与非静态 this 指针(两个面试考点):类的空指针问题(this指针可以为空吗?) | this指针存在哪里?

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

NPC的白话文谈

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值