C++友元和运算符重载

目录

一. 友元 friend

1.1 概念

1.2 友元函数

1.3 友元类

1.4 友元成员函数

二. 运算符重载

2.1 概念

2.2成员函数运算符重载

2.3 成员函数运算符重载

2.4 特殊运算符重载

2.4.1 赋值运算符重载

2.4.2 类型转换运算符重载

2.5 注意事项

三、std::string 字符串类(熟悉)


一. 友元 friend

1.1 概念

定义:

        类实现了数据的隐藏与封装,类的数据成员一般定义为私有成员,仅能通过类的成员函数才能读写。如果数据成员定义为公共的,则又破坏了封装性。但是某些情况下,需要频繁读写类的成员,特别是在对某些成员函数多次调用时,由于参数传递、类型检查和安全性检查等都需要时间开销,而影响程序的运行效率。

        友元是一种定义在类外部的普通函数,但他需要在类体内进行说明,为了和该类的成员函数加以区别,在说明时前面加以关键字friend。友元不是成员函数,但是他能够访问类中的所有成员

作用:

        在于提高程序的运行效率,但是,他破坏了类的封装性和隐藏性,使得非成员函数能够访问类的私有成员。导致程序维护性变差,因此使用友元要慎用。

友元较为实际的应用是在运算符重载,这种应用可以提高软件系统的灵活性。

分类:

● 友元函数

● 友元类

● 友元成员函数

1.2 友元函数

友元函数是一种“声明”在类内,实际在类外的普通函数

#include <iostream>using namespace std;class Girl
{
private:int age;public:Girl(int age):age(age){}int get_age() const{cout << &age << endl;return 18;}// 1. "声明"友元函数friend void access_true_age(Girl&);
};// 2. 定义友元函数
void access_true_age(Girl& g)
{// 突破权限cout << &g.age << endl;cout << "真实年龄:" << g.age << endl;// 修改g.age = 18;cout << "修改后年龄:" << g.age << endl;
}int main()
{Girl g(45);cout << g.get_age() << endl;// 通过友元函数访问Girl的年龄access_true_age(g);return 0;
}
需要注意的

● 由于属于成员函数因此友元函数没有this指针访问成员只能通过对象

● 友元函数中的声明”可以写在任何部分不受权限修饰符影响

● 理论上一个友元函数可以多个友元函数只需要在各个分别声明”

1.3 友元

一个B成为另一个A友元B可以访问A所有成员

需要注意的

● 友元关系单向的不具有交换性

如果BA友元类A不一定B友元类

● 友元关系不具有传递性

如果CB友元类BA友元类C不一定A友元类

● 友元关系不能被继承

#include <iostream>using namespace std;class A
{
private:string str = "A私有";// “声明”友元类friend class B;
};class B
{
public:void func(A& a){
//        cout << this->str << endl; 错误:this是B对象不是A对象cout << a.str << endl;a.str =  "我改了";cout << a.str << endl;}
};int main()
{A a;
//    cout << a.str << endl; 错误B b;b.func(a);return 0;
}

1.4 友元成员函数

友元类任何成员函数都可以访问其他成员但是友元成员函数友元范围限制一个成员函数

例如,类B某个成员函数称为A友元成员函数这样B成员函数可以访问A所有成员

#include <iostream>using namespace std;// 3. 因为第二步中用到了类A,提前声明类A
class A;// 2. 编写类B,并真正声明友元成员函数
class B
{
public:void func(A&);
};class A
{
private:string str = "A私有";// 1. 确定友元的函数格式并“声明”friend void B::func(A&);
};// 4. 类外定义友元成员函数
void B::func(A & a)
{//  cout << this->str << endl; 错误:this是B对象不是A对象cout << a.str << endl;a.str =  "我改了";cout << a.str << endl;
}int main()
{A a;//    cout << a.str << endl; 错误B b;b.func(a);return 0;
}

二. 运算符重载

2.1 概念

如果运算符看做一个函数运算符也可以函数一样重载

C++中预定义的运算符的操作对象只能是基本数据类型。但实际上对于很多用户的自定义类型,也需要类似的运算操作、这时可以在C++中重新定义这些运算符,赋予已有运算符新的功能,使它能够用于特定类型,执行特定的操作。

可以被重载的运算符:

算术运算符:+、-、*、/、%、++、--

位操作运算符:&、|、~、^(位异或)、<<(左移)、>>(右移)

逻辑运算符:!、&&、||

比较运算符:<、>、>=、<=、==、!=

赋值运算符:=、+=、-=、*=、/=、%=、&=、|=、^=、<<=、>>=

其他运算符:[]、()、->、,、new、delete、new[]、delete[]

不被重载的运算符:

成员运算符“.”、指针运算符“*”、三目运算符“? :”、sizeof、作用域“::”

2.2成员函数运算符重载

#include <iostream>
using namespace std;class MyInt
{
private:int a;
public:MyInt(int a):a(a){}int get_int(){return a;}// + 运算符重载friend MyInt operator +(MyInt &i,MyInt &i2);friend MyInt operator ++(MyInt &i); // 前置自增friend MyInt operator ++(MyInt &i, int);    // 后置自增
};// 友元函数 实现
MyInt operator +(MyInt &i,MyInt &i2)
{// int → MyInt 触发构造函数隐式调用return i.a + i2.a;
}// 前置自增
MyInt operator ++(MyInt &i)
{return ++i.a;
}// 后置自增
MyInt operator ++(MyInt &i, int)
{return i.a++;
}int main()
{MyInt int1(2);MyInt int2(int1);   // 拷贝构造函数MyInt int3 = int1 + int2;cout << (int3++).get_int() << endl; // 4cout << int3.get_int() << endl; // 5return 0;
}

2.3 成员函数运算符重载

成员函数运算符重载相比于友元函数重载,最主要的区别在于,友元函数的第一个输出参数,在成员函数运算符重载中使用this指针代替。因此相同的运算符重载,成员函数运算符重载比友元函数运算符重载参数少一个。

#include <iostream>
using namespace std;class MyInt
{
private:int a;
public:MyInt(int a):a(a){}int get_int(){return a;}MyInt operator +(MyInt &i2);MyInt operator ++();MyInt operator ++(int);
};// 成员函数 类外实现
MyInt MyInt::operator +(MyInt &i2)
{// int → MyInt 触发构造函数隐式调用return this->a + i2.a;
}// 前置自增
MyInt MyInt::operator ++()
{return ++this->a;
}// 后置自增
MyInt MyInt::operator ++(int)
{return this->a++;
}int main()
{MyInt int1(2);MyInt int2(int1);   // 拷贝构造函数MyInt int3 = int1 + int2;cout << (++int3).get_int() << endl;cout << int3.get_int() << endl;return 0;
}

2.4 特殊运算符重载

2.4.1 赋值运算符重载

除了之前学习的无参构造函数、拷贝构造函数、析构函数以外,如果程序员不手写,编译器就会给一个类添加赋值运算符重载函数。

#include <iostream>
using namespace std;class MyInt
{
private:int a;
public:MyInt(int a):a(a){}int get_int(){return a;}// 编译器会自动添加赋值运算符重载函数MyInt & operator =(MyInt &i){cout << "赋值运算符被调用了" << endl;    // 编译器自动添加的赋值运算符重载函数不会打印这句话this->a = i.a;return *this;}
};int main()
{MyInt int1(2);MyInt int4(3);cout << int4.get_int() << endl;int4 = int1;    // 赋值运算符重载cout << int4.get_int() << endl;return 0;
}

当类中出现指针成员变量时,默认的赋值运算符重载函数会出现类似于浅拷贝构造函数的问题,因此也需要手动编写解决“浅拷贝”的问题。

【面试题】一个类什么都不写,编译器添加了那些代码?

无参构造函数、拷贝构造函数、析构函数、赋值运算符重载函数

2.4.2 类型转换运算符重载

必须使用成员函数运算符重载,且格式比较特殊。

#include <iostream>
using namespace std;class MyInt
{
private:int a;string str = "hello";
public:MyInt(int a):a(a){}int get_int(){return a;}// 编译器会自动添加赋值运算符重载函数MyInt & operator =(MyInt &i){cout << "赋值运算符被调用了" << endl;    // 编译器自动添加的赋值运算符重载函数不会打印这句话this->a = i.a;return *this;}// 类型转换运算符重载operator int(){return a;}operator string(){return str;}
};int main()
{MyInt int1(2);int a = int1;string str = int1;cout << a << endl;cout << str << endl;return 0;
}

2.5 注意事项

● 重载的运算符限制在C++语言中已有的运算符范围,不能创建新的运算符。

● 运算符重载的本质也是函数重载,但是不支持函数参数默认值设定。

● 重载之后的运算符不能改变运算符的优先级和结合性,也不能改变运算符的操作数和语法结构。

● 运算符重载必须基于或包含自定义类型,即不能改变基本数据类型的运算符规则。

● 重载功能应该与原有功能类似,避免没有目的的滥用运算符重载。

● 一般情况下,双目运算符建议使用友元函数进行重载,单目运算符建议使用成员函数进行重载。

三、std::string 字符串类(熟悉)

字符串对象是一个特殊类型的容器,专门设计用于操作字符串。

#include <iostream>
#include <string.h>
using namespace std;int main()
{string s;   // 创建一个空字符串// 判断是否为空cout << s.empty() << endl;  // 1// 隐式调用构造函数string s1 = "hello";cout << s1 << endl; // hello// 显式调用构造函数,等同于上面写法string s2("world");cout << s2 << endl;// ==、!=、<、> 都是判断编码cout << (s1 == s2) << endl; // 0cout << (s1 != s2) << endl; // 1cout << (s1 > s2) << endl;  // 0cout << (s1 < s2) << endl;  // 1// 拷贝构造函数string s3(s2);  // string s3 = s2;cout << s3 << endl;// 参数1:char *源字符串// 参数2:保留的字符数string s4("ABCDEFG",3);cout << s4 << endl; // ABC// 参数1:std::string 源字符串// 参数2:不保留的字符数string s5(s2,3);cout << s5 << endl; // ld// 参数1:字符的数量// 参数2:字符的内容charstring s6(5,'a');cout << s6 << endl; // aaaaa// 交换cout << "原s5=" << s5 << " " << "原s6=" << s6 << endl;    // 原s5=ld 原s6=aaaaaswap(s5,s6);cout << "s5=" << s5 << " " << "s6=" << s6 << endl;  // s5=aaaaa s6=ld// 字符串拼接、连接string s7 = s5 + s6;cout << s7 << endl; // aaaaald// 向后追加字符串s7.append("jiajia");cout << s7 << endl; // aaaaaldjiajia// 向后追加单字符s7.push_back('s');cout << s7 << endl; // aaaaaldjiajias// 插入// 参数1:插入的位置// 参数2:插入的内容s7.insert(1,"234");cout << s7 << endl; // a234aaaaldjiajias// 删除字符串// 参数1:起始位置// 参数2:删除的字符数量s7.erase(2,5);cout << s7 << endl; // a2aldjiajias// 替换// 参数1:起始位置// 参数2:被替换的字符数// 参数3:替换的新内容s7.replace(0,3,"***");cout << s7 << endl; // ***ldjiajias// 清空s7.clear();cout << s7.length() << endl;    // 0// 直接赋值初始化(隐式调用构造函数)string s8 = "hahaha";cout << s8 << endl;// 重新赋值s8 = "ABCDEFGH";cout << s8 << endl; // ABCDEFGH// 参数1:拷贝的目标// 参数2:拷贝的字符数量// 参数3:拷贝的起始位置char arr[20] = {0};s8.copy(arr,6,1);cout << arr << endl;    // BCDEFG// C++string 到 c string 用到了C语言的strcpy// c_str C++的字符串转换成C语言的字符数组// c_str返回值类型是一个const char*char c[20] = {0};strcpy(c,s8.c_str());cout << c <<endl;   // ABCDEFGHreturn 0;
}

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

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

MyBatis-Plus分页查询

在实际开发中&#xff0c;对于大量数据的查询&#xff0c;可以通过分页查询的方式来减少查询量和提高查询效率。在 MyBatis-Plus 中&#xff0c;分页查询可以通过使用 Page 对象和 IService 接口提供的分页方法来实现。MyBatis-Plus 的分页插件 PaginationInnerInterceptor 提供…

基于Spring框架的分层解耦详解

博客主页&#xff1a;誓则盟约系列专栏&#xff1a;Java Web关注博主&#xff0c;后期持续更新系列文章如果有错误感谢请大家批评指出&#xff0c;及时修改感谢大家点赞&#x1f44d;收藏⭐评论✍ Java Web 三层架构&#xff1a; Java Web可以大致被分为三层架构&#xff1a;…

Win11 安装 PostgreSQL 数据库,两种方式详细步骤

文章目录 一、exe文件安装 &#xff08;推荐&#xff09;下载安装包1. 选择操作系统2. 跳转到EDB&#xff08;PostgreSQL 的安装包托管在 EDB上&#xff09;3. 选择版本点击下载按钮 安装1. 管理员打开安装包2. 选择安装目录3. 勾选安装项4. 设置数据存储目录5. 设置管理员密码…

【C++报错已解决】std::ios_base::floatfield

&#x1f3ac; 鸽芷咕&#xff1a;个人主页 &#x1f525; 个人专栏: 《C干货基地》《粉丝福利》 ⛺️生活的理想&#xff0c;就是为了理想的生活! 专栏介绍 在软件开发和日常使用中&#xff0c;BUG是不可避免的。本专栏致力于为广大开发者和技术爱好者提供一个关于BUG解决的经…

YOLOv8改进,YOLOv8主干网络替换为GhostNetV3(2024年华为提出的轻量化架构,全网首发),助力涨点

摘要 GhostNetV3 是由华为诺亚方舟实验室的团队发布的,于2024年4月发布。 摘要:紧凑型神经网络专为边缘设备上的应用设计,具备更快的推理速度,但性能相对适中。然而,紧凑型模型的训练策略目前借鉴自传统模型,这忽略了它们在模型容量上的差异,可能阻碍紧凑型模型的性能…

如何用ChatGPT制作一款手机游戏应用

有没有想过自己做一款手机游戏&#xff0c;并生成apk手机应用呢&#xff1f;有了人工智能&#xff0c;这一切就成为可能。今天&#xff0c;我们就使用ChatGPT来创建一个简单的井字棋游戏&#xff08;Tic-Tac-Toe&#xff09;&#xff0c;其实这个过程非常轻松且高效。 通过Cha…

从哪里下载高清解压视频素材?推荐五个优质素材资源网站

想制作吸引人的抖音小说推文&#xff0c;但不知道从哪里获取高清解压视频素材&#xff1f;今天就为大家推荐五个优秀的网站&#xff0c;帮助你轻松找到所需的素材&#xff0c;提升你的创作质量。 首先是蛙学网 作为国内顶级的短视频素材网站&#xff0c;蛙学网提供了丰富的4K高…

浅谈java异常[Exception]

一&#xff0e; 异常的定义 在《java编程思想》中这样定义 异常&#xff1a;阻止当前方法或作用域继续执行的问题。虽然java中有异常处理机制&#xff0c;但是要明确一点&#xff0c;决不应该用"正常"的态度来看待异常。绝对一点说异常就是某种意义上的错误&#xf…

SpringBoot使用validation进行自参数校验

一&#xff1a;介绍 在 SpringBoot 项目开发中&#xff0c;很多与数据库交互的参数需要校验数据正确性。很多小伙伴会把参数判断写进代码里&#xff0c;但是这种写法往往会有低可读性以及多处使用的时候&#xff0c;需要变更验证规则时&#xff0c;不易于维护等缺点。今天给大家…

Java之多态

文章目录 1. 多态1.1 多态的概念 2. 方法的重写3. 向上转型3.13.2 发生向上转型的时机 4. 动态绑定和静态绑定5. 什么是多态5.15.2 多态的优缺点 6. 避免在构造方法中调用重写的方法7. 向下转型![在这里插入图片描述](https://i-blog.csdnimg.cn/direct/fd1fa83140d94f37ab3b88…

HTML+CSS 水滴登录页

文章目录 一、效果演示二、Code1.HTML2.CSS 三、实现思路拆分 一、效果演示 实现了一个水滴登录页的效果。页面包含一个水滴形状的登录框和两个按钮&#xff0c;登录框包括用户名、密码和登录按钮&#xff0c;按钮分别为忘记密码和注册。整个页面的设计非常有创意&#xff0c;采…

一些超好用的 GitHub 插件和技巧

聊聊我平时使用 GitHub 时学到的一些插件、技巧。 ‍ ‍ 浏览器插件 在我的另一篇博客 浏览器插件推荐 里提到过跟 GitHub 相关的一些插件&#xff0c;这里重复下&#xff1a; Sourcegraph&#xff1a;在线打开项目&#xff0c;方便阅读&#xff0c;将 GitHub 变得和 IDE …

【AI创作组】Matlab中进行符号计算

提示:代码一定要自己运行过才算数…… 1. 符号计算工具箱介绍 1.1 工具箱功能 MATLAB的符号计算工具箱,即Symbolic Math Toolbox,是一套强大的数学软件工具,它使得MATLAB具备了符号运算的能力。该工具箱提供了一系列函数,用于求解、绘制和操作符号数学方程。用户可以直接…

【Linux】修改用户名用户家目录

0、锁定旧用户登录 如果旧用户olduser正在运行中是无法操作的&#xff0c;需要先禁用用户登录&#xff0c;然后杀掉所有此用户的进程。 1. 使用 usermod 命令禁用用户 这将锁定用户账户&#xff0c;使其无法登录&#xff1a; sudo usermod -L olduser2. 停止用户的进程 如…

Woocommerce怎么分类显示产品?如何将Shopify的产品导入到Woocommerce?

WooCommerce作为WordPress的一个电子商务插件&#xff0c;功能强大、使用简洁&#xff0c;能够轻松集成到WordPress网站中&#xff0c;为用户提供了一个完整的在线商店解决方案&#xff0c;在国外还是挺受欢迎的。 Woocommerce怎么分类显示产品&#xff1f; 在Woocommerce中&a…

【微服务】springboot 实现动态修改接口返回值

目录 一、前言 二、动态修改接口返回结果实现方案总结 2.1 使用反射动态修改返回结果参数 2.1.1 认识反射 2.1.2 反射的作用 2.1.3 反射相关的类 2.1.4 反射实现接口参数动态修改实现思路 2.2 使用ControllerAdvice 注解动态修改返回结果参数​​​​​​​ 2.2.1 注解…

docker pull 超时的问题如何解决

docker不能使用&#xff0c;使用之前的阿里云镜像失败。。。 搜了各种解决方法&#xff0c;感谢B站UP主 <iframe src"//player.bilibili.com/player.html?isOutsidetrue&aid113173361331402&bvidBV1KstBeEEQR&cid25942297878&p1" scrolling"…

已解决:“ModuleNotFoundError:No module named apex”

首先遇到这个问题不可以直接简单粗暴的使用&#xff1a;“pip install apex”直接安装模块来解决&#xff0c;这样的话程序还是会继续报错“ModuleNotFoundError&#xff1a;No module named apex”&#xff0c;别问我怎么知道&#xff0c;问就是深受其害&#xff01; 去网上查…

基于pdf.js实现对pdf预览、批注功能、 保存下载pdf,适配H5,平板 踩坑记录

项目场景&#xff1a; 在APP端实现对pdf的批注,能够下载保存.能够获取批注信息同时能够重新渲染到pdf中.基于pdf.js-4.5.136版本源码实现。pc端能够正常预览下载pdf&#xff0c;构建打包后嵌入uniapp的webview遇到的问题记录 问题描述 将构建打包后的代码嵌入到uniapp中&…

ELK-03-skywalking监控linux系统

文章目录 前言一、下载node_exporter二、启动node_exporter三、下载OpenTelemetry Collector四、启动OpenTelemetry Collector4.1 将配置文件下载到同级目录4.2 启动 五、查看总结 前言 skywalking安装完成后&#xff0c;开始我们的第一个监控-监控linux系统。 参考官方文档&a…