C++(友元和运算符重载)

目录

友元:

友元函数:

示例:

友元类:

示例:

优点:

注意事项:

运算符重载:

注意:

示例:


友元:

C++中如果想要外部函数或者类对一个类的private(私有成员)和protected(保护成员),可以通过使用friend关键字对其进行声明。

声明位置灵活,可以在类内任何访问区域进行友元声明。

友元函数:

友元函数一般在运算符重载和需要访问私有数据的全局函数进行使用。友元函数是声明在类内的非成员函数,可以访问该类的所有成员(包括私有和保护成员)。

示例:

通过友元函数访问Student类的私有成员_name,在类内声明GetStudentName()友元函数,在类外进行定义来。

#include <iostream>
#include <string>
#include <thread>class Student {friend void GetStudentName(const Student& student);
public:Student():_name(""),_age(0),_data(new int(0)) {std::cout << "无参构造" << std::endl;}Student(std::string name, int age,int number):_name(name),_age(age),_data(new int(number)) {std::cout << "有参构造" << std::endl;}Student(const Student &student):_name(student._name),_age(student._age) {//const可以加可以不加,主要是为了防止对参数进行修改,但是&是必须加std::cout << "拷贝构造" << std::endl;_data = new int();*_data = *student._data;}Student(Student && student):_name(std::move(student._name)),_age(student._age),_thread(std::move(student._thread)){std::cout << "移动构造" << std::endl;_data = new int();*_data = std::move(*(student._data));}~Student() {std::cout << "析构函数" << std::endl;delete _data;}void GetTarget() {std::cout << "获取的target的值:";std::cout << _target << std::endl;std::cout << std::endl;}void ModifyTarget(int target) {std::cout << "修改target之后的值:";_target = target;std::cout << _target<<std::endl;}void GetName() {std::cout << _name << std::endl;}void GetAge() {std::cout << _age << std::endl;}void GetData() {std::cout << _data << std::endl;}
private:std::string _name;int _age;static int _target;//类内声明,类外初始化std::thread _thread;int* _data;
};
int Student::_target = 100;void GetStudentName(const Student& student) {std::cout << student._name << std::endl;
}int main() {Student student1("小明",16,10);GetStudentName(student1);return 0;
}

运行结果:

友元类:

友元类是其所有成员均可以访问另一个类的私有成员和保护成员的类。需要注意的是:

类A声明为类B为友元,不意味着类B自动授予类A的访问权限,类B可以访问类A的私有成员和保护成员,但是类A不是类B的友元,所以不能访问类B的私有成员和保护成员。

如果类B是类A的友元类,同时类C是类B的友元,类C是不会自动成为类A的友元,也就是不会有传递性。

基类的派生类不会继承基类的友元关系,也就是没有继承性。

示例:

创建一个获取Student类的私有成员_name的类,在其成员函数中定义获取的成员函数func()。

#include <iostream>
#include <string>
#include <thread>class Student {friend void GetStudentName(const Student& student);
public:Student():_name(""),_age(0),_data(new int(0)) {std::cout << "无参构造" << std::endl;}Student(std::string name, int age,int number):_name(name),_age(age),_data(new int(number)) {std::cout << "有参构造" << std::endl;}Student(const Student &student):_name(student._name),_age(student._age) {//const可以加可以不加,主要是为了防止对参数进行修改,但是&是必须加std::cout << "拷贝构造" << std::endl;_data = new int();*_data = *student._data;}Student(Student && student):_name(std::move(student._name)),_age(student._age),_thread(std::move(student._thread)){std::cout << "移动构造" << std::endl;_data = new int();_data = std::move(student._data);}~Student() {std::cout << "析构函数" << std::endl;delete _data;}void GetTarget() {std::cout << "获取的target的值:";std::cout << _target << std::endl;std::cout << std::endl;}void ModifyTarget(int target) {std::cout << "修改target之后的值:";_target = target;std::cout << _target<<std::endl;}Student operator+(const Student& other)const {Student temp;temp._age=this->_age + other._age;temp._data = new int(*this->_data + *other._data);return temp;}Student& operator=(const Student& other) {if (this == &other) {return *this;}delete _data;this->_name = other._name;this->_age = other._age;this->_data = new int();*this->_data = *other._data;std::cout << "拷贝赋值运算符" << std::endl;return *this;}Student& operator=(Student&& other)noexcept {if (this == &other) {return *this;}delete this->_data;this->_name = std::move(other._name);this->_age = other._age;this->_data = other._data;other._data = nullptr;std::cout << "移动赋值运算符" << std::endl;return *this;}Student& operator++() {this->_age++;(*this->_data)++;return *this;}const Student operator++(int) {Student temp(*this);this->_age++;(*this->_data)++;return temp;}friend std::ostream& operator<<(std::ostream& os, Student& other);
private:std::string _name;int _age;static int _target;//类内声明,类外初始化std::thread _thread;int* _data;
};
int Student::_target = 100;void GetStudentName(const Student& student) {std::cout << student._name << std::endl;
}std::ostream& operator<<(std::ostream& os, Student& other) {os << other._name << "  "<< other._age << "  "<< *other._data << std::endl;return os;
}int main() {std::cout << "构造student1和student2:" << std::endl;Student student1("小明",16,10);Student student2("小刚", 10, 10);std::cout << student2;std::cout << student1;std::cout << std::endl << "构造student3:" << std::endl;Student student3;student3=student1 + student2;std::cout << student3;std::cout <<std::endl<< "对student1进行前置++,对student2进行后置++:" << std::endl;Student student5=++student1;Student student6=student2++;std::cout << "前置++:" << std::endl;std::cout << student1;std::cout << student5;std::cout << "后置++:" << std::endl;std::cout << student2;std::cout << student6;std::cout << "移动赋值运算符:" << std::endl;Student student7;student7=std::move(student2);std::cout << student7;return 0;
}

运行结果:

优点:

避免了共有接口简介访问私有数据,支持特殊的场景,比如运算符重载等。

注意事项:

友元会破坏类的封装性,不能够通过继承或者嵌套自动传递,会导致代码的耦合度增加,维护难度上升。

优先使用成员函数或者公有接口,在必要时使用友元,尽量使用友元函数不使用友元类,减少权限的开放。

运算符重载:

通过成员函数或者友元函数重新定义运算符对自定义类型的操作行为。

注意:

运算符重载不能够创建新的运算符。

不能够改变运算符的优先级和结合性。

并非所有的运算符都能够进行重载,比如成员当问运算符、成员指针运算符、作用域解析运算符、条件运算符、sizeof和typeid运算符不能够进行重载。

示例:

对"+"、"<<"、"="、"前置++"、"后置++"进行重载。"-"、"*"、和"/"和"+"是一样的思路。注意区分前置++和后置++的区别,还需要注意重载时,前置++和后置++的函数参数区别。移动语义操作中一定注意将被移动对象的指针置空,防止出现双重释放或者悬空指针问题。

#include <iostream>
#include <string>
#include <thread>class Student {friend void GetStudentName(const Student& student);
public:Student():_name(""),_age(0),_data(new int(0)) {std::cout << "无参构造" << std::endl;}Student(std::string name, int age,int number):_name(name),_age(age),_data(new int(number)) {std::cout << "有参构造" << std::endl;}Student(const Student &student):_name(student._name),_age(student._age) {//const可以加可以不加,主要是为了防止对参数进行修改,但是&是必须加std::cout << "拷贝构造" << std::endl;_data = new int();*_data = *student._data;}Student(Student && student):_name(std::move(student._name)),_age(student._age),_thread(std::move(student._thread)){std::cout << "移动构造" << std::endl;_data = new int();_data = std::move(student._data);}~Student() {std::cout << "析构函数" << std::endl;delete _data;}void GetTarget() {std::cout << "获取的target的值:";std::cout << _target << std::endl;std::cout << std::endl;}void ModifyTarget(int target) {std::cout << "修改target之后的值:";_target = target;std::cout << _target<<std::endl;}Student operator+(const Student& other)const {Student temp;temp._age=this->_age + other._age;temp._data = new int(*this->_data + *other._data);return temp;}Student& operator=(const Student& other) {if (this == &other) {return *this;}delete _data;this->_name = other._name;this->_age = other._age;this->_data = new int();*this->_data = *other._data;std::cout << "拷贝赋值运算符" << std::endl;return *this;}Student& operator=(Student&& other)noexcept {if (this == &other) {return *this;}delete this->_data;this->_name = std::move(other._name);this->_age = other._age;this->_data = other._data;other._data = nullptr;std::cout << "移动赋值运算符" << std::endl;return *this;}Student& operator++() {this->_age++;(*this->_data)++;return *this;}const Student operator++(int) {Student temp(*this);this->_age++;(*this->_data)++;return temp;}friend std::ostream& operator<<(std::ostream& os, Student& other);
private:std::string _name;int _age;static int _target;//类内声明,类外初始化std::thread _thread;int* _data;
};
int Student::_target = 100;void GetStudentName(const Student& student) {std::cout << student._name << std::endl;
}std::ostream& operator<<(std::ostream& os, Student& other) {os << other._name << "  "<< other._age << "  "<< *other._data << std::endl;return os;
}int main() {std::cout << "构造student1和student2:" << std::endl;Student student1("小明",16,10);Student student2("小刚", 10, 10);std::cout << student2;std::cout << student1;std::cout << std::endl << "构造student3:" << std::endl;Student student3;student3=student1 + student2;std::cout << student3;std::cout <<std::endl<< "对student1进行前置++,对student2进行后置++:" << std::endl;Student student5=++student1;Student student6=student2++;std::cout << "前置++:" << std::endl;std::cout << student1;std::cout << student5;std::cout << "后置++:" << std::endl;std::cout << student2;std::cout << student6;std::cout << "移动赋值运算符:" << std::endl;Student student7;student7=std::move(student2);std::cout << student7;return 0;
}

运行结果:

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

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

相关文章

和平精英风格射击游戏开发指南

本教程将完整讲解如何开发一款和平精英风格的HTML射击游戏&#xff0c;涵盖核心设计理念、代码架构与关键实现细节。 核心设计架构 游戏机制系统 角色控制系统&#xff1a;通过键盘实现玩家移动战斗系统&#xff1a;子弹发射与碰撞检测道具系统&#xff1a;武器、弹药和医疗包收…

21.1 《24GB显存搞定LLaMA2-7B指令微调:QLoRA+Flash Attention2.0全流程实战》

24GB显存搞定LLaMA2-7B指令微调:QLoRA+Flash Attention2.0全流程实战 实战 LLaMA2-7B 指令微调 一、指令微调技术背景 指令微调(Instruction Tuning)是大模型训练中的关键技术突破点。与传统全量微调(Full Fine-Tuning)相比,指令微调通过特定格式的指令-响应数据训练,…

周志华《机器学习导论》第10章 降维与度量学习

https://www.lamda.nju.edu.cn/aml24fall/slides/Chap10.pptx 目录 1.MDS (Multiple Dimensional Scaling) 多维缩放方法 2. 主成分分析 (Principal Component Analysis, PCA) 2.1 凸优化证明 2.2 人脸识别降维应用 3. 核化PCA 4. 流行学习 4.1 LLE 局部线性嵌入&#…

Kubernetes 弹性伸缩:深入讲解 HPA 和 VPA

1. 介绍 Kubernetes 提供了多种资源管理方式&#xff0c;其中 弹性伸缩&#xff08;Auto-scaling&#xff09;是最重要的特性之一。弹性伸缩可以根据应用的负载变化自动调整 Pod 的数量和资源&#xff0c;以确保在高负载下应用能够正常运行&#xff0c;而在低负载时节省资源。在…

大数据毕业设计选题推荐-基于大数据的家庭能源消耗数据分析与可视化系统-Hadoop-Spark-数据可视化-BigData

✨作者主页&#xff1a;IT毕设梦工厂✨ 个人简介&#xff1a;曾从事计算机专业培训教学&#xff0c;擅长Java、Python、PHP、.NET、Node.js、GO、微信小程序、安卓Android等项目实战。接项目定制开发、代码讲解、答辩教学、文档编写、降重等。 ☑文末获取源码☑ 精彩专栏推荐⬇…

【Spring】原理解析:Spring Boot 自动配置的核心机制与实战剖析

一、引言在当今的 Java 开发领域&#xff0c;Spring Boot 凭借其快速搭建项目、简化配置等优势&#xff0c;成为了众多开发者的首选框架。而 Spring Boot 自动配置作为其核心特性之一&#xff0c;极大地提升了开发效率&#xff0c;让开发者能够更专注于业务逻辑的实现。本文将深…

Java forEach中不能用i++的原因以及代替方案

因为在 Lambda 表达式内部访问的外部局部变量必须是 final 或 effectively final&#xff08;事实最终变量&#xff09;&#xff0c;而 i 操作试图改变这个变量的值&#xff0c;违反了这一规定。下面我们来详细拆解这个问题&#xff0c;让你彻底明白。1. 一个具体的例子我们先看…

第十四届蓝桥杯青少组C++选拔赛[2023.1.15]第二部分编程题(2 、寻宝石)

参考程序&#xff1a;#include <bits/stdc.h> using namespace std;int main() {int N;cin >> N; // 读入盒子数vector<int> a(N);for (int i 0; i < N; i) cin >> a[i]; // 读入每个盒子的宝石数// N > 3&#xff08;题目保证&#x…

9120 部 TMDb 高分电影数据集 | 7 列全维度指标 (评分 / 热度 / 剧情)+API 权威源 | 电影趋势分析 / 推荐系统 / NLP 建模用

一、引言在影视行业分析与数据科学实践中&#xff0c;高分电影数据的深度挖掘已成为平台优化内容推荐、制片方研判市场趋势、影迷发现优质作品的核心支撑 —— 通过上映年份与评分的关联可捕捉电影质量演变、依托热度与投票数能定位爆款潜质、结合剧情概述可开展情感与主题分析…

Tomcat PUT方法任意写文件漏洞学习

1 PUT请求 PUT请求是一种在HTTP协议中常见的请求方法 1.1 基本原理 PUT请求是一种用于向指定资源位置上传新的实体数据的请求方法&#xff0c;与其他请求方法的区别在于&#xff0c;PUT请求用于创建或者更新只当资源位置的实体数据。它与GET请求不同&#xff0c;PUT请求会替换掉…

【C++基础】初识模板——一起步入泛型编程的大门

引言在 C 世界里&#xff0c;模板&#xff08;Template&#xff09;就像一把万能钥匙。它允许你编写通用的代码&#xff0c;让编译器在需要的时候为具体类型生成对应的函数或类。换句话说&#xff0c;模板是 C 泛型编程&#xff08;Generic Programming&#xff09; 的基石。 如…

项目管理框架如何影响团队协作

在项目执行过程中&#xff0c;项目管理框架不仅是一套工具和流程&#xff0c;更是团队协作方式的基础。不同的项目管理框架会深刻影响团队沟通效率、任务分配、决策方式和整体协同效果。 传统框架通常强调层级与计划&#xff0c;带来高度规范化的协作&#xff1b;敏捷框架则强调…

正向代理,反向代理,负载均衡还有nginx

这是一个非常核心且重要的后端/运维知识领域。我会用尽可能清晰易懂的方式&#xff0c;结合生动的比喻&#xff0c;为你详细梳理这些概念。核心概念一览我们先从一个宏观的角度来理解它们之间的关系&#xff1a;代理&#xff08;Proxy&#xff09;&#xff1a; 一个中间人的角色…

WebSocket压缩传输优化:机器视觉高清流在DCS中的低延迟方案

引言在现代工业自动化领域&#xff0c;分布式控制系统&#xff08;DCS&#xff09;正面临着前所未有的数据挑战。随着机器视觉技术的广泛应用&#xff0c;高清视频流已成为监控产品质量、检测设备异常和保障生产安全的重要手段。然而&#xff0c;将720P、1080P甚至4K分辨率的高…

《Linux常见命令》

ls 功能&#xff1a;列出目录下的子目录与文件&#xff0c;对于文件&#xff0c;还会列出文件名及其他信息。 语法&#xff1a;ls [选项] [目录或文件] 1.常用选项及说明选项说明-a列出目录下的所有文件&#xff0c;包括以 . 开头的隐含文件-d将目录象文件一样显示&#xff0c;…

Python数据分析:函数定义时的位置参数。

目录1 代码示例2 欢迎纠错3 免费爬虫4 论文写作/Python 学习智能体1 代码示例 直接上代码。 def pargs1(a, b):"""先看确定数量的位置参数。最简单的位置参数。a和b都叫而且只能叫“位置参数”。所谓确定数量&#xff0c;很明显&#xff0c;是两个就是两个&…

《没有架构图?用 netstat、ss、tcpdump 还原服务连接与数据流向》

&#x1f4e2; 你是否遇到过这些问题&#xff1f; 接手一个老项目&#xff0c;只有服务器账号&#xff0c;没有架构图&#xff1f;服务突然异常&#xff0c;但不知道它依赖哪些外部系统&#xff1f;想画数据流向图&#xff0c;却找不到文档&#xff1f; 别担心&#xff01;只要…

Redis列表(List):实现队列/栈的利器,底层原理与实战

Redis列表&#xff08;List&#xff09;&#xff1a;实现队列/栈的利器&#xff0c;底层原理与实战 1. Redis列表概述 1.1 什么是Redis列表 Redis列表&#xff08;List&#xff09;是一个有序的字符串元素集合&#xff0c;支持在头部和尾部进行高效的插入和删除操作。它可以…

OpenCV 图像双三次插值

文章目录 一、简介 二、实现代码 三、实现效果 参考资料 一、简介 在数学中,双三次插值是三次样条插值(一种将三次插值应用于数据集的方法)的扩展,用于在二维规则网格上插值数据点。插值曲面(指核形状,而非图像)比通过双线性插值或最近邻插值获得的相应曲面更平滑。双三…

【Java实战㊲】Spring Security:为Spring Boot应用筑牢安全防线

目录 一、Spring Security 概述 1.1 Spring Security 核心功能 1.2 Spring Security 与 Shiro 对比 二、Spring Boot 整合 Spring Security 基础 2.1 整合依赖导入 2.2 默认安全配置 2.3 自定义用户认证 2.4 自定义登录与注销 三、Spring Security 授权控制 3.1 基于角色的授权…