C++ day04(友元 friend、运算符重载、String字符串)

目录

【1】友元 friend

1》概念

2》友元函数 

3》友元类

 4》友元成员函数

 【2】运算符重载

1》概念

2》友元函数运算符重载

 ​编辑

 3》成员函数运算符重载

4》赋值运算符与类型转换运算符重载

 5》注意事项

【3】String 字符串类


【1】友元 friend

1》概念

定义:

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


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


作用:

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

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


分类:

1.友元函数

2.友元类

3.友元成员函数

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)
{// 突破权限,直接操作Girl类的私有成员;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;
}

 需要注意的是:

1.由于友元函数不属于成员函数,因此友元函数没有this 指针,访问类的成员的时候只能通过对象

2.友元函数在类中的“声明”可以写在类的任何部分,不受权限修饰符的影响。

3.理论上,一个友元函数可以是多个类的友元函数,只需要在各个类中分别“声明”。

3》友元类

当一个类B成为了另一个类A的友元类的时候,类B可以访问类A的所有成员。

需要注意的是:

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

    如果类B是类A的友元类,类A不一定是类B的友元类

2.友元关系不具有传递性

    如果类C是类B的友元类,类B是类A的友元类,类C不一定是类A 的友元类。

3.友元关系不能被继承

#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的私有成员a.str =  "我改了";cout << a.str << endl;}
};int main()
{A a;
//    cout << a.str << endl; 错误,全局不能调用类A的私有成员B b;b.func(a);return 0;
}

 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》友元函数运算符重载

 

#include <iostream>using namespace std;/*** @brief The Integer class 整数类*/
class Integer
{
private:int value;public:Integer(int value):value(value){}int get_value() const{return value;}// 友元函数“声明”friend Integer operator +(const Integer&,const Integer&);friend Integer operator ++(Integer&); // 前置friend Integer operator ++(Integer&,int); // 后置
};//友元函数定义
Integer operator +(const Integer& i1,const Integer& i2)
{return i1.value + i2.value; // 隐式调用构造函数
}Integer operator ++(Integer& i)
{return ++i.value; // 隐式调用构造函数
}Integer operator ++(Integer& i,int)
{return i.value++; // 隐式调用构造函数
}int main()
{Integer i1(1);Integer i2(2);Integer i3 = i1 + i2;cout << i3.get_value() << endl; // 3cout << (i1++).get_value() << endl; // 1cout << (++i1).get_value() << endl; // 3return 0;
}

 3》成员函数运算符重载

成员函数运算符重载与友元函数运算符重载的最大区别:友元函数运算符重载的第一个参数,在成员函数中使用this 指针代替,即使用成员函数重载的运算符重载相比友元函数的参数少一个。

 

#include <iostream>using namespace std;/*** @brief The Integer class 整数类*/
class Integer
{
private:int value;public:Integer(int value):value(value){}int get_value() const{return value;}// 声明成员函数Integer operator +(const Integer&); // 双目Integer operator ++(); // 前置Integer operator ++(int) // 后置{return this->value++;}
};Integer Integer::operator +(const Integer& i)
{return this->value + i.value;
}Integer Integer::operator ++()
{return ++this->value;
}int main()
{Integer i1(1);Integer i2(2);Integer i3 = i1 + i2;cout << i3.get_value() << endl; // 3cout << (i1++).get_value() << endl; // 1cout << (++i1).get_value() << endl; // 3return 0;
}

4》赋值运算符与类型转换运算符重载

如果程序员不写赋值运算符重载函数,编译器会为类自动添加一个赋值运算符重载函数,且此函数支持链式调用,因此只能使用成员函数运算符重载。

#include <iostream>using namespace std;class Value
{
public:int value = 0;// 1. 构造函数// 2. 拷贝构造// 3. 析构函数// 4. 赋值运算符重载// 编译器自动添加:Value& operator =(const Value& v){value = v.value;return *this;}
};int main()
{Value v; // 构造函数Value v2(v); // 拷贝构造Value v3 = v2; // 拷贝构造v.value = 1;v3 = v; // 赋值运算符cout << v3.value << endl; // 1return 0;
}

 类型转换运算符与赋值运算符的符号都是 = ,因此类型转换运算符重载函数比较特殊,以便于与赋值运算符重载进行区分,同样类型转换运算符重载函数也只支持成员函数运算符重载。

#include <iostream>using namespace std;class Value
{
private:int value;public:Value(int value):value(value){}int get_value() const{return value;}// 类型转换运算符重载函数operator int()//value转换为int类型{return value;}
};int main()
{// int → ValueValue v = 1; // 隐式构造// Value → intint i = v; // 类型转换运算符重载函数cout << i << endl; // 1return 0;
}

 5》注意事项

1.运算符重载限制在C++已有的运算符范围内,不能创建新的运算符。

2.运算符重载不能改变运算符的优先级、结合性、操作数和语法结构。

3.运算符重载不能改变基本类型的计算规则,只能更改包含自定义类型的计算规则。

4.运算符重载实现的功能应该与元运算符相近。

5.运算符重载函数不支持参数默认值。

6.通常单目运算符使用成员函数重载,双目运算符使用友元函数重载。

【3】String 字符串类

#include <iostream>
#include <string.h>using namespace std;int main()
{string s; // 生成一个空字符串cout << "判断字符串是否为空:" <<  s.empty() << endl; // 1string s1 = "Thursday"; // 隐式调用构造函数,参数const char*string s2("Thursday"); // 显式调用上面的构造函数cout << "判断是s1是否等于s2:" << (s1 == s2) << endl; // 1string s3 = s1; // 隐式调用拷贝构造string s4(s2); // 显式调用拷贝构造cout << "判断是s1是否等于s2:" << (s3 == s4) << endl; // 1s = s4; // 赋值运算符cout << s << endl; // "Thursday"// 参数1:const char* 原字符串// 参数2:保留几个字符string s5("ABCDEFG",2);//保留前两个字符cout << s5 << endl; // ABs = "ABCDEFG";// 参数1:string 原字符串// 参数2:不保留前几个字符string s6(s,2);cout << s6 << endl; // CDEFG// 参数1:字符串长度// 参数2:字符内容string s7(6,'A');cout << s7 << endl; // AAAAAA// 交换swap(s6,s7);cout << s6 << " " << s7 << endl; // AAAAAA CDEFGs = s6+s7; // 拼接cout << s << endl; // AAAAAACDEFG// 向后追加s.append("123");cout << s << endl; // AAAAAACDEFG123// 向后追加单字符s.push_back('%'); // AAAAAACDEFG123%// 插入// 参数1:插入的位置// 参数2:插入的内容s.insert(1,"222"); // A222AAAAACDEFG123%// 参数1:删除的起始位置// 参数2:删除的字符数s.erase(4,10);cout << s << endl; // A222123%// 参数1:替换的起始位置// 参数2:替换的字符数// 参数3:替换的内容s.replace(0,3,"******");cout << s << endl; // ******2123%s.clear(); // 清空cout << s.length() << endl; // 0char c[20];s = "1234567890";// 参数1:拷贝的目标// 参数2:拷贝的字符数// 参数3:拷贝的起始位置s.copy(c,3,1);cout << c << endl; // 234// C → C++ 直接赋值即可// char* → stringchar* c1 = "Tom";char c2[] = "Jerry";string sc1 = c1;string sc2 = c2;cout << sc1 << "&" << sc2 << endl; // Tom&Jerry// C++ → C// string → char[]s = "abcd";char ch[10];strcpy(ch,s.c_str()); // c_str()返回值的const char*不稳定cout << ch << endl;return 0;
}

今天的分享就到这里结束啦,如果有哪里写的不好的地方,请指正。
如果觉得不错并且对你有帮助的话点个关注支持一下吧! 

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

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

相关文章

YOLOv5改进——添加SimAM注意力机制

目录 一、SimAM注意力机制核心代码 二、修改common.py 三、修改yolo.py ​三、建立yaml文件 四、验证 一、SimAM注意力机制核心代码 在models文件夹下新建modules文件夹&#xff0c;在modules文件夹下新建一个py文件。这里为simam.py。复制以下代码到文件里面。 import…

吴恩达深度学习笔记:卷积神经网络(Foundations of Convolutional Neural Networks)2.7-2.8

目录 第四门课 卷积神经网络&#xff08;Convolutional Neural Networks&#xff09;第二周 深度卷积网络&#xff1a;实例探究&#xff08;Deep convolutional models: case studies&#xff09;2.7 Inception 网络&#xff08;Inception network&#xff09;2.8 使 用 开 源 …

【Linux】 TCP短服务编写和守护进程

文章目录 TCP 短服务编写流程进程组和会话和守护进程 TCP 短服务编写流程 TCP服务器是面向连接的&#xff0c;客户端在发送数据之前需要先与服务器建立连接。 因此&#xff0c;TCP服务器需要能够监听客户端的连接请求。为了实现这一功能&#xff0c;需要将TCP服务器创建的套接字…

75. 颜色分类

思路 先排最小的数&#xff0c;将最小的数都放至列表前面 则0~r-1都是最小值 从r到len(nums)-1继续进行排序&#xff0c;从尾部开始&#xff0c;将最大值放置尾部 class Solution(object):def sortColors(self, nums):""":type nums: List[int]:rtype: None …

Python | Leetcode Python题解之第468题验证IP地址

题目&#xff1a; 题解&#xff1a; class Solution:def validIPAddress(self, queryIP: str) -> str:if queryIP.find(".") ! -1:# IPv4last -1for i in range(4):cur (len(queryIP) if i 3 else queryIP.find(".", last 1))if cur -1:return &q…

Window系统编程 - 文件操作

前言 各位师傅大家好&#xff0c;我是qmx_07&#xff0c;今天主要介绍使用windows系统编程操作读写文件 文件 CreateFile()函数讲解 介绍:该函数用于打开文件或者I/O流设备&#xff0c;文件、文件流、目录、物理磁盘、卷、控制台缓冲区、磁带驱动器、通信资源、mailslot 和…

Jenkins Pipline流水线

提到 CI 工具&#xff0c;首先想到的就是“CI 界”的大佬--]enkjns,虽然在云原生爆发的年代,蹦出来了很多云原生的 CI 工具,但是都不足以撼动 Jenkins 的地位。在企业中对于持续集成、持续部署的需求非常多,并且也会经常有-些比较复杂的需求,此时新生的 CI 工具不足以支撑这些很…

看门狗电路设计

看门狗电路设计 看门狗是什么应用架构图TPV6823芯片功能硬件时序图为什么要一般是要保持200个毫秒左右的这种低电平的时间看门狗电路实际应用与条件 看门狗是什么 硬件看门狗芯片&#xff0c;Watch DogTimer&#xff0c;可用于受到电气噪音、电源故障、静电放电等影响(造成软件…

LSTM(长短时记忆网络)

一、引言 在处理序列数据时&#xff0c;循环神经网络&#xff08;RNN&#xff09;虽然能够处理序列数据并保留历史信息&#xff0c;但在实践中发现它对于捕捉长时间依赖关系的能力有限&#xff0c;尤其是在训练过程中容易遇到梯度消失或梯度爆炸的问题。为了解决这些问题&…

力扣1031. 两个非重叠子数组的最大和

力扣1031. 两个非重叠子数组的最大和 题目解析及思路 题目要求找到两段长分别为firstLen 和 secondLen的子数组&#xff0c;使两段元素和最大 图解见灵神 枚举第二段区间的右端点&#xff0c;在左边剩余部分中找出元素和最大的第一段区间&#xff0c;并用前缀和优化求子数组…

Nginx基础详解5(nginx集群、四七层的负载均衡、Jmeter工具的使用、实验验证集群的性能与单节点的性能)

续Nginx基础详解4&#xff08;location模块、nginx跨域问题的解决、nginx防盗链的设计原理及应用、nginx模块化解剖&#xff09;-CSDN博客 目录 14.nginx集群&#xff08;前传&#xff09; 14.1如何理解单节点和集群的概念 14.2单节点和集群的比较 14.3Nginx中的负载均衡…

对象的概念

对象是编程中一个重要的概念&#xff0c;尤其在面向对象编程&#xff08;OOP&#xff09;中更为核心。简单来说&#xff0c;对象是一种数据结构&#xff0c;它可以存储相关的数据和功能。以下是关于对象的详细描述&#xff1a; 1. 对象的定义 对象是属性&#xff08;数据&…

QT入门教程攻略 QT入门游戏设计:贪吃蛇实现 QT全攻略心得总结

Qt游戏设计&#xff1a;贪吃蛇 游戏简介 贪吃蛇是一款经典的休闲益智类游戏&#xff0c;玩家通过控制蛇的移动来吃掉地图上的食物&#xff0c;使蛇的身体变长。随着游戏的进行&#xff0c;蛇的移动速度会逐渐加快&#xff0c;难度也随之增加。当蛇撞到墙壁或自己的身体时&…

深入探讨JavaScript中的精度问题:原理与解决方案

深入探讨JavaScript中的精度问题&#xff1a;原理与解决方案 在日常的JavaScript开发中&#xff0c;我们经常会遇到一些令人困惑的数值计算问题&#xff0c;特别是涉及到小数点运算时。例如&#xff0c;为什么0.1 0.2的结果不是预期的0.3&#xff0c;而是0.30000000000000004…

Laravel Filament 如何配置多语言支持

演示 一、安装拓展包outerweb/filament-translatable-fields composer require outerweb/filament-translatable-fields配置模型 该套件包含一个名为 HasTranslations 的特性&#xff0c;用于使 Eloquent 模型具备多语言功能。翻译值以 JSON 格式存储&#xff0c;并不需要额外…

Run the FPGA VI 选项的作用

Run the FPGA VI 选项的作用是决定当主机 VI 运行时&#xff0c;FPGA VI 是否会自动运行。 具体作用&#xff1a; 勾选 “Run the FPGA VI”&#xff1a; 当主机 VI 执行时&#xff0c;如果 FPGA VI 没有正在运行&#xff0c;系统将自动启动并运行该 FPGA VI。 这可以确保 FPG…

夜间数据库IO负载飙升?MySQL批量删除操作引发的问题排查

目录 问题现象 问题分析 修改建议 总结 问题现象 近日&#xff0c;某用户反馈他们的MySQL数据库实例在凌晨时段会频繁出现IO负载急剧上升的情况&#xff0c;这种状态会持续一段时间&#xff0c;随后自行恢复正常。为了查明原因&#xff0c;该用户通过DBdoctor工具收集了相…

js进阶——深入解析JavaScript中的URLSearchParams

深入解析 JavaScript 中的 URLSearchParams 在现代Web开发中&#xff0c;我们经常需要处理URL中的查询参数&#xff0c;尤其是在构建动态Web应用时。这些查询参数&#xff08;query parameters&#xff09;通常以 ?keyvalue&key2value2 的形式存在。JavaScript 提供了一个…

javascript:void(0)

javascript:void(0)是一种常用于HTML中的Javascript语句&#xff0c;通常用作链接的href属性。它的主要作用是防止链接的默认行为(例如跳转到一个新页面或刷新当前页面)&#xff0c;同时又可以执行一些Javascript代码 详细解释 javascript&#xff1a;这是一个协议&#xff0c…

第十三章 Redis短信登录实战(基于Redis)

目录 一、概述 1.1. Session复制 1.2. 使用Redis 二、基于Redis实现共享Session登录 2.1. 实现思路 2.2. 功能实现的主要代码 2.2.1. 用户业务接口 2.2.2. 用户业务接口实现类 2.2.3. 用户控制层 2.2.4. 登录拦截器 2.2.5. 拦截器配置类 2.3. 优化登录拦截器 完…