当前位置: 首页 > article >正文

C++11QT复习 (四)

Day6-1 输入输出流运算符重载(2025.03.25)

1. 拷贝构造函数的调用时机
2. 友元2.1 友元函数
3. 输入输出流运算符重载3.1 关键知识点3.2 代码3.3 关键问题3.4 完整代码
4. 下标访问运算符 `operator[]`4.1 关键知识点4.2 代码
5. 函数调用运算符 `operator()`5.1 关键知识点5.2 代码5.3 示例5.4 完整代码
6. 总结

1. 回顾

1.1 拷贝构造函数的调用时机

拷贝构造函数在以下情况会被调用:

  1. 对象初始化

    • 当用一个已经存在的对象去初始化一个刚刚创建的对象时,调用拷贝构造函数。
    • 例:
      Complex c1(1, 2);
      Complex c2 = c1; // 调用拷贝构造函数
      
  2. 函数参数传递

    • 当形参与实参都是对象时,在函数调用时会调用拷贝构造函数。
    • 例:
      void func(Complex c) { }
      func(c1); // 形参与实参结合时调用拷贝构造函数
      
  3. 函数返回对象

    • 当函数返回一个对象时,可能调用拷贝构造函数(但现代 C++ 编译器会尝试优化此过程,如返回值优化 RVO)。
    • 例:
      Complex func() {Complex c(3, 4);return c; // 可能调用拷贝构造函数
      }
      

2. 友元

2.1 友元函数
  • 友元函数可以访问类的私有成员。
  • 友元声明可以出现在类的 publicprotectedprivate 部分,不影响其权限。
  • 友元关系是单向的、不可传递的
    • 单向:如果 AB 的友元,B 并不会自动成为 A 的友元。
    • 不可传递:如果 AB 的友元,BC 的友元,A 并不会自动成为 C 的友元。

3. 输入输出流运算符重载

3.1 关键知识点
  1. operator<< 必须是友元函数

    • 由于 cout << c1; 左操作数是 std::ostream,不能修改 std::ostream,所以 operator<< 不能是 Complex 的成员函数。
  2. operator>> 不能是 const 成员函数

    • 因为 operator>> 需要修改对象的值,因此不能加 const
3.2 代码
std::ostream& operator<<(std::ostream& os, const Complex& rhs) {if (rhs._imag > 0) {os << rhs._real << " + " << rhs._imag << "i";} else if (rhs._imag == 0) {os << rhs._real;} else {os << rhs._real << " - " << -rhs._imag << "i";}return os;
}std::istream& operator>>(std::istream& is, Complex& rhs) {std::cout << "请输入复数的实部和虚部:" << std::endl;is >> rhs._real >> rhs._imag;return is;
}
3.3 关键问题
  • 为什么 operator<<operator>> 的返回值是 std::ostream&std::istream&

    • 这样可以实现连续输入输出
      cout << c1 << c2 << endl;  // 连续输出
      cin >> c1 >> c2;           // 连续输入
      
  • 为什么 operator<<ostream& 参数不能去掉 &

    • 因为 ostream 的拷贝构造函数已被 delete,不能复制 ostream 对象。
3.4 完整代码
#include <iostream>
#include <limits.h>
#include <ostream>using namespace std;//复数
class Complex
{friend Complex operator*(const Complex& lhs, const Complex& rhs);//Complex operator/(const Complex& rhs) const;
public:Complex(double r = 0, double i = 0): _real(r), _imag(i){cout << "Complex(double r = 0, double i = 0)" << endl;}~Complex(){cout << "~Complex()" << endl;}void display() const{if (_imag > 0){cout << _real << " + " << _imag << "i" << endl;}else if (_imag == 0){cout << _real << endl;}else{cout << _real << " - " << -_imag << "i" << endl;}}//成员函数,operator输出运算符重载 //cout << c1 << endl; //第一个参数cout ,第二个参数c1//std::ostream& operator<<(std::ostream& os, const Complex& rhs); //error!隐含this指针//对于输出流运算符函数而言,不能写成成员函数的形式,因为违背了运算符重载的原则,不能改变操作数的顺序//std::ostream& operator<<(std::ostream& os);//error!this指针在参数列表的第一个位置/*友元函数可以放在类的 任何位置(public / protected / private),不影响其功能。从代码规范角度,建议统一放在类定义的开头或结尾,以提高可读性。友元关系是单向的,且不具备传递性(即类 A 的友元函数不会自动成为类 B 的友元)。*/friend std::ostream& operator<<(std::ostream& os, const Complex& rhs);//输入流运算符重载friend std::istream& operator>>(std::istream& is, Complex& rhs);private:double _real;double _imag;
};
//问题1 :参数列表中ostrream的引用符号&能不能去掉?
//解答1 :不能去掉因为形参"os"和实参"cout"结合的时候会满足拷贝构造函数的调用时机,但是ostream中的拷贝构造函数已被delete//问题2 : 函数返回类型中的引用符号&能不能删除?
//解答2 : 不能取掉,因为return os,返回类型满足拷贝构造函数的调用时机3//注释:basic_ifstream( const basic_ifstream& rhs ) = delete; (7)	(since C++11)
//	   basic_ofstream( const basic_ofstream& rhs ) = delete; (7)	(since C++11)
//ifstram 和 ofstream 的拷贝构造函数已经从C++11开始删除了
std::ostream& operator<<(std::ostream& os, const Complex& rhs)
{cout << "std::ostream& operator<<(std::ostream& os, const Complex& rhs)" << endl;if (rhs._imag > 0){os << rhs._real << " + " << rhs._imag << "i" << endl;}else if (rhs._imag == 0){os << rhs._real << endl;}else{os << rhs._real << " - " << -rhs._imag << "i" << endl;}return os;
}void readDouble(std::istream& is, double& rhs)
{while (is >> rhs, !is.eof()){if (is.bad()){std::cerr << "istream is bad" << endl;return;}else if (is.fail()){is.clear();//重置流的状态is.ignore(std::numeric_limits<::std::streamsize>::max(), '\n');//清空缓冲区cout << "请注意:需要输入double类型的数据!";}else{cout << "rhs = " << rhs << endl;break;}}
}//输入流运算符重载
std::istream& operator>>(std::istream& is, Complex& rhs)//因为要修改rhs 的值,所以不能加const
{cout << "std::istream& operator>>(std::istream& is, Complex& rhs)" << endl;cout << "请分别输入复数的实部和虚部:" << endl;//is >> rhs._real >> rhs._imag;readDouble(is, rhs._real);readDouble(is, rhs._imag);return is;
}void testOutputOperator()
{Complex c1(1, 2);cout << "c1 = ";c1.display();cout << endl << endl;//cout << "c1 = " << c1.display();//为什么没有做输出流运算符重载之前上面的写法 不可行呢? 解答:二元“<<”: 没有找到接受“void”类型的右操作数的运算符(或没有可接受的转换)cout << "c1 = " << c1 << endl;cout << endl;Complex c2;cin >> c2;cout << "c2 = " << c2 << endl;
}int main(int argc, char* argv[])
{testOutputOperator();return 0;
}

4. 下标访问运算符 operator[]

4.1 关键知识点
  • operator[] 主要用于自定义数组类型,使得 obj[idx] 访问数组元素。
  • 返回值应为 T&,以保证能够修改数组内容。
  • 必须进行越界检查,以防止访问非法内存。
4.2 代码
char& CharArrar::operator[](size_t idx) {if (idx < _size) {return _data[idx];} else {static char charNull = '\0';return charNull;}
}

5. 函数调用运算符 operator()

5.1 关键知识点
  • 使对象像函数一样调用,称为仿函数(函数对象)
  • 可存储状态,例如调用次数。
5.2 代码
class FunctionObject {
public:int operator()(int x, int y) {++_cnt;return x + y;}int operator()(int x, int y, int z) {++_cnt;return x * y * z;}private:int _cnt = 0;
};
5.3 示例
FunctionObject fo;
cout << "fo(3, 4) = " << fo(3, 4) << endl;
cout << "fo(3, 4, 5) = " << fo(3, 4, 5) << endl;
5.4 完整代码
//bracket.h
#pragma once
#include <iostream>
#include <string.h>using namespace std;
class CharArrar
{
public:CharArrar(size_t sz = 10):_size(sz), _data(new char[_size]){cout << " CharArrar(size_t sz = 10)" << endl;}~CharArrar(){cout << "~CharArrar()" << endl;if (_data){delete _data;_data = nullptr;}}size_t size() const{return _size;}//下标访问运算符的重载//int arr[10] = { 1,2,3,4,5 };//arr.operator[](idx);char& operator[](size_t idx);
private:size_t _size;char* _data;
};

//bracket.cpp
#include "bracket.h"/*
要修复错误 C2106: “=”: 左操作数必须为左值,需要确保 CharArrar 类的
下标运算符 operator[] 返回一个可修改的左值。当前的 operator[] 声明
返回的是一个 char,这不是一个可修改的左值。我们需要将其修改为返回一个 char&。
*/
char& CharArrar::operator[](size_t idx)
{if (idx < _size){return _data[idx];}else{static char charNUll = '\0';//静态变量延长生命周期return charNUll;   //使得返回的实体生命周期比函数的生命周期长}
}//C++中优势:重载的下标访问运算符考虑了越界的问题
//引用什么时候需要加上?
//1.如果返回类型是类型的时候,可以减少拷贝构造函数的执行
//2.有可能需要一个左值(来调用右操作数),而不是拷贝后的右值、
//3.cout << "111" << c1 << endl << 10 << 1 << endl,像这种情况下连续使用的时候可以加上引用 

//parenthese.h
#pragma once
#include <iostream>using namespace std;class FunctionObject
{
public:int operator()(int x, int y);int operator()(int x, int y, int z);private:int _cnt;//记录被调用的次数(函数对象状态)
};

parenthese.cpp
#include <iostream>
#include "parenthese.h"using namespace std;int FunctionObject::operator()(int x, int y)
{++_cnt;cout << "int operator()(int x, int y)" << endl;return x + y;
}int FunctionObject::operator()(int x, int y, int z)
{cout << "int operator()(int x, int y,int z)" << endl;++_cnt;return x * y * z;
}

//main.cpp
#include <iostream>
#include "bracket.h"
#include "parenthese.h"using namespace std;int add(int x, int y)
{cout << "int add(int x,int y)" << endl;static int cnt = 0;++cnt;return x + y;
}void testFunctionObject()
{FunctionObject fo;int a = 3;int b = 4;int c = 5;//fo本质上是一个对象,但是他的使用cout << "fo(a,b) = " << fo(a, b) << endl;cout << "fo(a, b ,c) = " << fo(a, b, c) << endl;cout << endl;//正经的函数cout << "add(a, b) = " << add(a, b) << endl;
}void testCharArrar()
{//把字符串中的内容拷贝到CharArrayconst  char* pstr = "hello cpp";CharArrar ca(strlen(pstr) + 1);for(size_t idx = 0; idx != ca.size(); ++idx){//ca[idx] = pstr[idx];//上面和下面两条代码等价ca.operator[](idx) = pstr[idx];}for (size_t idx = 0; idx != ca.size(); ++idx){cout << ca[idx] << "  ";}cout << endl;
}int main(int argc, char** argv)
{testFunctionObject();testCharArrar();return  0;
}

相关文章:

C++11QT复习 (四)

Day6-1 输入输出流运算符重载&#xff08;2025.03.25&#xff09; 1. 拷贝构造函数的调用时机 2. 友元2.1 友元函数 3. 输入输出流运算符重载3.1 关键知识点3.2 代码3.3 关键问题3.4 完整代码 4. 下标访问运算符 operator[]4.1 关键知识点4.2 代码 5. 函数调用运算符 operator…...

LVS的 NAT 模式实验

文章目录 目录 文章目录 概要 IP规划与题目分析 实验步骤 一、nginx配置&#xff08;rs1、rs2、rs3&#xff09; 二、LVS配置 三、客户端配置 四、防火墙和selinux配置 实验结果 痛点解答 概要 LVS/NAT lvs/nat网络地址转换模式&#xff0c;进站/出站的数据流量经过分发器(IP负…...

【MacOS】2025年硬核方法清理MacOS中的可清除空间(Purgeable space)

背景 MacOS使用一段时间之后&#xff0c;硬盘空间会越来越少&#xff0c;但自己的文件没有存储那么多&#xff0c;在储存空间中可以发现可用空间明明还剩很多&#xff0c;但磁盘工具却显示已满&#xff0c;见下图。 尝试解决 df -h 命令却发现磁盘已经被快被占满。使用du命…...

ue材质学习感想总结笔记

2025 - 3 - 27 1.1 加法 对TexCoord上的每一个像素加上一个值&#xff0c;如果加上0.1&#xff0c;0.1&#xff0c; 那么左上角原来0,0的位置变成了0.1,0.1 右上角就变成了1.1,1.1&#xff0c;那么原来0,0的位置就去到了左上角左上边&#xff0c;所以图像往左上偏移。 总而言…...

Go 语言 sync 包使用教程

Go 语言 sync 包使用教程 Go 语言的 sync 包提供了基本的同步原语&#xff0c;用于在并发编程中协调 goroutine 之间的操作。 1. 互斥锁 (Mutex) 互斥锁用于保护共享资源&#xff0c;确保同一时间只有一个 goroutine 可以访问。 特点&#xff1a; 最基本的同步原语&#x…...

约束文件SDC常用命令

约束文件SDC常用命令 定义时钟create_clock -name CLK-period 2 [get_ports_clk]告诉工具主时钟周期是2ns(频率500MHz),从clk端口输入 输入信号延迟set_input_delay 0.5 -clock CLK [get_ports data_in]数据进芯片前,外部电路已消耗0.5ns,综合要预留这段“堵车时间”。 输出…...

信而泰PFC/ECN流量测试方案:打造智能无损网络的关键利器

导语&#xff1a; AI算力爆发的背后&#xff0c;如何保障网络“零丢包”&#xff1f; 在当今数据中心网络中&#xff0c;随着AI、高性能计算&#xff08;HPC&#xff09;和分布式存储等应用的飞速发展&#xff0c;网络的无损传输能力变得至关重要。PFC&#xff08;基于优先级的…...

golang不使用锁的情况下,对slice执行并发写操作,是否会有并发问题呢?

背景 并发问题最简单的解决方案加个锁,但是,加锁就会有资源争用,提高并发能力其中的一个优化方向就是减少锁的使用。 我在之前的这篇文章《开启多个协程,并行对struct中的每个元素操作,是否会引起并发问题?》中讨论过多协程场景下struct的并发问题。 Go语言中的slice在…...

Android 底部EditView输入时悬浮到软键盘上方

1. 修改 Activity 的 Manifest 配置 确保你的 Activity 在 AndroidManifest.xml 中有以下配置&#xff1a; <activityandroid:name".YourActivity"android:windowSoftInputMode"adjustResize|stateHidden" /> 关键点&#xff1a; adjustResize 是…...

CNN和LSTM的计算复杂度分析

前言&#xff1a;今天做边缘计算的时候&#xff0c;在评估模型性能的时候发现NPU计算的大部分时间都花在了LSTM上&#xff0c;使用的是Bi-LSTM&#xff08;耗时占比98%&#xff09;&#xff0c;CNN耗时很短&#xff0c;不禁会思考为什么LSTM会花费这么久时间。 首先声明一下实…...

UniApp 表单校验两种方式对比:命令式与声明式

目录 前言1. 实战2. Demo 前言 &#x1f91f; 找工作&#xff0c;来万码优才&#xff1a;&#x1f449; #小程序://万码优才/r6rqmzDaXpYkJZF 以下主要针对Demo讲解&#xff0c;从实战中的体会 何为命令式 何为声明式 命令式的体验&#xff0c;随时都会有提交的按钮&#xff…...

【树莓派Pico FreeRTOS】-Mutex(互斥体)

Mutex(互斥体) 文章目录 Mutex(互斥体)1、硬件准备2、软件准备3、FreeRTOS的Mutex介绍4、完整示例RP2040 由 Raspberry Pi 设计,具有双核 Arm Cortex-M0+ 处理器和 264KB 内部 RAM,并支持高达 16MB 的片外闪存。 广泛的灵活 I/O 选项包括 I2C、SPI 和独特的可编程 I/O (P…...

LCR 187. 破冰游戏(python3解法)

难度&#xff1a;简单 社团共有 num 位成员参与破冰游戏&#xff0c;编号为 0 ~ num-1。成员们按照编号顺序围绕圆桌而坐。社长抽取一个数字 target&#xff0c;从 0 号成员起开始计数&#xff0c;排在第 target 位的成员离开圆桌&#xff0c;且成员离开后从下一个成员开始计数…...

【漏洞修复】为了修复ARM64 Android10系统的第三方库漏洞,将ARM64 Android16的系统库直接拷贝到Android10系统如何?

直接替换系统库的风险分析 将高版本Android&#xff08;如Android 16&#xff09;的系统库直接拷贝到低版本系统&#xff08;如Android 10&#xff09;可能会导致以下问题&#xff1a; 符号与依赖不兼容 高版本库可能依赖更高版本的NDK或Bionic libc&#xff08;Android的C库&…...

Flutter环境配置

配置环境变量 PUB_HOSTED_URLhttps://pub.flutter-io.cnFLUTTER_STORAGE_BASE_URLhttps://storage.flutter-io.cn 这个命令是用来配置 Flutter 的镜像源地址&#xff0c;主要是为了解决在中国大陆地区访问 Flutter 官方资源较慢的问题。 具体的操作如下&#xff1a; 右键点…...

centOS 7.9 65bit 修复Openssh漏洞

一、背景&#xff1a; 在使用centos 7.9 64bit版本操作系统时有扫描出如下的漏洞&#xff1a; 二、修复openssh漏洞操作 升级注意事项 (一下所有的操作默认都是root或者管理员权限&#xff0c;如果遇到权限问题每个指令以及指令组合都要在前面加sudo) 1、查看CentOS操作系统信…...

金融级密码管理器——生物特征密钥绑定方案

目录 金融级密码管理器 —— 生物特征密钥绑定方案一、模块概述与设计目标1.1 模块背景与意义1.2 设计目标二、系统架构设计2.1 系统模块划分2.2 系统架构图(Mermaid示意图)三、核心算法与安全原理3.1 生物特征数据预处理3.2 密钥生成算法3.3 安全认证与密钥绑定验证3.4 密钥…...

JDBC-添加数据

文章目录 准备数据库添加数据引入数据库依赖包 准备数据库 自行安装软件&#xff0c;利用小皮内嵌的数据 添加数据 引入数据库依赖包 结构 drivercom.mysql.cj.jdbc.Driver urljdbc:mysql://127.0.0.1:3308/yanyuuserroot passwordrootpackage com.yanyu;import java.sql.*;…...

衡石科技HENGSHI SENSE异构数据关联技术深度解析:揭秘5-8倍性能提升背后的“异构过滤“架构

引言&#xff1a;多源数据关联的行业痛点 在大数据时代&#xff0c;企业数据通常分散在多个异构系统中——关系型数据库、NoSQL、数据仓库、湖仓一体平台等。根据Forrester调研&#xff0c;超过78%的企业需要同时访问5种以上不同类型的数据源进行分析&#xff0c;但传统ETL和跨…...

基于Netlify + Localtunnel 实现本地项目“无服务器”部署上线

基于Netlify Localtunnel 实现本地项目“无服务器”部署上线 1. 先看效果图2. 实现步骤2.1 分两步走2.2 netlify 部署前端资源2.3 Localtunnel 映射 localhost 服务 3. 其它工具内网穿透工具对比4. 总结5. 参考资料 1. 先看效果图 地址&#xff1a;zqchat 2. 实现步骤 2.1 …...

C#从入门到精通(3)

目录 第九章 窗体 &#xff08;1&#xff09;From窗体 &#xff08;2&#xff09;MDI窗体 &#xff08;3&#xff09;继承窗体 第十章 控件 &#xff08;1&#xff09;控件常用操作 &#xff08;2&#xff09;Label控件 &#xff08;3&#xff09;Button控件 &…...

设计模式之创建型5种

设计模式 为什么设计模式是23种创建型 对象创建为什么设计模式是23种 设计模式之所以被归纳为23种,而非其他数量,源于GoF(Gang of Four)在1994年的系统性总结和分类。这一数量的确定并非偶然,而是基于以下核心原因: 他们遵循“大三律”(Rule of Three),即只有经过三个…...

Java + LangChain 实战入门,开发大语言模型应用!

在 Baeldung 上看到了一篇介绍基于 Java LangChain 开发大语言模型应用的基础入门文章&#xff0c;写的非常不错&#xff0c;非常适合初学者。于是&#xff0c;我抽空翻译了一下。 原文地址&#xff1a;https://www.baeldung.com/java-langchain-basics翻译&#xff1a; Java…...

el-date-picker时间范围 编辑回显后不能修改问题

el-date-picker daterange时间范围 编辑回显后不能修改 <el-form-item:label"LABELS.gplanRecordDateLabel"prop"gplanRecordDate"><el-date-pickerstyle"width: 300px"v-model"formData.gplanRecordDate"type"daterang…...

Java多线程与高并发专题—— CyclicBarrier 和 CountDownLatch 有什么异同?

引入 上一篇我们了解CountDownLatch的原理和常见用法&#xff0c;在CountDownLatch的源码注释中&#xff0c;有提到&#xff1a; 另一种典型用法是将一个问题分解为 N 个部分&#xff0c;用一个Runnable描述每个部分&#xff0c;该Runnable执行相应部分的任务并对闭锁进行倒计…...

leetcode543.二叉树的直径

当前顶点作为拐点时&#xff0c;求左子树加上右子树的高度可以求出该通过该顶点的直径大小&#xff0c;再对该顶点和左右子节点作为拐点时直径大小进行比对&#xff0c;返回最大值 缺点是递归了多次 /*** Definition for a binary tree node.* public class TreeNode {* …...

Java EE 进阶:MyBatis案例练习

表白墙 首先我们先准备一下数据库的数据 创建一个信息表 DROP TABLE IF EXISTS message_info;CREATE TABLE message_info (id INT ( 11 ) NOT NULL AUTO_INCREMENT,from VARCHAR ( 127 ) NOT NULL,to VARCHAR ( 127 ) NOT NULL,message VARCHAR ( 256 ) NOT NULL,delete_fla…...

Dubbo 全面解析:从 RPC 核心到服务治理实践

一、分布式系统与 RPC 框架概述 在当今互联网时代&#xff0c;随着业务规模的不断扩大&#xff0c;单体架构已经无法满足高并发、高可用的需求&#xff0c;分布式系统架构成为主流选择。而在分布式系统中&#xff0c;远程服务调用&#xff08;Remote Procedure Call&#xff0…...

路由选型终极对决:直连/静态/动态三大类型+华为华三思科配置差异,一张表彻底讲透!

路由选型终极对决&#xff1a;直连/静态/动态三大类型华为华三思科配置差异&#xff0c;一张表彻底讲透&#xff01; 一、路由&#xff1a;互联网世界的导航系统二、路由类型深度解析三者的本质区别 三、 解密路由表——网络设备的GPS华为&#xff08;Huawei&#xff09;华三&a…...

[微信小程序]对接sse接口

[微信小程序]对接sse接口 在uni开发中&#xff0c;在微信小程序中实现sse接口请求 相关连接 微信小程序对接SSE接口记录 uni中实现sse代码 注意的坑点 接收的并不是字符串&#xff0c;而是ArrayBuffer模拟流推送并不是流推送&#xff0c;会有data:字符扰乱推送并不是完全按照…...