一.友元

C++中使用关键字friend可以在类外访问所有的成员,包括私有成员(之前提到过封装的核心思想是隐藏内部实现细节,通过公共接口控制访问),所以友元可以突破封装的限制访问数据,盲目使用会导致程序稳定性降低,所以使用友元必须慎重。

友元分类:

        友元函数

        友元类

        友元成员函数

1.友元函数

全局函数访问私有成员,可以配合运算符重载使用,友元函数是一种在类内“声明”,类外定义的非成员函数,但是没访问类内所有的成员。友元函数可以做到修改私有成员变量

注意:

(1)友元函数没有this指针。

(2)友元函数可以在类的私有部分,也可以在类的公有部分。
(3)一个函数可以是多个类的友元函数,只需要在不同的类汇中声明。

#include <iostream>
#include <string>using namespace std;class Techer{
private:int age = 45;string name = "zhangsna";
public:Techer(int age,string name):age(age),name(name){}//Techer():age(45),name("lisi"){}int get_age()const{return age;}string get_name()const{return name;}void print()const{cout << get_age() << endl;cout << get_name() << endl;}int print_age(){return 18;}friend void print_real_age(Techer &t);                //类内声明友元函数
};void print_real_age(Techer &t){                            //类外定义友元函数cout << "真实年龄:" << t.age << endl;cout << "虚假年龄:" << t.print_age() << endl;t.age = 30;cout << "修改年龄:" << t.age << endl;
}int main (){Techer t1(34,"zhangsan");cout << t1.print_age() << endl;print_real_age(t1);return 0;
}

2.友元类

当B是A的友元类时,类B就可以访问类A的所有成员,

需要注意的是:

        (1)友元类不具备交换性:A声明B为友元 → B可访问A的私有成员,但A不能访问B的私有成员。

        (2)友元类不具备传递性:A是B的友元,B是C的友元 → A不是C的友元。

        (3)友元类不具备继承性:基类友元不会继承给派生类。

#include <iostream>
#include <string>using namespace std;class Techer{
private:int age = 45;string name = "zhangsna";
public:Techer(int age,string name):age(age),name(name){}//Techer():age(45),name("lisi"){}int get_age()const{return age;}string get_name()const{return name;}void print()const{cout << get_age() << endl;cout << get_name() << endl;}int print_age(){return 18;}friend class student;
};class Student{
public:void get_name(Techer &t){cout << t.get_name() << endl;}
};int main (){Techer t1(34,"zhangsan");Student s1;s1.get_name(t1);return 0;
}

 友元成员函数

#include <iostream>
#include <string>using namespace std;class Techer; //声明类class Student{
public:void print_name(Techer &t);
};class Techer{
private:int age = 45;string name = "zhangsna";
public:Techer(int age,string name):age(age),name(name){}//Techer():age(45),name("lisi"){}int get_age()const{return age;}string get_name()const{return name;}void print()const{cout << get_age() << endl;cout << get_name() << endl;}int print_age(){return 18;}friend void Student::print_name(Techer &t);           //1.友元声明
};//4.实现友元函数
void Student::print_name(Techer &t){cout << t.get_name() <<endl;
}int main (){Techer t1(34,"zhangsan");Student s1;s1.print_name(t1);return 0;
}

二.函数运算符重载

C++中函数是可以重载的运算符也是一种特殊的函数,也可以重载,这样一来,本来只能基本数据类型能做的加减乘除也可以让对象直接加减乘除。

函数的三要素是:函数名,参数和返回值。

下面就是C++中运算符+含义,所以我们对+函数进行重载,就可以实现对象之间相加。

可以被重载的运算符:(了解)
        算术运算符: +、-、*、人、%、++、--
        位操作运算符:&、|、~、^(位异或)、<<(左移)、>>(右移)
        逻辑运算符:!、&&、
        比较运算符:<、>、>=、《=、==、!=
        赋值运算符:=、+=、-=、*=、/=、%=、&=、 I=、^=、《<=、>>=
        其他运算符:范、0、->、、new、delete、new[、delete[
不被重载的运算符:
        成员运算符""、指针运算符“*”、三目运算符"?:“、sizeof、作用域""

1.使用友元函数运算符重载

函数名:+

参数:const Integer &i1和const Integer &i2

返回值:Inteder

    friend Integer operator +(const Integer &i1,const Integer &i2);
#include <iostream>
#include <string>using namespace std;class Integer{
private:int value;
public:Integer(int value):value(value){}int get_value()const{return value;}void set_value(int a){value = a;}friend Integer operator +(const Integer &i1,const Integer &i2);friend Integer operator ++(Integer &i);friend Integer operator ++(Integer &i,int);
};Integer operator +(const Integer &i1,const Integer &i2){return i1.value + i2.value;                //返回两个int类型,这个时候编译器会自动帮你创建一个Integer类型的副本,类似于:return Integer(i1.value + i2.value);
}
Integer operator ++(Integer &i){return ++i.value;
}
Integer operator ++(Integer &i,int){return i.value++;
}int main (){Integer i1(3);Integer i2(4);Integer i3 = i1 + i2;cout << i3.get_value() << endl;++i3;cout << (i3++).get_value() << endl;cout << i3.get_value() << endl;return 0;
}

2.使用成员函数运算符重载

简单三步实现:(投机取巧的方式)

        (1).把友元函数实现的代码的friend去掉

        (2).再把所有传入的第一个参数去掉,函数内使用this指针替换(不加也可以,编译器自动识别)

        (3).在函数名前加上作用域限定符(Integer::)

正常直接写,就是写成员函数的步骤。

#include <iostream>
#include <string>using namespace std;class Integer{
private:int value;
public:Integer(int value):value(value){}int get_value()const{return value;}void set_value(int a){value = a;}Integer operator +(const Integer &i);Integer operator ++();Integer operator ++(int);
};Integer Integer::operator +(const Integer &i){return value + i.value;
}
Integer Integer::operator ++(){return ++value;
}
Integer Integer::operator ++(int){return value++;
}int main (){Integer i1(3);Integer i2(4);Integer i3 = i1 + i2;cout << i3.get_value() << endl;++i3;cout << (i3++).get_value() << endl;cout << i3.get_value() << endl;return 0;
}

3.特殊运算符重载

3.1复制运算符重载

如果程序员不手写赋值运算符重载函数,则编译器会自动为每个类增加一个赋值运算符重载函数。

在 C++ 中,赋值运算符(operator=必须被重载为类的成员函数,而不能作为友元函数或全局函数。这一设计决策源于 C++ 语言的核心特性:

(1)、根本原因:语言规范要求

C++ 标准(ISO/IEC 14882)明确规定:赋值运算符(=)必须被声明为类的非静态成员函数这是语言规范层面的硬性规定,违反此规则将导致编译错误。

(2)、技术原因:this 指针机制
1. 成员函数的隐式 this 指针
  • 成员函数自动获得隐式 this 指针,指向调用对象

  • 赋值操作需要修改左操作数的状态,this 提供直接访问

2. 友元函数缺少 this 指针
  • 友元函数没有隐式 this 指针

  • 必须显式声明两个参数(左操作数和右操作数)

  • 违反赋值运算符的二元操作符语法形式

#include <iostream>
#include <string>using namespace std;class String{
private:string str;
public:String(string str):str(str){}string get_str(){return str;}void set_str1(string str){this->str = str;}String& operator =(const String& a){        //系统默认自带的this->str = a.str;return *this;}
};int main (){String s1("hello ");String s2("world");s1 = s2;cout << s1.get_str() << endl;return 0;
}

3.2类型转换运算符重载

如果我们想把string类型转换为成员变量,如果正好你的成员变量只有一个string类型的成员变量,这个时候编译器会自动帮你赋值优化,String s1 = name;就不会报错,但是你要是想把s1对象赋值给string类型的name,这个时候编译器就无法识别,需要使用成员函数进行重载。

可以把注释的部分去掉,错误就没了,注视部分就是类型转换重载。

#include <iostream>
#include <string>using namespace std;class String{
private:string str;
public:String(string str):str(str){}string get_str(){return str;}void set_str1(string str){this->str = str;}/*operator string(){return str;}*/
};int main (){String s1("hello ");String s2("world");s1 = s2;string name = s1;cout << name << endl;cout << s1.get_str() << endl;return 0;
}

4.注意:

1.重载的运算符只能对C++语言中已有的运算符进行操作,不能创建新的运算符;

2.运算符重载也是函数重载;

3.运算符不能改变运算符的优先级(*的优先级比+大,不能改变)和结合性(a*b就是a*b不能ab*运算),也不能改变操作数和语法结构;

4.运算符重载函数不支持默认参数,即运算符的操作数数量固定(如二元运算符需要两个操作数)

5.运算符重载函数的操作数中一定包含自定义类型(运算符重载函数的操作数中必须至少有一个是用户定义类型

三.string字符串常用手册

C++函数手册:

通过网盘分享的文件:C++函数手册 (LibraryFunctions).chm
链接: https://pan.baidu.com/s/17gE3aR6VQhQQ10tBZNFfHg 提取码: 3589

#include <iostream>
#include <string.h>using namespace std;int main()
{string s1 = "ABC";// 隐式调用了下面的,参数为const char*string s2("ABC");string s3 = s2; // 拷贝构造函数cout << s3 << endl; // ABC// 参数1:const char*// 参数2:保留前几个字符string s4("ABCDE",2);cout << s4 << endl; // ABs1 = "ABCDE";// 参数1:string// 参数2:不保留前几个字符string s5(s1,2);cout << s5 << endl; // CDE// 参数1:字符数量// 参数2:字符内容string s6(3,'Z');cout << s6 << endl; // ZZZswap(s5,s6);cout << s5 << " " << s6 << endl; // ZZZ CDE// 向后追加字符串cout << s1.append("...").append(s5) << endl;// 向后追加单字符s6.push_back('O');cout << s6 << endl; // CDEO// 参数1:插入的位置// 参数2:插入的内容s6.insert(1,"222");cout << s6 << endl;// 参数1:删除的起始位置// 参数2:删除的字符数s6.erase(1,3);cout << s6 << endl;// 参数1:替换的起始位置// 参数2:替换的字符数// 参数3:替换的字符s6.replace(0,3,"xxxxxxx");cout << s6 << endl;s6.clear(); // 清空// 判断是否为空cout << s6.empty() << endl; // 1char c[20];s6 = "ABCDEFG";// 参数1:拷贝的目标// 参数2:拷贝的字符数// 参数3:拷贝的起始点s6.copy(c,2,3);cout << c << endl;char c2[20];s6 = "ABCDEFG";// c_str返回的char*指向一个内部数组,相对不可控cout << s6.c_str() << endl;// 因此需要拷贝出来strcpy(c2,s6.c_str());cout << c2 << endl;return 0;
}

练完后会不会有个疑问,为什么string有这么多操作,之前说过他不是基本数据类型,因为它就是C++中定义好的类。

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

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

相关文章

XR-RokidAR-UXR3.0-Draggable 脚本解析

using System.Collections.Generic; using Rokid.UXR.Utility; using UnityEngine; using UnityEngine.EventSystems;namespace Rokid.UXR.Interaction {/// <summary>/// Draggable 拖拽组件/// </summary>// [RequireComponent(typeof(RayInteractable))]public …

GitHub 趋势日报 (2025年06月17日)

&#x1f4ca; 由 TrendForge 系统生成 | &#x1f310; https://trendforge.devlive.org/ &#x1f310; 本日报中的项目描述已自动翻译为中文 &#x1f4c8; 今日获星趋势图 今日获星趋势图 1022 anthropic-cookbook 986 awesome-llm-apps 910 fluentui-system-icons 754 r…

NodeJS的中间件是什么

说简单一点&#xff0c;中间件就是在你的请求和业务逻辑之间做一层拦截。 在 Node.js 中&#xff0c;中间件&#xff08;Middleware&#xff09; 是一种函数&#xff0c;它在 请求&#xff08;Request&#xff09;到达路由处理器之前&#xff0c;或在 响应&#xff08;Respons…

MCAL学习(6)——诊断、DCM

1.诊断概述 汽车诊断就是通过汽车总线&#xff08;CAN LIN Eth&#xff09;来进行诊断会话&#xff0c;大部分通过CAN总线通讯进行请求与响应。 1.诊断分层 DCM内部支持UDS服务和OBD服务&#xff08;排放&#xff0c;动力&#xff09;。 以统一诊断服务UDS为例&#xff0c;应…

kafka-生产者-(day-4)

day-3 BufferPool 产生原因&#xff1a;ByteBuffer的创建和释放都是比较耗费资源的&#xff0c;为了实现内存的高效利用&#xff0c;产生了他。他会对特定大小的ByteBuffer进行管理 BufferPool的字段 free:是一个ArrayDeque队列&#xff0c;缓存指定大小的ByteBuffer对象Re…

java 验证ip是否可达

默认IP的设备已开放ping功能 代码 public class PingTest {public static void main(String[] args) throws Exception {String ip "192.168.21.101";boolean reachable InetAddress.getByName(ip).isReachable(3000);System.out.println(ip (reachable ? &quo…

LeetCode 2187.完成旅途的最少时间

题目&#xff1a; 给你一个数组 time &#xff0c;其中 time[i] 表示第 i 辆公交车完成 一趟旅途 所需要花费的时间。 每辆公交车可以 连续 完成多趟旅途&#xff0c;也就是说&#xff0c;一辆公交车当前旅途完成后&#xff0c;可以 立马开始 下一趟旅途。每辆公交车 独立 运…

永磁同步电机无速度算法--基于正切函数锁相环的滑模观测器

最近在学习锁相环&#xff0c;后续会记录一下了解到的几种PLL。 一、原理介绍 传统锁相环控制框图如下所示 在电机正转时&#xff0c;传统锁相环可以实现很好的转速和转子位置估计&#xff0c;但是当电机反转&#xff0c;反电动势符号发生变化&#xff0c;系统估计转子位置最…

Vim-vimrc 快捷键映射

Vim-vimrc 快捷键映射 文章目录 Vim-vimrc 快捷键映射Leader 键快捷键映射&#xff1a;插入特定字符插入 --插入 ##插入 解释Leader键设置快速插入分隔线 Leader 键 我们还将 , 设置为 Leader 键&#xff0c;使得其他快捷键映射更加简洁。 let mapleader ","快捷键…

SylixOS armv7 任务切换

SylixOS 操作系统下&#xff0c;任务切换可以分为两种 中断退出时&#xff0c;执行的任务切换&#xff08;_ScheduleInt&#xff09;内核退出时&#xff0c;执行的任务切换&#xff08;_Schedule&#xff09; 下面分别讲讲这两种任务切换 1、中断退出时任务切换 关于 ARM 架…

Java 自定义异常:如何优雅地处理程序中的“业务病”?

&#x1f525;「炎码工坊」技术弹药已装填&#xff01; 点击关注 → 解锁工业级干货【工具实测|项目避坑|源码燃烧指南】 一、从一个真实场景开始&#xff1a;银行转账系统的困境 假设你正在开发一个银行转账系统&#xff0c;当用户尝试转账时可能出现以下问题&#xff1a; 转…

【JAVA】【Stream流】

1. filter操作 filter()方法用于根据给定的条件过滤列表中的元素&#xff0c;仅保留满足条件的项。 List<Integer> list Arrays.asList(1, 2, 3, 4, 5, 6, 7, 8);List<Integer> res list.stream().filter(a -> a % 2 0).collect(Collectors.toList());for(I…

四、Redis实现限流

简介&#xff1a; 限流算法在分布式领域是一个经常被提起的话题&#xff0c;当系统的处理能力有限时&#xff0c;如何阻止计划外的请求继续对系统施压。 系统要限定用户的某个行为在指定的时间里只能允许发生 N 次&#xff0c;如何使用 Redis 的数据结构来实现这个限流的功能&a…

基于Geotools的两条道路相交并根据交点形成新路线实战-以OSM数据为例

目录 前言 一、需求场景及分解 1、需求场景 2、需求应用 二、需求实现 1、加载路网数据 2、获取道路信息 3、相交点求解 4、生成新道路 5、结果可视化 三、总结 前言 在当今数字化迅速发展的时代&#xff0c;地理空间数据的处理与分析已成为众多领域不可或缺的关键技…

goland有基础速通(需要其它编程语言基础)

tip: 无论是变量、方法还是struct的访问权限控制都是通过命名控制的&#xff0c;命名的首字母是大写就相当于java中的public&#xff0c;小写的话就是private&#xff0c;&#xff08;private只有本包可以访问&#xff09; 1 go的变量声明 普通变量 特点&#xff1a; 变量类…

量化面试绿皮书:19. 相关系数

文中内容仅限技术学习与代码实践参考&#xff0c;市场存在不确定性&#xff0c;技术分析需谨慎验证&#xff0c;不构成任何投资建议。 19. 相关系数 假设有三个随机变量x、y和z。 x与y之间的相关系数为0.8&#xff0c;x与z之间的相关系数也是0.8。 Q: 那么y与z之间的最大相关…

新生活的开启:从 Trae AI 离开后的三个月

很久没有写文章了&#xff0c;想借着入职新公司一个月的机会&#xff0c;和大家唠唠嗑。 离职 今年2月份我从字节离职了&#xff0c;结束了四年的经历&#xff0c;当时离开的核心原因是觉得加班时间太长了&#xff0c;平均每天都要工作15&#xff0c;16个小时&#xff0c;周末…

LLM部署之vllm vs deepspeed

部署大语言模型(如 Qwen/LLaMA 等)时,vLLM 与 DeepSpeed 是当前主流的两种高性能推理引擎。它们各自专注于不同方向,部署流程也有明显区别。 vLLM 提供极致吞吐、低延迟的推理服务,适用于在线部署;DeepSpeed 更侧重训练与推理混合优化,支持模型并行,适用于推理 + 微调/…

Git(二):基本操作

文章目录 Git(二)&#xff1a;基本操作添加文件修改文件版本回退撤销修改情况一&#xff1a;工作区的代码还没有 add情况⼆&#xff1a;已经 add 但没有 commit情况三&#xff1a;已经 add 并且也 commit 删除文件 Git(二)&#xff1a;基本操作 添加文件 首先我们先来学习一个…

nginx + ffmpeg 实现 rtsp视频实时播放和历史播放

nginx和ffmpeg 的安装请参考我的另一篇文章 Nginxrtmpffmpeg搭建视频转码服务_nginx-rtmp-module-master-CSDN博客 目录 1、整体方案设计如图 2、nginx下目录创建和配置文件创建 3、创建视频流生成脚本 4、修改nginx配置 5、管理界面 (video.html) 6、ffmpeg后台启动 …