【C++初阶】C++入门相关知识(2):输入输出 & 缺省参数 & 函数重载

【C++初阶】C++入门相关知识(2):输入输出 & 缺省参数 & 函数重载

🎈主页传送门:良木生香

🔥个人专栏:《C语言》 《数据结构-初阶》 《程序设计》《鼠鼠的C++学习之路》

🌟人为善,福随未至,祸已远行;人为恶,祸虽未至,福已远离


上期回顾:在上一篇文章中,我们对C++进行了初步的认识,学习了C++的发展历史,第一个C++程序以及命名空间,我们知道,C++的出现就是为了改进和完善C语言的不足,使得程序更加高效,程序员编写起来更加方便快捷,那么本篇文章我们继续往下认识C++的入门相关知识

目录

一、C++的输入&输出

1.1、核心载体:头文件

1.2、核心的IO对象:cin与cout

1.2.1、std::cin 标准输入流

1.2.2、std::cout 标准输出流

1.3、流操作符: << 与 >> 的双重身份

1.4、换行与缓冲区:endl的应用

1.5、C++IO的核心优势:从手动格式到自动适配

1.5.1、自动识别类型

1.5.2、自定义类型支持

1.6、面向对象的底层支撑:IO流的设计思想

1.7、提高输入输出效率

二、C++的缺省参数

2.1、缺省参数的定义及其基本用法

2.2、全缺省与半缺省

2.2.1、全缺省

2.2.2、半缺省

三、C++的函数重载

3.1、函数重载的定义:


一、C++的输入&输出

在C语言时代,我们一依赖printf和scanf两个函数完成输入和输出,手动指定格式符、处理类型不匹配的风险是每个开发者的日常。而C++带来了全新的IO库,以类型安全、可扩展的设计重构了输入输出的体验。

1.1、核心载体:<iostream>头文件

<iostream>头文件是Input Output stream的缩写,是C++标准输入输出的核心头文件,它不仅定义了cin,cout,endl等等标准的IO对象,同时封装了底层IO操作的复杂逻辑,让开发者无需关注缓冲区管理、设备交互等等细节

在这里有一个值得注意的小细节,在VS的编译器中(也就是微软公司的编译器),<iostream>头文件是会间接包含<stdio.h>这个头文件的,因此在微软的编译器中,我们可以混着使用cin与scanf.但是这只适用于微软的编译器,对于跨平台的兼容性不并不是很好,所以在编写代码的时候尽量不要混用

1.2、核心的IO对象:cin与cout

1.2.1、std::cin 标准输入流

std::cinistream类的对象,主要是面向窄字符(char类型)的标准输入流.它从键盘或者其他的输入设备获取数据,通过流提取运算符 >> 完成数据的读取,可参考以下代码:

#include <iostream> int main() { int age; std::cout << "请输入你的年龄:"; std::cin >> age; // 从标准输入读取整数 std::cout << "你的年龄是:" << age << "岁" << std::endl; return 0; }

1.2.2、std::cout 标准输出流

std::coutostream类的对象,同样是面对窄字符的标准输出流.它通过流插入运算符 <<向屏幕或者其他输出设备写入数据,支持链式调用,具体使用可参考以下代码:

#include <iostream> int main() { std::cout << "Hello, C++ IO Stream!" << std::endl; return 0; }

1.3、流操作符: << 与 >> 的双重身份

在C语言中,<< >>这两个符号分别代表的是左移/右移运算符.而在C++中,通过重载函数的技术,这两个运算符被赋予了新的角色:

  • << : 流插入运算符,用于向输出流写入数据
  • >> : 流提取运算符,用于从输入流提取数据

这种重载实现了 “语法糖” 效果,让 IO 操作更符合直觉。同时,运算符的返回值是流对象本身,支持链式调用:

std::cout << "姓名:" << "张三" << ",年龄:" << 25 << std::endl;

链式调用的底层原理是:每次<<操作返回ostream&,使得后续操作可以直接作用于同一个流对象。

1.4、换行与缓冲区:endl的应用

在我们刚刚开始学习C++语言的时候,老师经常会告诉我们,这个是换行符,其实不然,它的作用远不止于此:

表面功能:相当于插入换行符 \n,实现文本换行深层功能:强制舒心输出缓冲区,将缓冲区的数据立即写入输出设备

这与直接使用\n有着显著的区别:

// 仅换行,不刷新缓冲区,性能更优 std::cout << "Hello\n"; // 换行+刷新缓冲区,适用于需要立即输出的场景(如调试日志) std::cout << "Hello" << std::endl;

频繁使用endl会导致缓冲区频繁刷新,降低IO的性能,在性能高敏感的场景中,应当优先使用 \n,仅需要在立即输出的时候使用endl.

1.5、C++IO的核心优势:从手动格式到自动适配

1.5.1、自动识别类型

在C语言中,我们使用printf()需要手动指定格式符,如%s %d %f等等,一旦格式符与变量类型不相同,就会导致未定义行为,所以这也是C++针对C语言做的优化之一.C++IO流则是通过函数重载实现了自动类型识别:

int num = 42; double pi = 3.14; std::string name = "C++"; std::cout << num << " " << pi << " " << name << std::endl; // 自动识别类型,输出:42 3.14 C++

这种设计不仅简化了代码,还从根本上避免了格式不匹配的问题。

1.5.2、自定义类型支持

C++ IO 流的最大优势之一是支持自定义类型的输入输出。通过重载 << 和 >>运算符,我们可以让自定义类/结构体像内置类型一样直接参与 IO 操作:

#include <iostream> struct Point { int x, y; }; // 重载<<运算符,实现Point类型的输出 std::ostream& operator<<(std::ostream& os, const Point& p) { return os << "(" << p.x << ", " << p.y << ")"; } int main() { Point p{10, 20}; std::cout << "点的坐标:" << p << std::endl; // 输出:点的坐标:(10, 20) return 0; }

这种可扩展性让 C++ IO 流成为面向对象编程的理想选择。

1.6、面向对象的底层支撑:IO流的设计思想

C++IO流的设计深度融合了面向对象的核心思想:

  • 继承体系:istream和ostream作为基类,派生出文件流(fsteam)、字符串流(sstream)等子类,实现了IO操作的统一接口
  • 多态与重载:通过运算符重载和虚函数,实现了不同类型数据的IO适配
  • 封装性:底层缓冲区管理、设备交互等细节被封装在流内部,开发者只需要关注高层接口

这些设计使得IO流库即灵活又易于拓展,但是也意味着需要掌握更多面向对象只是才能深入理解其底层应用原理

1.7、提高输入输出效率

在需要输入输出性能的地方,C++在这方面是比不过C语言的,想要让C++的输入和输出像C语言一样,那就要在代码前面加上这段代码:

ios_base::sync_with_stdio(false); cin.tie(nullptr); cout.tie(nullptr);

总之:C++ IO 流不仅是输入输出的工具,更是面向对象设计思想的典型实践。掌握其核心原理与最佳实践,将为你构建更健壮、可扩展的 C++ 应用打下坚实基础。

二、C++的缺省参数

2.1、缺省参数的定义及其基本用法

缺省参数是声明或定义函数时为函数的参数指定⼀个缺省值。在调⽤该函数时,如果没有指定实参则采⽤该形参的缺省值,否则使⽤指定的实参,像下面这样:

#include<iostream> //这里定义一个函数 void Func(int a = 10) { std::cout << a; } int main() { int a = 20; //这里将参数a传入函数中 Func(a); return 0; }

运行结果如下:

但是这时候我们不将a的值传进去,我们看看结果是什么:

#include<iostream> //这里定义一个函数 void Func(int a = 10) { std::cout << a; } int main() { int a = 20; //这里不传a的值进去 Func(); return 0; }

运行结果为:

总结:我们在定义一个函数时,如果给里面的参数进行了初始化,那么在主函数调用时,如果给函数传进了参数,那就使用传进来的参数,如果没有传参数,那就使用在函数定义时所设定的初始值

2.2、全缺省与半缺省

2.2.1、全缺省

全缺省顾名思义就是函数中全部参数给缺省值,例子如下:

#include<iostream> //这里函数用三个参数做例子,可以更直观地看出全缺省的作用 void Func(int a = 10, int b = 20, int c = 30) { std::cout << a << " " << b << " " << c << std::endl; } int main() { int a = 1, b = 2, c = 3; Func(a,b,c); return 0; }

运行结果如下:

既然是全缺省,那是不是可以所有参数都不传进去?确实可以,想下面这样:

//这里为了方便,只展示主函数,其余的与上面的代码保持相同 int main() { int a = 1, b = 2, c = 3; Func(); return 0; }

运行结果如下:

这时候又有老铁要问了,能不能值传部分参数的值进去?我不想传完,行不行?答案是可以的,像这样:

int main() { int a = 1, b = 2, c = 3; Func(a); Func(a, b); return 0; }

我们可以传只传第一个参数的值进去,也可以只传前两个参数进去,但是如果我们想只传第一个和第三个的参数进去呢?写成这样可以吗?

Func(a, ,c);

很显然是不行的,为什么?因为在制定语法的时候这是不被允许的,但是我们如果真的只想传第一个和第三个的值呢?我们可以怎么做?简单,只用调换一下位置就行了:

#include<iostream> //像这样子调换一下b和c的位置即可 void Func(int a = 10, int c = 30 int b = 20) { std::cout << a << " " << b << " " << c << std::endl; } int main() { int a = 1, b = 2, c = 3; //只传入a和c的值 Func(a, c); return 0; }

运行结果如下:

这样一来,只有a和c的值被修改了

小贴士:在传入值的时候,只能从左向右依次传值,不能跨越地,间隔跳跃地传值

2.2.2、半缺省

与全缺省相反,半缺省就是对函数中部分变量进行初始化,其中规定只能从右往左依次缺省,不能间隔跳跃缺省:

#include<iostream> //只缺省最后一个参数 void Func(int a , int b, int c=10) { std::cout << a << " " << b << " " << c << std::endl; } int main() { int a = 1, b = 2, c = 50; //这时候就要将前两个参数全部传进去 Func(a, b); return 0; }

运行结果如下:

如果想要让两个参数缺省,那就这样子写:

#include<iostream> //void Func(int a = 10,int b,int c = 20) 这种格式是错误的 void Func(int a , int b =20, int c=10) { std::cout << a << " " << b << " " << c << std::endl; } int main() { int a = 1, b = 2, c = 50; Func(a); return 0; }

运行结果如下:

小贴士:带缺省参数的函数调用,C++规定必须是从左到右依次给实参,不能跳跃给实参函数声明和定义分离时,缺省参数不能在函数声明和定义中同时出现,这时候规定必须是函数声明时给缺省值.

三、C++的函数重载

在C语言中,我们经常会碰到这样问题:写很多个功能相同的函数但是命名却不能相同,这样就导致了程序员在编写代码时的效率大幅度降低,而C++的函数重载就是为了解决这个问题的

3.1、函数重载的定义:

C++⽀持在同⼀作⽤域中出现同名函数,但是要求这些同名函数的形参不同,可以是参数个数不同或者类型不同。这样C++函数调⽤就表现出了多态⾏为,使⽤更灵活。C语⾔是不⽀持同⼀作⽤中出现同名函数的。

 #include<iostream> //这是参数类型不相同 int add(int a, int b) { std::cout << "int (a+b) " << a + b << std::endl; return a + b; } double add(double a, double b) { std::cout << "double (a + b) " << a + b << std::endl; return a + b; } //这是参数个数不相同 int add2(int a, int b, int c) { std::cout <<"int (a + b + c) " <<a + b + c << std::endl; return a + b + c; } int add2(int a, int b, int c, int d) { std::cout << "int (a + b + c + d) " << a + b + c + d << std::endl; return a + b + c + d; } //这是参数类型顺序不同 void add3(int a, double b) { std::cout << "int a,int b" << std::endl; } void add3(double b, int a) { std::cout << "int b,int a " << std::endl; } int main() { int a = 10, b = 20, c = 30, d = 40; double a2 = 1.2, b2 = 2.2; add(a, b); add(a2, b2); add2(a, b, c); add2(a, b, c, d); return 0; }

运行结果如下:

小贴士:返回值的不同不能作为重载条件,因为如果是同名函数的话,编译器不能区分调用哪个:

#include<iostream> int fxx() { std::cout << "int fxx()" << std::endl; } void fxx() { std::cout << "void fxx()" << std::endl; } int main(){ fxx(); return 0; }

但是也要小心缺省函数带来的类似返回值不同的效果:

#include<iostream> void fxx(int a){ std:::cout << "fxx(int a)" << std::endl; } void fxx(){ std::cout << "fxx()" << std::endl; } int main(){ //这就是缺省参数带来的类似返回值不同的效果 fxx(); return 0; }

那么以上就是本次所有的内容了文章是自己写的哈,有什么描述不对的、不恰当的地方,恳请大佬指正,看到后会第一时间修改,感谢您的阅读~

Read more

排序算法指南:归并排序(非递归)

排序算法指南:归并排序(非递归)

前言:              非递归实现归并排序,通常被称为 “自底向上”(Bottom-Up) 的归并排序,与递归版本(先将数组对半拆分直到只剩一个元素,再通过递归栈回溯合并)不同,非递归版本直接从最小的子数组(长度为1)开始,两两合并,然后长度翻倍(2, 4, 8 ...),直到合并完整个数组。                                                                 一、归并排序非递归的核心思路          递归算法转换为非递归实现主要有两种常见方法:          1.使用栈结构模拟递归过程          2.将递归逻辑改写为循环结构          1.1 栈模拟失效          如果仅通过栈结构模拟递归过程,我们只能够做到拆分数组,而不能做到合并数组。          假设我们要排序数组 arr = [8, 4, 5, 7],下标是 0 到 3。          初始状态:栈中有任务 [0, 3]。                   第一步:弹

By Ne0inhk
Python APP反爬实战:Frida+Charles抓包,破解签名校验

Python APP反爬实战:Frida+Charles抓包,破解签名校验

做爬虫做到APP层面,你会发现网页反爬的那套思路完全失效:用Charles抓包能看到请求参数,但sign/appSign这类签名参数始终是乱码;手动拼接参数模拟请求,服务端直接返回“签名验证失败”;甚至换了代理、改了设备信息,还是过不了服务端的校验——这就是APP反爬的核心壁垒:签名校验。 我经手过电商APP价格爬取、短视频APP数据采集、物流APP轨迹抓取等数十个APP反爬项目,从最初的“抓包改参数被秒拒”,到后来用Frida Hook脱壳获取签名密钥,再到Python还原签名算法实现稳定爬取,踩过的坑能帮新手少走一年弯路。这篇文章全程聚焦“实战”:从APP签名校验的底层逻辑,到Charles抓包定位参数,再到Frida Hook破解签名算法,最后用Python实现完整爬取,每个步骤都附可直接复制的生产级代码,新手也能跟着搞定99%的APP签名反爬。 一、先搞懂:APP签名校验的核心逻辑(为什么普通抓包没用) 新手先别着急装工具,搞懂签名校验的原理,才能精准破解——这是APP反爬的“命门”,也是服务端验证请求合法性的核心手段。 1.1 APP反爬 vs 网页反爬:核心差异

By Ne0inhk
基于Python的近红外光谱数据预处理与特征筛选——以哈密瓜品质检测为例

基于Python的近红外光谱数据预处理与特征筛选——以哈密瓜品质检测为例

目录 * 一、引言 * 二、研究背景 * 三、数据集 * 四、预处理算法 * (1)原始光谱读取 * (2)趋势校正(Detrending, DT) * (3)标准正态变换(Standard Normal Variate, SNV) * (4)多元散射校正(Multiplicative Scatter Correction, MSC) * (5)卷积平滑(Savitzky-Golay smoothing, SG) * (6)一阶导数(First Derivative, FD) * (7)光谱预处理结果 * 五、特征筛选算法 * (1)竞争自适应重加权(Competitive Adaptive Reweighted Sampling, CARS) * (2)无信息变量消除算法(

By Ne0inhk
Python 纯函数编程:从理念到实战的完整指南

Python 纯函数编程:从理念到实战的完整指南

Python 纯函数编程:从理念到实战的完整指南 引言:当函数式编程遇见 Python 在我十多年的 Python 开发生涯中,我见证了无数项目因为代码复杂度失控而陷入泥潭。调试时,你永远不知道一个函数会修改哪些全局状态;测试时,你需要费尽心思构造各种环境;并发时,你担心数据竞争导致诡异的 bug。直到我深入理解了纯函数的理念,这一切才豁然开朗。 纯函数(Pure Function)并非 Python 独有的概念,它源自函数式编程范式。但在 Python 这样的多范式语言中,纯函数思想能与面向对象、过程式编程完美融合,帮助我们写出更健壮、更易维护的代码。今天,我想通过实战案例,带你深入理解纯函数的本质,以及它如何让你的 Python 代码脱胎换骨。 一、纯函数的本质:可预测的代码世界 1.1 什么是纯函数? 纯函数必须满足两个核心特征: 特征一:相同输入必定产生相同输出 # 纯函数示例defadd(a,

By Ne0inhk