目录

一、为什么要使用友元

二、友元函数

1.友元函数定义

2.友元函数特性

三、友元类

1.友元类定义

2.友元类特性

四、内部类

1.内部类定义

2.内部类特性

五、总结​​​​​​​


一、为什么要使用友元

对于自定义类型Date类,为了打印Date类的对象,需要我们自己在Date类中写打印函数:

void Print() const
{cout << _year << "-" << _month << "-" << _day << endl;
}

而内置类型在不写打印重载函数的情况下却能够直接打印:

#include<iostream>
using namespace std;int main()
{int a = 0;cout << a << endl;return 0;
}

这是因为库里面对内置类型写了许多运算符重载函数,包括operator>>和operator<<并且能够自动识别类型构成重载,所以内置类型直接能调打印。而自定义类型需要自己写打印函数。

假如库里面对内置类型没有写operator>>和operator<<重载,对于自定义的Date类那就只有在类中自己写operator>>和operator<<重载函数了:

#include<iostream>
using namespace std;class Date
{
public://构造函数Date(int year = 2022, int month = 4, int day = 8){_year = year;_month = month;_day = day;}//void Date::Print() const//{//    cout << _year << "-" << _month << "-" << _day << endl;//}void operator<<(ostream& out){out << _year << "-" << _month << "-" << _day << endl;}void operator>>(istream& in){in>>_year;in >> _month;in >> _day;}private:int _year;int _month;int _day;
};int main()
{Date d1;cout << d1;return 0;
}

但是用cout<<d1却调用不了<<运算符:

我们需要的是cout<<d1,但是调用operator<<实际上执行的是:

void operator<<(ostream& out) //void operator<<(Date* this, ostream& out)

d1作为this就变成了第一个参数,main函数里面的调用应该是d1<<cout,编译通过:

int main()
{Date d1;d1 << cout;//我们需要cout<<d1return 0;
}

但是d1<<cout的调用不符合我们的习惯,可读性不高,我们需要cout作为第一个参数,这样就会造成d1和cout抢占第一个参数的问题。假如把operator>>和operator<<重载不写在类里面,而是写成全局函数写在Date类外面,我们可以指定参数顺序:

#include<iostream>
using namespace std;class Date
{
public://构造函数Date(int year = 2022, int month = 4, int day = 8){_year = year;_month = month;_day = day;}private:int _year;int _month;int _day;
};void operator<<(ostream& out,const Date& d)
{out << _year << "-" << _month << "-" << _day << endl;
}void operator>>(istream& in, const Date& d)
{in >> _year;in >> _month;in >> _day;
}int main()
{Date d1;cout << d1;return 0;
}

但会带来访问不了私有成员变量的问题:

如何能够访问到类的私有成员变量,突破类域呢?-------使用友元,友元提供了一种突破封装的方式。友元分为友元函数和友元类。

二、友元函数

1.友元函数定义

友元函数是定义在类外部的普通函数,不属于任何类,但可以直接访问类的私有成员,需要在类的内部使用friend关键字进行声明,类就会把友元函数当作类里面的成员。

#include<iostream>
using namespace std;class Date
{//友元函数friend ostream& operator<<(ostream& out, const Date& d);friend istream& operator>>(istream& in, Date& d);public://构造函数Date(int year = 2022, int month = 4, int day = 8){_year = year;_month = month;_day = day;}private:int _year;int _month;int _day;
};ostream& operator<<(ostream& out,const Date& d)
{out << d._year << "-" << d._month << "-" << d._day << endl;return _cout;
}istream& operator>>(istream& in, Date& d)
{in >> d._year;in >> d._month;in >> d._day;return in;
}int main()
{Date d1;cin >> d1;cout << d1 <<endl;return 0;
}

2.友元函数特性

(1)友元函数可访问类的私有和保护成员,但不是类的成员函数

(2)友元函数不能用const修饰(const修饰this指针指向的内容,友元函数作为全局函数没有this指针)

(3)友元函数可以在类定义的任何地方声明,不受类访问限定符限制

(4)一个函数可以是多个类的友元函数

(5)友元函数的调用与普通函数的调用和原理相同

三、友元类

1.友元类定义

友元类的所有成员函数都可以是另一个类的友元函数,都可以访问另一个类中的非公有成员。如下Date类是Time类的友元类,Date类要访问Time类,就要把Date类定义成Time类的友元:

class Date; // 前置声明
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;
};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;}private:int _year;int _month;int _day;Time _t;
};int main()
{return 0;
}

2.友元类特性

(1)友元关系是单向的,不具有交换性。

在Time类中,声明Date 类是其友元类,可以在Date类中直接访问Time类的私有成员。但不能在Time中访问Date类中的私有成员。

(2)友元关系不能传递

A是B的友元,B是C的友元,但A不是C的友元。

四、内部类

1.内部类定义

一个类定义在另一个类的内部,这个内部类就叫做内部类。

内部类和外部类关系: 

(1)内部类不属于外部类,更不能通过外部类的对象调用内部类。外部类对内部类没有任何优越的访问权限。

(2)内部类是外部类的友元类,内部类可以通过外部类的对象参数来访问外部类的所有成员,但外部类不是内部类的友元。

#include<iostream>
using namespace std;class A {
private:static int k;int h;
public:class B  //B是A的内部类,B是A的友元类{public:void foo(const A& a){cout << k << endl;//内部类可以访问外部类的非公有成员cout << a.h << endl;//普通成员只能通过对象访问,不能通过类名访问}private:int _b;};
};int A::k = 1;int main()
{A::B b; //定义一个内部类对象b.foo(A());return 0;
}

2.内部类特性

(1)内部类可以定义在外部类的public、protected、private都是可以的。

(2)注意内部类可以直接访问外部类中的static、枚举成员,不需要外部类的对象/类名。

(3)sizeof(外部类)=外部类,和内部类没有任何关系

int main()
{A::B b;b.foo(A());//由于静态成员变量不在对象中存储,类的大小为非静态成员变量内存对齐的结果,A只有一个非静态成员变量cout << "sizeof(A) = " << sizeof(A) << endl;return 0;
}

五、总结

A无论是类还是全局函数,只要A被定义为B的友元,A就可以访问B的非公有成员。

【C++】-- 友元相关推荐

  1. C++ 笔记(30)— 友元函数与友元类

    我们知道类的私有成员只能在类的成员函数内部访问,如果想在别处访问对象的私有成员,只能通过类提供的接口(成员函数)间接地进行.这固然能够带来数据隐藏的好处,利于将来程序的扩充,但也会增加程序书写的麻烦. ...

  2. C++ primer 第七章之 友元函数与友元类

    1.为什么需要友元函数?  类具有封装和信息隐藏的特性: 只有类的成员函数才能访问类的私有成员,程序中的其他函数是无法访问私有成员的 ; 非成员函数可以访问类中的公有成员,但是如果将数据成员都定义为公 ...

  3. 友元函数、类的非静态成员函数、静态成员函数的区别

    类中申明的函数相对于类来说有三层意思: 1.有this指针 2.函数在类的作用区域中 3.可以访问类中私有部分 4.可以被继承 非静态成员函数具有1234 静态成员函数具有234 友元函数具有3 静态 ...

  4. C++——运算符的重载---以成员函数方式重载---以友元函数方式重载

    一.运算符的重载 1.运算符的重载 允许把标准运算符(如+ - * /等运算符)应用于自定义数据类型的对象,可以提高程序的可读性,运算符的重载本质上还是函数重载.运算符仅仅是语法上的方便,它是另一种函 ...

  5. C++运算符重载形式--成员函数or友元函数?

    1.C++操作符重载形式-成员函数or友元函数 1.对运算符重载,需要坚持四项基本原则: 不可臆造运算符: 运算符原有操作数的个数.优先级和结合性不能改变: 操作数中至少一个是自定义类型: 保持重载运 ...

  6. C++中的友元函数friend

    1.C++中的友元函数 类的友元函数是定义在类外部,但有权访问类的所有私有(private)成员和保护(protected)成员.尽管友元函数的原型有在类的定义中出现过,但是友元函数并不是成员函数.友 ...

  7. 友元类实例:日期类 学生类

    1.定义Date类 : Date类中定义了三个私有数据成员(year ,month,day) 2.定义Student类: 在Student类中定义了两个私有数据成员(name[] ,birthday) ...

  8. C++中友元类使用场合

    在C++中我们可以將函数定义成类的友元函数,这样在函数中就可以访问类的私有成员.与函数相同,类也可以作为另一个类的友元类,在友元类中可以访问另外一个类的所有成员. 声明友元类的方法很简单,只需在类中写 ...

  9. C++中友元函数和友元类

    友元函数 友元函数是可以直接访问类的私有成员的非成员函数.它是定义在类外的普通函数,它不属于任何类,但需要在类的定义中加以声明,声明时只需在友元的名称前加上关键字friend,其格式如下: frien ...

  10. 运算符中的二元重载,为什么要调用友元函数而不是全局函数的问题

    #include <iostream>using namespace std; //实现运算符的重载 class A { public:A(int real=0,int imaginary ...

最新文章

  1. 最新发现6个高质量网站,让人眼前一亮!
  2. css重叠边界,关于css:两个重叠元素上的边界半径; 背景闪耀
  3. 单片机原理及其应用——单片机控制8只发光二极管交替闪烁
  4. GridView简单创建序号列
  5. C# 特性 Attribute
  6. 多媒体音频格式解析WMA WAV OGG AAC APE FLAC
  7. 学习Unix,可从事什么样的工作(3)《精通Unix下C语言与项目实践》读书笔记(5)...
  8. 罗永浩抖音直播带货100天,糊了?
  9. Falsy Bouncer 过滤数组假值 Array.filter()方法
  10. AWE /3GB 内存扩展技术
  11. 图解汽车各部位的名称大全
  12. python中len的用法_Python len函数用法
  13. 6岁的招聘界“ChatGPT”|企业家俱乐部“创业者下午茶”第八期——AI得贤招聘官创始人方小雷
  14. python学习之爬取ts流电影
  15. 比较二进制工具哪家强?
  16. GEDI学习笔记1:数据产品简介
  17. 军备竞赛!奔驰全球“扩招”3000名软件工程师,2024年推MB.OS
  18. 数据结构与算法学习⑤(BFS和DFS 贪心算法 二分查找)
  19. jquery实现图片的跑马灯效果
  20. ClickHouse加载TPCH数据

热门文章

  1. Win7蓝牙耳机怎么连接电脑
  2. Linux常用命令汇总 - 近乎全量命令!
  3. panda经典四道题期末考核分享
  4. 机器学习中的特征重要性 Feature Importance
  5. 基于51单片机的温湿度检测及调节系统
  6. LINUX——账号和权限管理
  7. 针对python代码下载youtub视屏报错修复
  8. php- 秒的转换 (天 小时 分钟) (小时 分钟 )
  9. vite+ts+vue3 知识点(全局组件,局部组件,递归组件)
  10. 配置SDN网关:关于VRF、本地路由及inet-vpn路由