当前位置: 首页 > 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;无论…...

java 实现excel文件转pdf | 无水印 | 无限制

文章目录 目录 文章目录 前言 1.项目远程仓库配置 2.pom文件引入相关依赖 3.代码破解 二、Excel转PDF 1.代码实现 2.Aspose.License.xml 授权文件 总结 前言 java处理excel转pdf一直没找到什么好用的免费jar包工具,自己手写的难度,恐怕高级程序员花费一年的事件,也…...

【JVM】- 内存结构

引言 JVM&#xff1a;Java Virtual Machine 定义&#xff1a;Java虚拟机&#xff0c;Java二进制字节码的运行环境好处&#xff1a; 一次编写&#xff0c;到处运行自动内存管理&#xff0c;垃圾回收的功能数组下标越界检查&#xff08;会抛异常&#xff0c;不会覆盖到其他代码…...

[Java恶补day16] 238.除自身以外数组的乘积

给你一个整数数组 nums&#xff0c;返回 数组 answer &#xff0c;其中 answer[i] 等于 nums 中除 nums[i] 之外其余各元素的乘积 。 题目数据 保证 数组 nums之中任意元素的全部前缀元素和后缀的乘积都在 32 位 整数范围内。 请 不要使用除法&#xff0c;且在 O(n) 时间复杂度…...

LINUX 69 FTP 客服管理系统 man 5 /etc/vsftpd/vsftpd.conf

FTP 客服管理系统 实现kefu123登录&#xff0c;不允许匿名访问&#xff0c;kefu只能访问/data/kefu目录&#xff0c;不能查看其他目录 创建账号密码 useradd kefu echo 123|passwd -stdin kefu [rootcode caozx26420]# echo 123|passwd --stdin kefu 更改用户 kefu 的密码…...

【从零学习JVM|第三篇】类的生命周期(高频面试题)

前言&#xff1a; 在Java编程中&#xff0c;类的生命周期是指类从被加载到内存中开始&#xff0c;到被卸载出内存为止的整个过程。了解类的生命周期对于理解Java程序的运行机制以及性能优化非常重要。本文会深入探寻类的生命周期&#xff0c;让读者对此有深刻印象。 目录 ​…...

RSS 2025|从说明书学习复杂机器人操作任务:NUS邵林团队提出全新机器人装配技能学习框架Manual2Skill

视觉语言模型&#xff08;Vision-Language Models, VLMs&#xff09;&#xff0c;为真实环境中的机器人操作任务提供了极具潜力的解决方案。 尽管 VLMs 取得了显著进展&#xff0c;机器人仍难以胜任复杂的长时程任务&#xff08;如家具装配&#xff09;&#xff0c;主要受限于人…...

Bean 作用域有哪些?如何答出技术深度?

导语&#xff1a; Spring 面试绕不开 Bean 的作用域问题&#xff0c;这是面试官考察候选人对 Spring 框架理解深度的常见方式。本文将围绕“Spring 中的 Bean 作用域”展开&#xff0c;结合典型面试题及实战场景&#xff0c;帮你厘清重点&#xff0c;打破模板式回答&#xff0c…...

python爬虫——气象数据爬取

一、导入库与全局配置 python 运行 import json import datetime import time import requests from sqlalchemy import create_engine import csv import pandas as pd作用&#xff1a; 引入数据解析、网络请求、时间处理、数据库操作等所需库。requests&#xff1a;发送 …...

MyBatis中关于缓存的理解

MyBatis缓存 MyBatis系统当中默认定义两级缓存&#xff1a;一级缓存、二级缓存 默认情况下&#xff0c;只有一级缓存开启&#xff08;sqlSession级别的缓存&#xff09;二级缓存需要手动开启配置&#xff0c;需要局域namespace级别的缓存 一级缓存&#xff08;本地缓存&#…...

高考志愿填报管理系统---开发介绍

高考志愿填报管理系统是一款专为教育机构、学校和教师设计的学生信息管理和志愿填报辅助平台。系统基于Django框架开发&#xff0c;采用现代化的Web技术&#xff0c;为教育工作者提供高效、安全、便捷的学生管理解决方案。 ## &#x1f4cb; 系统概述 ### &#x1f3af; 系统定…...