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

news2024/9/30 21:42:05

在之前的友元中就曾经讲过,我们为了去访问修改私有成员中的数据时,只能通过公有的办法去进行访问操作,非常的局限。所以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的友元函数
    //实现 >> 运算符重载   istream
    friend 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 30
    cout << t1;//5小时,30分钟

   // cout << t3 ;//错误,没有实现如何 cout<< Time的对象

    //cout 是 ostream类对象  ; cin是istream类对象

    return 0;
}

每日金句:

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

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

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2180778.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

无水印短视频素材下载网站有哪些?十个高清无水印视频素材网站分享

你知道怎么下载无水印视频素材吗&#xff1f;今天小编就给大家推荐十个高清无水印视频素材下载的网站&#xff0c;如果你也是苦于下载高清无水印的短视频素材&#xff0c;赶紧来看看吧&#xff5e; 1. 稻虎网 首推的是稻虎网。这个网站简直就是短视频创作者的宝库。无论你需要…

编程魔法:基于LLM的AI function开发,如何实现高效数据生成?

基于大语言模型&#xff08;LLM&#xff09;的AI function开发&#xff0c;简直就是现代编程界的“魔法棒”&#xff01; 你好&#xff0c;我是三桥君 最近三桥君有个任务&#xff0c;需要造一些测试数据&#xff0c;比如姓名、手机号、银行卡号、邮箱啥的&#xff0c;用来做测…

每日OJ题_牛客_添加逗号_模拟_C++_Java

目录 牛客_添加逗号_模拟 题目解析 C代码1 C代码2 Java代码 牛客_添加逗号_模拟 添加逗号_牛客题霸_牛客网 题目解析 读取输入&#xff1a;读取一行字符串。分割字符串&#xff1a;使用空格将字符串分割成单词数组。拼接字符串&#xff1a;将单词数组中的每个单词用逗号…

群晖安装Gitea(代码托管工具)

一、Gitea介绍 Gitea 是一款开源的轻量级代码托管平台,可以为团队和开发者提供了一个易于部署、运行快速、使用体验良好的自建 Git 服务。相比于其它自部署代码托管平台,Gitea 的设计更加轻量,对系统资源的占用相对较少,能够在较低配置的服务器上流畅运行。相比于其他代码…

嘉楠科技AI芯片K230-初探

勘智K230 介绍入门购买开发板 安装开机开发学习点亮第1个LED点亮屏幕预览摄像头代码离线运行 在线训练平台 参考 介绍 K230芯片是嘉楠科技 Kendryte系列AIoT芯片中的最新一代SoC产品。该芯片采用全新的多异构单元加速计算架构&#xff0c;集成了2个RISC-V高能效计算核心&#x…

Spring系列 BeanPostProcessor

文章目录 BeanPostProcessor注册时机执行时机 InstantiationAwareBeanPostProcessorSmartInstantiationAwareBeanPostProcessor 本文源码基于spring-beans-5.3.31 参考&#xff1a;https://docs.spring.io/spring-framework/reference/core/beans/factory-extension.html#beans…

【ASE】第四课_高亮显示效果(手动切换)

今天我们一起来学习ASE插件&#xff0c;希望各位点个关注&#xff0c;一起跟随我的步伐 今天我们来学习高亮的效果。 思路&#xff1a; 1.添加纹理贴图和法线贴图&#xff0c;环境光遮挡贴图 2.添加高亮的参数&#xff0c;并设置 3.手搓一个边缘光,通过高亮参数调节 4.将模…

微信小程序——音乐播放器

目的 掌握swiper组件、scroll-view组件的使用掌握image组件的使用掌握音频API的使用掌握slider组件的使用 内容 了音乐小程序项目的完整开发流程&#xff0c;其开发步骤包括页面结构的分析、样式的设计、组件的运用等。通过本章的学习&#xff0c;读者能够掌握小程序的基本交…

聚星文社——绘唐科技有什么区别!

聚星文社和绘唐科技是两个不同的公司&#xff0c;有一些区别。下面是它们的一些区别&#xff1a; 绘唐科技——聚星文社https://iimenvrieak.feishu.cn/docx/ZhRNdEWT6oGdCwxdhOPcdds7nof 行业领域&#xff1a;聚星文社主要从事文化娱乐行业&#xff0c;包括出版、影视制作等&…

点餐小程序实战教程14点餐功能

目录 1 功能分析2 初始化菜品的数量3 加入购物车4 显示购物车5 最终的效果总结 上一篇我们讲解了如果通过扫码实现餐桌信息显示&#xff0c;本篇我们介绍一下点餐的功能。 1 功能分析 点餐的话一般我们是在菜品点击号或者-号来加入购物车&#xff0c;加入购物车之后还可以修改…

APP 安全测试项总结

一、安装包测试 1.1、关于反编译 目的是为了保护公司的知识产权和安全方面的考虑等&#xff0c;一些程序开发人员会在源码中硬编码一些敏感信息&#xff0c;如密码。而且若程序内部一些设计欠佳的逻辑&#xff0c;也可能隐含漏洞&#xff0c;一旦源码泄漏&#xff0c;安全隐患…

Temporal Dynamic Quantization for Diffusion Models阅读

文章目录 AbstractIntroductionBackgrounds and Related Works2.1 扩散模型2.2 量化2.3 量化感知训练和训练后量化 TemporalDynamic Quantization3.1 量化方法3.2 扩散模型量化的挑战3.3 TDQ模块的实现3.4 工程细节时间步的频率编码TDQ模块的初始化 Experimental SetupResults5…

#git 问题failed to resolve head as a valid ref

问题如下&#xff1a; 解决方法&#xff1a; 1、运行 git fsck --full 可以查看具体error信息&#xff0c;一般都是head索引问题 2、.git\refs\heads\xxx&#xff08;当前分支&#xff09;txt编辑器打开显示乱码&#xff0c;而不是hash编码 3、在.git\logs\refs\heads\xxx&a…

如何评价 Python 语言的运行速度

Python 作为一门编程语言&#xff0c;其运行速度一直是业界讨论的焦点。它的简洁语法和广泛的应用使得它在开发过程中非常高效&#xff0c;然而&#xff0c;运行速度与一些更底层的编程语言相比存在一定的劣势。这是否是由于 Python 语法的简洁性所带来的代价&#xff1f;我们可…

心觉:自我暗示语“正确姿势”的科学解释

Hi&#xff0c;我是心觉&#xff0c;与你一起玩转潜意识、脑波音乐和吸引力法则&#xff0c;轻松掌控自己的人生&#xff01; 挑战每日一省写作185/1000天 “如何重塑高效学习的潜意识”这个系列文章其实昨天已经写完了 在写这个系列文章的时候&#xff0c;我突然有一个关于…

宠物空气净化器该怎么选?希喂、美的、有哈这三款有推荐的吗?

终于要到国庆了&#xff0c;这可是打工人除春节外最长的假期&#xff01;在外上班后&#xff0c;回家的次数越来越少了&#xff0c;这次国庆肯定要回去陪陪父母。这票是真难买啊&#xff0c;候补了我一个多星期才买到。本来以为最困难的问题已经解决了&#xff0c;又想到我家猫…

Mamba以及我们看的第一篇MambaOcc

0. 简介 深度学习架构有很多&#xff0c;但近些年最成功的莫过于 Transformer&#xff0c;其已经在多个应用领域确立了自己的主导地位。如此成功的一大关键推动力是注意力机制&#xff0c;这能让基于 Transformer 的模型关注与输入序列相关的部分&#xff0c;实现更好的上下文…

动手测试:CPU的L1~L3级缓存和内存的读取速度测试

引言 在许多文章中指出了这些缓存的架构&#xff0c;速度差异等。纸上得来终觉浅&#xff0c;今天想实际写代码简单测试一下。 背景 现代计算机系统中&#xff0c;CPU缓存&#xff08;L1、L2、L3&#xff09;和主内存&#xff08;RAM&#xff09;之间的读取速度有着显著的差…

数据结构之链表(2),双向链表

目录 前言 一、链表的分类详细 二、双向链表 三、双向链表的实现 四、List.c文件的完整代码 五、使用演示 总结 前言 接着上一篇单链表来详细说说链表中什么是带头和不带头&#xff0c;“哨兵位”是什么&#xff0c;什么是单向什么是双向&#xff0c;什么是循环和不循环。然后实…

U盘恢复数据工具:让数据失而复得的魔法

优盘里数据丢失无疑会给我们的工作和生活带来诸多不便。幸运的是&#xff0c;优盘数据恢复软件应运而生&#xff0c;它们如同数据的守护者&#xff0c;为我们提供了找回丢失数据的希望。这次我们就一同来探讨u盘恢复数据有什么方法吧。 1.福昕恢复数据 链接直达&#xff1a;h…