本系列 C++ 相关文章 仅为笔者学习笔记记录,用自己的理解记录学习!C++ 学习系列将分为三个阶段:基础篇、STL 篇、高阶数据结构与算法篇,相关重点内容如下:
- 基础篇:类与对象(涉及C++的三大特性等);
- STL 篇:学习使用 C++ 提供的 STL 相关库;
- 高阶数据结构与算法篇: 手动实现自己的 STL 库 及 设计实现高阶数据结构,如 B树、B+树、红黑树等。
学习集:
- C++ 入门到入土!!!学习合集
- Linux 从命令到网络再到内核!学习合集
本期内容:【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关键字。
- 友元函数可访问类的私有和保护成员,但不是类的成员函数。
- 友元函数不能用 const 修饰。
- 友元函数可以在类定义的任何地方声明,不受类访问限定符限制。
- 一个函数可以是多个类的友元函数。
- 友元函数的调用与普通函数的调用原理相同。
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. 什么时候用友元?
回忆什么是友元,它的作用是?:友元提供了一种突破封装的方式,有时提供了便利。但是友元会增加耦合度,破坏了封装,所以友元不宜多用。
如上友元函数和友元类的示例简单总结:
- 需要重载 流输入 / 流输出 时!(cout / cin);
- 某个类需要访问另一个具有一定关系的类的成员变量时使用。【说白了就是要突破类封装的限制时使用】
5. 相关文章推荐
1. C++ 学习 ::【基础篇:05】:C++ 函数重载认识及使用、简单介绍:C++ 支持函数重载的原因
2. C++ 学习 ::【基础篇:09】:C++ 类的认识及基本声明定义;简单对比C++中类与结构体的区别
3. C++ 学习 ::【基础篇:10】:C++ 类的访问限定符介绍与说明(三种)及类封装(三大特性之一)的初步认识
4. C++ 学习 ::【基础篇:11】:C++ 类的基本使用与非静态 this 指针(两个面试考点):类的空指针问题(this指针可以为空吗?) | this指针存在哪里?