C++篇:C向C++迈进(下)

news2024/11/27 23:45:42

目录

引言

缺省参数

1.缺省参数的概念

2.缺省参数的分类

2.1 全缺省

2.2 半缺省

3.注意事项

函数重载

1.函数重载的定义

2.函数重载的基本规则

3.函数重载的运用场景

引用

1.引用的概念

2.引用的主要特性

3.常引用

4.引用的使用场景

4.1 函数参数传递

4.2 函数返回值

5.引用和指针的差异

5.1 定义和本质

5.2 初始化和赋值

5.3 空值

5.4 内存占用

5.5 安全性

内联函数

1.内联函数的定义

2.注意事项

nullptr空指针

结束语


引言

在 C++篇:C向C++迈进(上)中我们学习了一些有关C++的知识,接下来我们继续学习。

本文将介绍了C++中的缺省参数、全缺省和半缺省参数、函数重载、引用、内联函数,以及nullptr的使用。

求点赞收藏关注!!!

缺省参数

1.缺省参数的概念

缺省参数是声明或定义函数时为函数的参数指定一个缺省值。在调用该函数时,如果没有指定实参则采用该形参的缺失值,否则使用指定的实参。

举个例子:

void func(int a = 0)
{
	cout << a << endl;
}

int main()
{
	func();  // 没有传参时,使用参数的默认值,输出0
	func(1); // 传参时,使用指定的实参,输出1
	return 0;
}

输出如下:

2.缺省参数的分类

根据其缺省参数的个数,我们我可以将缺省参数分为全缺省半缺省。

2.1 全缺省

每一个参数都有缺省值。

#include<iostream>
using namespace std;

void func(int a = 0, int b = 1, int c = 2)
{
	cout << "a = " << a << endl;
	cout << "b = " << b << endl;
	cout << "c = " << c << endl;
}

int main()
{
	func();				//不传参数
	func(10, 20);		//半传参数
	func(10, 20, 30);	//全传
	return 0;
}

输出结果:

2.2 半缺省

半缺省是部分形参给缺省值。C++规定半缺省参数必须从右往左依次连续缺省。

像这样:

#include<iostream>
using namespace std;

void func(int a, int b = 1, int c = 2)
{
	cout << "a = " << a << endl;
	cout << "b = " << b << endl;
	cout << "c = " << c << endl;
}
int main()
{

	func(10, 20);		//半传参数
	cout << endl;
	func(10, 20, 30);	//全传
	return 0;
}

输出结果为:

3.注意事项

(1)带缺省参数的函数调用,C++规定必须从左到右依次给实参,不能跳跃给实参。

void func(int a ,int b=1,int c=2)
{
	cout <<" a = " << a << endl;
	cout << "b = " << b << endl;
	cout << "c = " << c << endl;
}
func(,10,20)    //错误

(2)函数声明和定义分离时,缺省参数不能在函数声明和定义中同时出现,规定必须函数声明给缺省值

例如:我们在test.h中进行声明:

void Func(int a = 10);//声明

在test.cpp中定义:

void Func(int a = 20)    //定义
{
    cout << "a = " << a << endl;
}

这样是违反规定的。

函数重载

1.函数重载的定义

函数重载(Function Overloading)是面向对象编程语言(如C++、Java、C#等)中的一个重要特性,它允许在同一个作用域内定义多个同名的函数,只要这些函数的参数列表(参数的类型、个数或顺序)不同即可。通过函数重载,可以实现功能相似但处理不同类型数据或不同数量参数的函数,而无需改变函数名

举个例子:

int Add(int x, int y)
{
	return x + y;
}

double Add(double x, double y)
{
	return x + y;
}

int Add(int x, int y, int z)
{
	return x + y + z;
}

2.函数重载的基本规则

(1)函数名必须相同

(2)参数列表必须不同

(3)作用域相同

(4)const和引用限定符不影响重载

此外,还有以下两点注意事项:

(1)仅仅只有返回类型不同,不能构成函数重载

int Add(int a, int b)
{
	return a + b;
}
// 错误
double Add(int a,int b)
{
	return a + b;
}

(2)缺省值不同不能构成函数重载

int Add(int a=1, int b=20)
{
	return a + b;
}
// 错误
int Add(int a=1, int b=2)
{
	return a + b;
}

3.函数重载的运用场景

(1)操作符重载: 虽然操作符重载严格来说不是函数重载的直接应用,但它利用了重载的原理。通过重载操作符(如 + 、 - 、 * 等),可以使自定义类型的使用更加直观和方便,就像使用内置类型一样。

(2)构造函数重载: 在类的设计中,构造函数重载允许为对象的初始化提供多种不同的方式。这不仅可以提高类的灵活性,还可以使类的使用更加直观。例如,一个表示日期的类可能提供多个构造函数,允许用户通过年、月、日来创建日期对象,或者通过另一个日期对象和一个时间间隔来创建新的日期对象。

(3)流插入和提取操作符的重载: 在C++标准库中,流插入操作符 << 和流提取操作符 >> 经常被重载,以便能够将这些操作符用于自定义类型。这使得将自定义类型的数据写入输出流或从输入流中读取自定义类型的数据变得非常简单和直观。

(4)通用函数:设计一组功能相似但处理不同类型数据的函数,通过函数重载提高代码的可读性和可维护性。

本篇博客主要讲的是第四种,其余三种将会在后面学习到。

引用

1.引用的概念

在C++中,引用(Reference)是一种复合类型,它提供了对另一个变量的直接访问能力,而不需要通过指针那样使用解引用操作符(*)。引用可以看作是某个变量的别名,对引用的操作实际上就是对它所引用的变量的操作。

其语法为:

引用对象类型& 引用变量名(对象名) = 引用实体;

引用类似于指针,因为指向同一块空间,所以改变引用变量引用实体也会改变。

来试着使用一下引用:

#include<iostream>
using namespace std;

int main()
{
	int a = 0;
	int& b = a;
	cout << &a << endl;
	cout << &b << endl;
	b++;
	cout << a << endl;
	cout << b << endl;
	return 0;
}

输出结果如下:

2.引用的主要特性

  • 必须初始化:引用在声明时必须被初始化,因为它没有独立的存储空间,只是另一个变量的别名。
  • 一旦绑定,不可改变:引用一旦被初始化后,就不能再指向另一个变量。尝试将引用重新绑定到另一个对象会导致编译错误。
  • 不占独立存储空间:引用本身不占用额外的存储空间,它只是提供了一个访问已存在变量的途径。
  • 引用传递:在函数调用时,可以通过引用传递参数,这样函数内对参数的修改会反映到原始变量上,而不需要通过指针来间接访问。
  • 引用作为返回值:函数可以返回引用,但需要注意返回局部变量的引用是危险的,因为局部变量在函数返回后会被销毁,导致返回的引用成为“悬挂引用”。

3.常引用

常引用(const引用)是一种特殊的引用,它指向的变量不能被修改。常引用可以用于函数参数和返回值,以保护数据不被意外修改。

举个例子:

int main()
{
	const int a = 0;	 
	const int& b = a;	

	// int& c = a;		
	// 错误:不能定义一个对常量的非常量引用c
	// 尝试修改常量的值是非法的  

	int c = 1;			 
	const int& d = c;	

	double pi = 3.14;	 

	// int& e = pi;		
	// 错误:不能定义一个整型引用e来引用浮点型变量pi。
	// 类型不匹配,且即使发生隐式类型转换
	// (这里不会发生,因为引用类型必须严格匹配),  
	// 引用也必须是指向相同类型的对象  
  
	const int& f = pi;
	// 正确:定义一个整型常量引用f来引用浮点型变量pi。
	// 这里发生了从double到int的隐式类型转换,但f是一个常量引用,  
	// 所以f不能用来修改pi的值
	// (即使pi是浮点型,但f引用的转换后的int值被视为常量)  
	return 0;
}

4.引用的使用场景

4.1 函数参数传递

通过引用传递函数参数是C++中常用的一种优化手段。

引用传递函数参数可以避免不必要的拷贝:当函数参数是大型对象或数据结构时,如果按值传递(即传递参数的副本),会导致在函数调用时复制整个对象。这不仅会消耗大量的内存和时间,还可能导致程序效率低下。而通过引用传递,函数直接接收原始对象的引用,而不是其副本,从而避免了不必要的拷贝操作。

示例:

void swap(int& x, int& y) 
{
	int tmp = x;
	x = y;
	y = tmp;
}

在这里,swap函数通过引用传递了两个整数参数x和y。在函数内部,它交换了这两个整数的值。由于使用了引用传递,所以交换操作直接作用于原始变量上,无需进行数据的复制。

4.2 函数返回值

函数可以返回引用,这样可以使函数返回一个可修改的对象,而不是返回对象的副本。这在重载赋值运算符和数组下标运算符等场景下非常有用。但需要注意,不能返回局部变量的引用,因为局部变量在函数返回后会被销毁,导致返回的引用成为“悬挂引用”

举个例子:

int& Fun()
{
	static int n = 0;
	n++;
	return n;
}

在这个例子中,由于n是静态的,它在程序的生命周期内始终存在,因此返回其引用是安全的。

5.引用和指针的差异

引用和指针在C++中都是用于间接访问数据的工具,但它们在使用上有一些差异。

5.1 定义和本质

引用:引用是已存在变量的别名。一旦引用被创建,它就绑定到了某个特定的变量上,并且在整个生命周期内都保持对该变量的引用。引用在定义时必须初始化,且一旦初始化后,就不能再改变为引用另一个变量。

指针:指针是存储变量地址的变量。指针可以指向任何类型的变量,包括其他指针。指针的值(即它所存储的地址)可以在程序执行过程中被改变,使其指向不同的变量或内存地址。

5.2 初始化和赋值

引用:引用在定义时必须初始化,且一旦初始化后,就不能再被重新绑定到另一个变量上。尝试将引用重新绑定到另一个变量将导致编译错误。

指针:指针可以在定义时初始化,也可以不初始化(此时它包含的是一个不确定的值,通常称为野指针)。指针的值(即它所指向的地址)可以在程序执行过程中被改变,使其指向不同的变量或内存地址。

5.3 空值

引用:引用不可以为空。一旦引用被创建,它就必须始终引用一个有效的变量。

指针:指针可以为空。空指针不指向任何有效的内存地址,通常用于表示指针当前不指向任何对象。

5.4 内存占用

引用:引用本身不占用额外的内存空间,它只是所引用变量的别名。因此,引用的大小与所引用变量的大小相同。

指针:指针本身占用一定的内存空间,用于存储它所指向变量的地址。在大多数现代计算机上,指针的大小通常是固定的(如4字节或8字节),与它所指向的变量大小无关。

5.5 安全性

引用:由于引用一旦初始化就不能改变其指向,且不存在空引用,因此引用在使用上相对更安全。引用减少了因指针操作不当而导致的错误(如野指针、空指针解引用等)。

指针:指针提供了更大的灵活性,但也带来了更高的风险。指针可以指向任何内存地址,包括未分配的内存或受保护的内存区域,这可能导致程序崩溃或安全问题。此外,指针还需要显式地进行内存管理(如分配和释放内存),这增加了出错的可能性。

内联函数

1.内联函数的定义

用inline修饰的函数叫做内联函数,编译时C++编译器会在调用的地方展开内联函数,这样调用内联函数就不需要建立栈帧了,就可以提高效率。

举个例子:

#include<iostream>
using namespace std;

inline int Add(int x, int y)
{
	return x + y;
}

int main()
{
	cout << Add(1, 2) << endl;
	return 0;
}

2.注意事项

 (1)内联函数是一种以空间换时间的做法,如果编译器将函数当成内联函数处理,在编译阶段,会用函数体替换函数调用。内联函数的优势减少了调用开销,提高程序运行效率,缺陷就是可能会使目标文件变大

(2)虽然使用了inline关键字,但编译器可能会忽略这个请求,特别是当函数体很大或包含复杂的控制结构时。编译器会根据自己的优化策略决定是否将函数内联。

(3)内联函数不能是递归的,因为内联展开会导致无限递归。

(4)inline不能声明和定义分离,分离会导致链接错误。因为inline被展开,就没有函数地址了,链接就会找不到。

nullptr空指针

NULL实际是⼀个宏,在传统的C头文件(stddef.h)中,可以看到如下代码:

#ifndef NULL
    #ifdef __cplusplus
        #define NULL 0
    #else
        #define NULL ((void *)0)
    #endif
#endif

由此我们知道NULL既可以代表数字0,也可以代表空指针。这种模棱两可的定义就可能引出一些问题:

NULL 通常被定义为 (void*)0,这是一个指向 void 类型的空指针。然而,这种定义方式在某些情况下可能会引发类型安全问题,特别是当它被隐式转换为其他类型的指针时。此外,由于 NULL 是一个宏定义(在 C 和某些 C++ 环境中),它并不属于类型系统的一部分,这可能导致一些编译器警告或错误。

来看个例子:

#include<iostream>
using namespace std;

void func(int a)
{
	cout << "func(int)" << endl;
}

void func(int* p)
{
	cout << "func(int*)" << endl;
}

int main()
{
	func(0);
	func(NULL);
	func((int*)NULL);
	return 0;
}

输出结果为:

在默认情况下NULL被编译器当做数字0。这种问题是我们并不想看见的,所以 C++11 引入了nullptr来代替NULL。

结束语

开学了博客写的没有上个月快了。。。

不过我还是会坚持好好写的!!!

感谢各位大佬的支持!!!

希望各位大佬不要吝啬点赞收藏评论关注!!!

感谢!!!

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

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

相关文章

计算机网络-VRRP基础概念

回顾一下以前我们学习的网络通信基础&#xff0c;终端通过交换机可以相互进行通信&#xff0c;而如果是不同网段间的通信需要经过三层网关&#xff0c;网关进行路由寻址和转发&#xff0c;所以基本的网络结构就是终端--交换机--路由器网关--网络出口--Internet。 一、VRRP虚拟路…

逻辑回归算法详解

目录 原理推导 逻辑回归求解 项目实战--信用卡欺诈检测 数据分析与预处理 数据读取与分析 样本不均衡解决方案 特征标准化 下采样方案 交叉验证 模型评估方法 正则化惩罚 逻辑回归模型 参数对结果的影响 混淆矩阵 分类阈值对结果的影响 过采样方案 SMOTE数据生…

点击率预测模型Embedding层的学习和训练

导读&#xff1a; 本文将简要介绍推荐模型的发展历史&#xff0c;现状&#xff0c;和下一步的研究趋势。并重点介绍针对embedding数据的模型训练及优化。主要包含以下几大部分内容&#xff1a; CTR预测模型&#xff08;CTR Models&#xff09;连续值处理&#xff08;Continuou…

OpenAI“草莓项目”最快今年秋季发布!苹果将于9月10号推出首款AI iPhone|AI日报

文章推荐 吴恩达辞任Landing AI CEO&#xff0c;专注AI投资&#xff1f;数学家斯蒂芬预言哲学家引领AI未来&#xff5c;AI日报 与人类产生情感共鸣&#xff1f;数字华夏推出“夏澜”人形机器人&#xff1b;微软Azure AI语音服务推出虚拟人形象&#xff5c;AI日报 今日热点 …

行程问题

某直升机原定以260公里的时速飞往目的地&#xff0c;因任务紧急&#xff0c;飞行时速提高到360公里&#xff0c;结果提前1小时到达&#xff0c;则总的航程是&#xff08; &#xff09;公里。 A 900 B 936【正确答案】 C 1200 D 1296 第一步&#xff0c;本题考察行程问题&#x…

自行车租赁管理系统设计与实现

第三章 系统分析 3.1 系统可行性分析 可行性研究(Feasibility Study)是通过对项目的主要内容和配套条件&#xff0c;如市场需求、资源供应、建设规模、工艺路线、设备选型、环境影响、资金筹措、盈利能力等&#xff0c;从技术、经济、工程等方面进行调查研究和分析比较&…

使用mybatis对学生管理系统的完整功能实现

一、什么是mybatis: MyBatis 是一个优秀的持久层框架&#xff0c;它支持定制化 SQL、存储过程以及高级映射。MyBatis 避免了几乎所有的 JDBC 代码和手动设置参数以及获取结果集。MyBatis 可以使用简单的 XML 或注解来配置和映射原生信息&#xff0c;将接口和 Java 的 POJOs(Pla…

大赛题目公布,鸣志电器,对不起了

大家好&#xff0c;我是博主&#xff0c;夏目 即9/2发布组织第一届 电机电磁仿真大赛后&#xff0c;有很多朋友跃跃欲试&#xff0c;但也有不少顾虑。 跃跃欲试的原因是&#xff0c;对于这种新颖的活动&#xff0c;参与其中&#xff0c;也是一种乐趣&#xff0c;一种经验的积…

什么是I2C总线?

1.什么是I2C&#xff1f; 1.1 I2C的由来 在电视机内部电路中&#xff0c;众多功能需要用到许多集成电路IC来实现&#xff0c;包括主控器件微控制器和众多外围设备器件。这些器件相互之间要传递数据信息&#xff0c;那么就需要用导线相互连接&#xff0c;如此众多IC器件的互连&…

ArcGIS Pro 发布松散型切片

使用ArcGIS Pro发布松散型切片问题&#xff0c;有时候会出现切片方案写了松散型&#xff0c;但是自动切片完成后依然是紧凑型的问题&#xff0c;这时候可以采用手动修改然后再切片的方式。 1. 发布切片服务 选择手动切片方式 2. 手动修改服务的切片方案文件 修改cache服务…

htop的使用详解

1. htop简介&#xff1a; htop 是一个基于 ncurses 的跨平台进程查看器。 它与 top 类似&#xff0c;但允许您垂直和水平滚动&#xff0c;并使用指针设备&#xff08;鼠标&#xff09;进行交互。您可以观察系统上运行的所有进程及其命令行参数&#xff0c;以及以树形格式查看它…

Golang | Leetcode Golang题解之第392题判断子序列

题目&#xff1a; 题解&#xff1a; func isSubsequence(s string, t string) bool {n, m : len(s), len(t)f : make([][26]int, m 1)for i : 0; i < 26; i {f[m][i] m}for i : m - 1; i > 0; i-- {for j : 0; j < 26; j {if t[i] byte(j a) {f[i][j] i} else {…

Python | Leetcode Python题解之第392题判断子序列

题目&#xff1a; 题解&#xff1a; class Solution:def isSubsequence(self, s: str, t: str) -> bool:n, m len(s), len(t)f [[0] * 26 for _ in range(m)]f.append([m] * 26)for i in range(m - 1, -1, -1):for j in range(26):f[i][j] i if ord(t[i]) j ord(a) el…

软件工程-图书管理系统的需求分析

软件需求规格说明书 目录 软件需求规格说明书 一、引言 1.1编写目的 1.2背景 1.3定义 1.4参考资料 二、任务概述 2.1目标 2.2用户特点 2.3假定和约束 三、需求规定 3.1功能划分 3.1.1系统功能组成 3.1.2功能编号和优先级 3.2功能描述 3.3性能 3.4输入输出 …

VUE2.0 elementUI el-input-number 数据更新,视图不更新——基础积累

今天遇到一个问题&#xff0c;是关于el-input-number组件的&#xff0c;发现数据明明已经更改了&#xff0c;但是页面上组件输入框中还是之前的值。 比如上方输入框中&#xff0c;我输入120.5&#xff0c;就会出现下面的诡异现象 回显此值是120.779&#xff0c;但是页面上输入…

WPF MVVM如何在ViewModel直接操作控件对象

早些年在WPF中使用COM组件时&#xff0c;需要在ViewModel中操作COM组件中的控件对象&#xff0c;但是这个控件对象又不支持绑定&#xff0c; 后面的解决办法是在窗口加载时&#xff0c;将控件对象以参数传递到Loaded事件的处理命令中&#xff0c;然后将这个对象记录下来&#…

uniapp基础知识点补充

一. 响应式单位rpx和绝对单位px 1.px的作用及理解 绝对单位&#xff1a;px 是一个绝对单位&#xff0c;表示屏幕上的实际像素数量,不随屏幕尺寸或分辨率变化而变化。广泛适用&#xff1a;在Web开发中广泛使用&#xff0c;适用于各种浏览器和设备,适用于CSS中的各种属性&#xf…

线性代数 第四讲 极大线性无关组,等价向量组,向量组的秩

文章目录 1.极大线性无关组2.等价向量组2.1 等价向量组的判断 3.向量组的秩4.等价矩阵和等价向量组5. 重难点题型总结5.1 极大线性无关组的计算5.2 AB的行向量表示与AB的列向量表示 1.极大线性无关组 定义: 在一个向量组中&#xff0c;取部分向量组成新的向量组&#xff0c;这…

零基础5分钟上手亚马逊云科技-开发云原生网站应用

简介&#xff1a; 欢迎来到小李哥全新亚马逊云科技AWS云计算知识学习系列&#xff0c;适用于任何无云计算或者亚马逊云科技技术背景的开发者&#xff0c;通过这篇文章大家零基础5分钟就能完全学会亚马逊云科技一个经典的服务开发架构方案。 我会每天介绍一个基于亚马逊云科技…

交换机自动化获取诊断(H3C_无人值守)

介绍 在网络遇到个人无法处理的问题时&#xff0c;需要下载诊断信息发送给400处理&#xff0c;而通过传统的方式获取诊断信息需要通过多个步骤来获取&#xff0c;步骤繁琐&#xff0c;在设备数量过多的情况下&#xff0c;严重影响工作效率&#xff0c;而通过python自动化的方式…