当前位置: 首页 > news >正文

C++之 友元重载 以及最常用的几种友元函数

在之前的友元中就曾经讲过,我们为了去访问修改私有成员中的数据时,只能通过公有的办法去进行访问操作,非常的局限。所以C++引用了友元函数,只要加上friend关键字,C++的这个类,会自动把这个函数的权限拉到类内,这样就可以访问私有成员了。

上一篇文章,讲了重载运算符的操作。但有些运算符不能够在类内进行重载,例如输入输出的符号。下面我会详细讲,为什么不能在类内进行重载。

这里我们先假设有一个类:

A{};//功能暂且不写,知道是个类就行了

首先,普通类内重载,会自带一个this指针,指向用此函数的对象。这被称作第一操作数。

如果在定义+号的时候,实际上是并不是简单的(类对象)+(某某)亦或是(某某)+(类对象);

它实际上全部的写法应该是:

A    a;                     //这里定义了一个对象a

a.operator+(某某);      //这是全部写法,也是正常情况应该写的情况,只是我们平时简写,编译器仍然认识罢了。

a+(某某)   // 这是我们平时的写法

比如你想重载<<或者>>符号,这种情况,他的第一操作符就一定不是类本身,例如:

A    a;

我们不可能写成:a<<或者是a>>;我们正常的写法应该是:cin >>a;cout << a;

这里第一操作符并不是a这个对象,而是cin/cout。这是ios的输入输出的参数。

这里有人就要问了,那(类对象)+(某某);我也可以写成(某某)+(类对象);这里实际上是交换律,因为,这里类对象写的地方,并不是唯一的,可以进行交换,这种情况可以不算。

话不多说,我们使用代码来进行讲解,下面先给大家展示时间类运算符重载,作为对比,我先写类内成员函数重载,再写类外友元重载,大家可以复制下来,看看。

#include <iostream>
#include <string>
using namespace std;/*
* 1.类的成员    在类内的运算符重载函数的第一个操作数一定是类的对象
* 总结:
*   有的情况运算符必须写成非成员函数.这个函数如果需要获得类对象的私有数据,则有如下方法
*   1.可以利用交换律(前提是类已经实现该运算符的重载.1.5*t->t*1.5)
*   2.类把该函数声明为它的友元函数
*   3.类提供获取私有数据的公有方法
*   
*   举例:如下  
*/
class Time
{
private:int hours;//小时int minutes;//分钟
public:Time(int h = 0, int m = 0) :hours(h), minutes(m)//构造函数{}Time operator +(const Time& t)const;//重载 +,注意返回值不是引用Time operator -(const Time& t)const//重载 -{int tmp = (hours * 60 + minutes) - (t.hours * 60 + t.minutes);//分钟return Time(tmp / 60, tmp % 60);}Time operator *(double n)const;//重载 *  .含义;3:40 * 3 ->11小时0分//3*3:40  不是void show() const;//提供获得时间的公有方法/* int GetHours()const{return hours;}int GetMinutes()const{return minutes;}*/
};Time Time::operator+(const Time& t)const  //2:30+2:45
{return Time(hours + t.hours + (minutes + t.minutes) / 60, (minutes + t.minutes) % 60);
}Time Time::operator *(double n)const  // Time * 小数
{double tmp = (hours * 60 + minutes) * n;return Time{ (int)tmp / 60,(int)tmp % 60 };
}void Time::show() const
{cout << hours << "小时," << minutes << "分钟" << endl;
}Time operator*(double n,const Time &t)//普通函数的形式重载*
{//double tmp = n * (t.hours * 60 + t.minutes);//错误,这个函数不是Time成员,不能访问它的私有// int tmp = (int)(n * (t.GetHours() * 60 + t.GetMinutes()));//  return Time(tmp/60,tmp%60);return t * n;//前提:已经实现了 t*n
}int main()
{Time t1{ 2,35 };Time t2 = { 2,40 };Time t3 = t1 + t2;//t1.operator+(t2);Time t4 = t2 - t1;//t2.operator-(t1);Time t5 = t1 * 1.5;Time t6 = 1.5 * t1;//没有实现 小数*时间t3.show();t4.show();t5.show();t6.show();//t1 * 3;//t1.operator*(3);//3*t1;//3.*(t1);//在3这个int类 没有实现对Time的*重载return 0;
}

接下来,作为对比,我继续把重载输入输出的代码。

#include <iostream>
#include <string>
using namespace std;class Time
{
private:int hours;//小时int minutes;//分钟public:Time(int h = 0, int m = 0);void show() const;//void operator <<(ostream& os)//os是输出流对象的引用//{//    os << hours << "小时,," << minutes << "分钟" << endl;//}friend Time operator *(double n, const Time& t);//这个是Time的友元函数friend ostream& operator <<(ostream& os, const Time& t);//这个是Time的友元函数//实现 >> 运算符重载   istreamfriend istream& operator >>(istream& is, Time& t);
};Time::Time(int h, int m)
{hours = h;minutes = m;
}void Time::show() const
{cout << hours << "小时," << minutes << "分钟" << endl;
}Time operator *(double n, const Time& t)
{int tmp = (int)(n * (t.hours * 60 + t.minutes));return Time(tmp/60,tmp%60);
}ostream & operator <<(ostream& os, const Time& t)//os不加const,需要把数据写入到输出流
{os << t.hours << "小时,," << t.minutes << "分钟" << endl;return os;
}istream& operator >>(istream& is, Time& t)
{return is >> t.hours >> t.minutes;
}int main()
{Time t1 = { 2,35 };Time t2 = { 2,40 };Time t3 = 1.5*t1;  //第一个操作数不是类对象,所以只能是非成员函数//t3.show();//t3 << cout; //可以作为类成员函数的,但不能理解cout << t3;//这个不能调用t3的成员函数,但我们需要cout << t1 << t2;cin >> t1; //5 30cout << t1;//5小时,30分钟// cout << t3 ;//错误,没有实现如何 cout<< Time的对象//cout 是 ostream类对象  ; cin是istream类对象return 0;
}

每日金句:

        一步一行,便无惧陷入泥沼!

                                                                                                           ---------------银枝

相关文章:

C++之 友元重载 以及最常用的几种友元函数

在之前的友元中就曾经讲过&#xff0c;我们为了去访问修改私有成员中的数据时&#xff0c;只能通过公有的办法去进行访问操作&#xff0c;非常的局限。所以C引用了友元函数&#xff0c;只要加上friend关键字&#xff0c;C的这个类&#xff0c;会自动把这个函数的权限拉到类内&a…...

动态规划(3)——dp多状态问题Ⅰ

题一.按摩师&#xff08;LeetCode&#xff09; 题目描述 一个有名的按摩师会收到源源不断的预约请求&#xff0c;每个预约都可以选择接或不接。在每次预约服务之间要有休息时间&#xff0c;因此她不能接受相邻的预约。给定一个预约请求序列&#xff0c;替按摩师找到最优的预约集…...

在Mac电脑上安装adb环境

当你在命令行输入 adb version 或adb devices, 报错&#xff1a;zsh: command not found: adb &#xff0c;那么说明你的 Mac 上没有安装 ADB&#xff08;Android Debug Bridge&#xff09;&#xff0c;或者它没有添加到你的路径中。你可以按照以下步骤安装和配置 ADB&#xff…...

分糖果C++

题目&#xff1a; 样例解释&#xff1a; 样例1解释 拿 k20 块糖放入篮子里。 篮子里现在糖果数 20≥n7&#xff0c;因此所有小朋友获得一块糖&#xff1b; 篮子里现在糖果数变成 13≥n7&#xff0c;因此所有小朋友获得一块糖&#xff1b; 篮子里现在糖果数变成 6<n7&#xf…...

Spring中如何为静态变量注入值

在 Spring 中&#xff0c;如果使用 Value 注解注入值&#xff0c;不能将其应用于 static 字段。Spring 只能为实例变量注入值&#xff0c;不能直接对静态变量进行注入。 使用 PostConstruct 初始化&#xff1a; 如果确实需要在静态上下文中使用该值&#xff0c;可以使用 Post…...

HTML5实现唐朝服饰网站模板源码

文章目录 1.设计来源1.1 网站首页-界面效果1.2 唐装演变-界面效果1.3 唐装配色-界面效果1.4 唐装花纹-界面效果1.5 唐装文化-界面效果 2.效果和源码2.1 动态效果2.2 源代码 源码下载万套模板&#xff0c;程序开发&#xff0c;在线开发&#xff0c;在线沟通 作者&#xff1a;xcL…...

ESXI识别USB设备

步骤&#xff1a; 插入usb设备到服务器。关闭虚拟机&#xff0c;添加USB控制器&#xff0c;根据U盘选择usb 3.0控制器&#xff0c;再添加usb设备如果usb设备灰色&#xff0c;进入主机打开SSH。使用xshell进行连接&#xff0c;运行以下命令&#xff1a; ESXI识别USB设备 - 插入…...

视频美颜SDK与直播美颜工具API是什么?计算机视觉技术详解

今天&#xff0c;小编将深入探讨视频美颜SDK与直播美颜工具API的概念及其背后的计算机视觉技术。 一、视频美颜SDK的概念 视频美颜SDK是一套用于开发实时美颜效果的工具集&#xff0c;开发者可以利用它在视频流中实现面部特征的优化。这些SDK通常提供了一系列功能&#xff0c…...

not exist 解决一对多 场景 条件过滤问题

场景&#xff1a; 现在存在一对多关系&#xff0c;蓝色的盒子装的篮球&#xff0c;黄的的盒子装的黄球&#xff0c; 黑色的盒子 &#xff08;模拟工作类似场景&#xff09; boxIdballId蓝盒ID-15蓝盒ID-16蓝盒ID-17黄盒ID-212黄盒ID-215黄盒ID-216黑盒ID-38黑盒ID-39 需求&a…...

解决$‘r‘ command not found或者文件夹显示’tvsf 33‘$‘r‘

问题现象: 某客户反馈在执行脚本的时候文件夹显示存在问题,如下图: 但是脚本文件中的内容并没有\r字符,如下图: 也有客户反馈如下: 问题分析: $\r’是回车符的转义表示。在Unix和Linux系统中,回车符是一个不可见的控制字符,它通常用于文本文件中的行结尾。以上…...

linux:详解nohup命令

在 UNIX 和类 UNIX 操作系统&#xff08;如 Linux 和 macOS&#xff09;中&#xff0c;nohup 意图为后台运行且免疫挂断信号的命令&#xff0c;用于在用户注销&#xff08;logout&#xff09;或终端关闭后继续运行相应的进程。 基本语法 启动进程 nohup [COMMAND] [ARG...] …...

负载箱:充电桩测试利器

RCD负载箱是用于测试和验证电气设备在故障状态下的性能的设备。它可以模拟真实的负载情况&#xff0c;从而帮助工程师和技术人员对设备进行准确的检测和维护。此外&#xff0c;RCD负载箱也是一种重要的安全保护设备&#xff0c;主要用于防止电路中的漏电现象引发的事故。它通常…...

Ubuntu 开机自启动 .py / .sh 脚本,可通过脚本启动 roslaunch/roscore等

前言 项目中要求上电自启动定位程序&#xff0c;所以摸索了一种 Ubuntu 系统下开机自启动的方法&#xff0c;开机自启动 .sh 脚本&#xff0c;加载 ROS 环境的同时启动 .py 脚本。在 . py 脚本中启动一系列 ROS 节点。 一、 .sh 脚本的编写 #!/bin/bash # gnome-terminal -- …...

RabbitMQ 消息队列:生产者与消费者实现详解

在分布式系统中&#xff0c;消息队列&#xff08;Message Queue, MQ&#xff09;是一种重要的组件&#xff0c;用于解耦系统、异步处理任务以及实现系统间的通信。RabbitMQ 是一个流行的开源消息代理软件&#xff0c;它实现了高级消息队列协议&#xff08;AMQP&#xff09;。在…...

vue3项目中组件切换不起作用

以下这种方式写页面中组件切换&#xff0c;不起作用。 <component :is"steps[compIndex].comp" />解决&#xff1a;使用shallowReactive或者shallowRef把对应的组件名称重新定义下。 <component :is"compNames[steps[compIndex].comp]" /> &…...

YOLOv11改进策略【损失函数篇】| Slide Loss,解决简单样本和困难样本之间的不平衡问题

一、本文介绍 本文记录的是改进YOLOv11的损失函数&#xff0c;将其替换成Slide Loss&#xff0c;并详细说明了优化原因&#xff0c;注意事项等。Slide Loss函数可以有效地解决样本不平衡问题&#xff0c;为困难样本赋予更高的权重&#xff0c;使模型在训练过程中更加关注困难样…...

动静态库(Linux)

文章目录 前言一、静态库二、动态库三、深入理解动态库总结 前言 我们之前用过c语言的库.Linux中默认的都是使用动态库&#xff0c;如果想要使用静态库&#xff0c;就必须加上-static选项。默认都是安装的动态库&#xff0c;系统中一般没有静态库&#xff0c;如果要使用&#…...

51单片机和ARM单片机的区别

在嵌入式系统设计与应用中&#xff0c;单片机作为核心控制单元&#xff0c;扮演着至关重要的角色。其中&#xff0c;51单片机和ARM单片机作为两种常见的单片机类型&#xff0c;各自具有独特的特点和优势。本文将从多个维度深入探讨这两种单片机的区别&#xff0c;以便读者更好地…...

[Day 81] 區塊鏈與人工智能的聯動應用:理論、技術與實踐

區塊鏈在食品安全中的應用 前言 食品安全一直是全球關注的問題&#xff0c;隨著全球供應鏈的複雜性增加&#xff0c;追踪食品從生產到消費的過程變得愈發困難。區塊鏈技術以其去中心化、不可篡改的特性&#xff0c;為食品安全提供了可靠的解決方案。在這篇文章中&#xff0c;…...

flac格式怎么转mp3?关于flac转为MP3的方法介绍

flac格式怎么转mp3&#xff1f;MP3格式经过压缩&#xff0c;相较于flac文件&#xff0c;显著减小了文件体积。这一特点使得音乐的存储和传输更加便捷&#xff0c;尤其适合移动设备以及存储空间有限的场景。由于MP3文件体积较小&#xff0c;分享音乐变得非常简单&#xff0c;无论…...

华为云AI开发平台ModelArts

华为云ModelArts&#xff1a;重塑AI开发流程的“智能引擎”与“创新加速器”&#xff01; 在人工智能浪潮席卷全球的2025年&#xff0c;企业拥抱AI的意愿空前高涨&#xff0c;但技术门槛高、流程复杂、资源投入巨大的现实&#xff0c;却让许多创新构想止步于实验室。数据科学家…...

练习(含atoi的模拟实现,自定义类型等练习)

一、结构体大小的计算及位段 &#xff08;结构体大小计算及位段 详解请看&#xff1a;自定义类型&#xff1a;结构体进阶-CSDN博客&#xff09; 1.在32位系统环境&#xff0c;编译选项为4字节对齐&#xff0c;那么sizeof(A)和sizeof(B)是多少&#xff1f; #pragma pack(4)st…...

Mybatis逆向工程,动态创建实体类、条件扩展类、Mapper接口、Mapper.xml映射文件

今天呢&#xff0c;博主的学习进度也是步入了Java Mybatis 框架&#xff0c;目前正在逐步杨帆旗航。 那么接下来就给大家出一期有关 Mybatis 逆向工程的教学&#xff0c;希望能对大家有所帮助&#xff0c;也特别欢迎大家指点不足之处&#xff0c;小生很乐意接受正确的建议&…...

Web 架构之 CDN 加速原理与落地实践

文章目录 一、思维导图二、正文内容&#xff08;一&#xff09;CDN 基础概念1. 定义2. 组成部分 &#xff08;二&#xff09;CDN 加速原理1. 请求路由2. 内容缓存3. 内容更新 &#xff08;三&#xff09;CDN 落地实践1. 选择 CDN 服务商2. 配置 CDN3. 集成到 Web 架构 &#xf…...

Pinocchio 库详解及其在足式机器人上的应用

Pinocchio 库详解及其在足式机器人上的应用 Pinocchio (Pinocchio is not only a nose) 是一个开源的 C 库&#xff0c;专门用于快速计算机器人模型的正向运动学、逆向运动学、雅可比矩阵、动力学和动力学导数。它主要关注效率和准确性&#xff0c;并提供了一个通用的框架&…...

LeetCode - 199. 二叉树的右视图

题目 199. 二叉树的右视图 - 力扣&#xff08;LeetCode&#xff09; 思路 右视图是指从树的右侧看&#xff0c;对于每一层&#xff0c;只能看到该层最右边的节点。实现思路是&#xff1a; 使用深度优先搜索(DFS)按照"根-右-左"的顺序遍历树记录每个节点的深度对于…...

QT3D学习笔记——圆台、圆锥

类名作用Qt3DWindow3D渲染窗口容器QEntity场景中的实体&#xff08;对象或容器&#xff09;QCamera控制观察视角QPointLight点光源QConeMesh圆锥几何网格QTransform控制实体的位置/旋转/缩放QPhongMaterialPhong光照材质&#xff08;定义颜色、反光等&#xff09;QFirstPersonC…...

Windows安装Miniconda

一、下载 https://www.anaconda.com/download/success 二、安装 三、配置镜像源 Anaconda/Miniconda pip 配置清华镜像源_anaconda配置清华源-CSDN博客 四、常用操作命令 Anaconda/Miniconda 基本操作命令_miniconda创建环境命令-CSDN博客...

Golang——7、包与接口详解

包与接口详解 1、Golang包详解1.1、Golang中包的定义和介绍1.2、Golang包管理工具go mod1.3、Golang中自定义包1.4、Golang中使用第三包1.5、init函数 2、接口详解2.1、接口的定义2.2、空接口2.3、类型断言2.4、结构体值接收者和指针接收者实现接口的区别2.5、一个结构体实现多…...

【前端异常】JavaScript错误处理:分析 Uncaught (in promise) error

在前端开发中&#xff0c;JavaScript 异常是不可避免的。随着现代前端应用越来越多地使用异步操作&#xff08;如 Promise、async/await 等&#xff09;&#xff0c;开发者常常会遇到 Uncaught (in promise) error 错误。这个错误是由于未正确处理 Promise 的拒绝&#xff08;r…...