【c++初阶】C++入门(下)

✅✅✅✅✅✅✅✅✅✅✅✅✅✅✅✅

✨✨✨✨✨✨✨✨✨✨✨✨✨✨✨✨

🌿🌿🌿🌿🌿🌿🌿🌿🌿🌿🌿🌿🌿🌿🌿🌿

🌟🌟🌟🌟🌟🌟🌟🌟🌟🌟🌟🌟🌟🌟🌟🌟

🌟🌟 追风赶月莫停留 🌟🌟

🍀🍀🍀🍀🍀🍀🍀🍀🍀🍀🍀🍀🍀🍀🍀🍀

🌟🌟 平芜尽处是春山🌟🌟

🌟🌟🌟🌟🌟🌟🌟🌟🌟🌟🌟🌟🌟🌟🌟🌟

🌿🌿🌿🌿🌿🌿🌿🌿🌿🌿🌿🌿🌿🌿🌿🌿

✨✨✨✨✨✨✨✨✨✨✨✨✨✨✨✨

✅✅✅✅✅✅✅✅✅✅✅✅✅✅✅✅

🍋C++入门

🍑引用

🍍引用定义

在C++中,引用是已存在变量的别名,或者可以理解为这个已存在变量的另一个名字,通过将声明符&放在变量名前来定义引用。

c++ 复制代码
	int ret = 10;
	int& cur = ret;//定义引用类型
	cout << "cur = " << cur << endl << "ret = " << ret << endl;
	return 0 ;


注意:引用类型必须和引用实体是同种类型

🍍引用特性

(1)一旦引用被初始化为另一个对象,就不能在指向其它对象,但是一个对象可以有多个别名。

(2)引用必须在声明时被初始化,不然会报错。

(3)引用在声明时必须说明其类型。

(4)编译器不会为引用变量开辟内存空间,它和它引用的变量共用同一块内存空间。

🍍常引用

引用不能做常量的引用,不然会报错,如下图:

因为引用的是可以修改的值,而常量是定量不可以修改,在C语言中大家就知道const修饰的变量相较于普通的变量权限缩小,所以没有被const修饰的变量权限大于被const修饰的变量,所以在这里同样不可以如图中这样所写。

当然如果我们把引用的权限缩小,也可以实现上图中的写法,如下图:

🍍引用使用的场景

(1)做参数

大家不知道记得我们以前写的Swap()交换函数:

从图中,使用交换函数时,我们要传地址,还要用指针接受,有点麻烦了。

来看看引用做参数时的交换函数:

如图中的写法是不是看着就很舒服,以前写交换函数,可能大家还会遗漏地址,现在就很便利。

(2)做返回值

第一幅图中,使用的是传值返回,传值返回会创建一个中间的临时变量用来存储返回值,也就是最后返回的不是c而是c的拷贝,所以net就是接受实际运算的值。

而第二幅图,是引用返回,返回的是c的别名。调用函数会创建一个栈帧来存储临时的变量等信息,但是函数调用结束后这个栈帧就会被释放,再进行访问就会越界,所以cur的值就是返回值,但是在vs编译器中会进行优化,版本越高优化的越好,大家可以用其它编译器试试,所以返回的是确定的值。

🍍引用和指针的区别

引用和指针在编程中存在明显的区别。

首先,引用必须在声明时被初始化,而且一旦初始化后,就不能改变其引用的对象。这就意味着,引用具有更强的稳定性,并且不能被设为NULL。相对地,指针可以在任何时候被初始化,也可以指向NULL,并且可以随时改变指向的对象。这种灵活性虽然带来了更大的操作空间,但同时也增加了出错的可能性,使得指针在编程中相对更危险。

其次,从大小上看,引用的大小是所指向的变量的大小,因为引用只是一个别名而已。而指针的大小则是固定的,通常是指针变量自身在内存中所占的空间大小,例如在大多数32位系统中,指针的大小是4个字节。

最后,从使用的便捷性和安全性来看,引用具有优势。使用引用指向的内容时可以直接使用引用变量名,而不需要像使用指针那样使用*来解引用。同时,由于引用不能为空且不能改变指向,因此使用引用可以更安全地避免一些常见的编程错误。

总结:引用和指针在编程中各有其用途,但引用在稳定性和安全性上通常优于指针。在选择使用引用还是指针时,需要根据大家在实际应用中具体的编程需求和环境来决定。

🍑内联函数

🍍定义

内联函数是指在调用时,在函数调用处直接插入函数代码的函数。这种插入操作是由编译器在编译时自动完成的,而不需要在运行时进行函数调用。因此,内联函数可以消除函数调用的开销,包括参数传递和控制转移的开销,从而提高程序运行时的效率。

🍍特性

内联函数具有几个显著的特点:

代码替换:当编译器遇到内联函数的调用时,它会在调用点直接插入或替换函数的代码,而不是进行常规的函数调用。这消除了函数调用的开销,包括返回参数、执行return等过程。

提高执行效率:由于内联函数直接插入了函数调用处的代码,因此避免了函数调用的开销,从而提高了程序的执行效率。但是,如果内联函数体过大,会增加编译后的代码大小,可能导致程序运行时的空间开销增大。

定义与声明:内联函数的定义通常在头文件中进行,这样编译器在多处调用时都能见到定义。内联函数的声明和定义通常放在同一个头文件中。

编译时确定:内联函数的作用域规则与一般的函数相同。内联函数只是在调用时内联展开,而不是在定义时内联展开。如果编译器认为内联替换不能带来性能上的提升,它会忽略内联请求,将函数调用作为普通函数调用处理。

不能含有复杂的控制语句:内联函数体内不能有复杂的控制语句,如循环语句和switch语句,否则即使定义了内联函数,编译器也会把它当成普通函数来处理。

谨慎使用:虽然内联函数能够提升执行效率,但过度使用内联函数可能会使代码膨胀,增加编译后的代码大小,甚至可能导致程序性能下降。因此,应谨慎选择哪些函数作为内联函数。

总结:请注意,即使函数被声明为内联的,编译器也可以选择不内联该函数。这是因为编译器在编译时会考虑多种因素,如函数的大小、调用频率以及可能的优化效果等,来决定是否进行内联替换。

🍑auto关键字(C++11)

🍍类型别名

不管是在C语言中还是在C++中,我们都遇到过许多的类型别名,学习过程中我们遇到的类型别名越来越复杂,在实际的过程中也不方便我们书写,这个时候auto关键字的作用就体现出来了。

auto主要作用就是自动类型推断,简化了代码,提高了代码的可读性和可维护性。

🍍auto简介

Auto是一个在多个编程语境中都有特定含义的关键词。在早期的C/C++中,auto被用作存储类型指示符,主要表示局部变量的存储期。在函数内部定义的变量成为局部变量,它们在使用auto修饰时具有自动存储期,即这些变量在进入声明它们的程序块时被创建,当退出该程序块时它们会被撤销。

这个d的类型大家可能有点陌生,等大家学到后面会明白,这个也是字符串类型。

🍍auto的用途

迭代器:在遍历容器(如:std::vector、std::map等)时,迭代器的类型可能较为复杂,使用auto可以简化迭代器的声明和使用。

范围基于的for循环:C++引入的范围基于的for循环与auto结合使用,可以方便的遍历容器中的元素,而无需关心元素的具体类型。

模板编程:在处理模板函数或类时,auto能够自动推导那些难以手动指定的类型,从而简化了模板的编写和使用。

大概有常用的这三个用途,当然还有其它用途,在这里就不一一列举了。

大家比较熟悉的可能就是for循环了,我用for循环给大家演示演示。

两个的结果都是一样的,不过从图中大家应该能感受到auto使用的方便,特别是需要输入复杂类型的时候auto体现的作用更大。

🍍auto使用限制

函数参数:auto不能用于函数参数的类型声明。这是因为函数参数的类型必须在函数调用之前就已经确定,而auto类型是在编译时根据初始化表达式推导出来的。因此,在函数声明或定义时,函数参数不能使用Auto。

类的非静态成员变量:auto同样不能用于类的非静态成员变量的初始化。类的成员变量在类定义时就需要确定其类型,而auto类型的推导是基于初始化表达式的,这在类的成员变量上下文中并不适用。静态成员变量虽然可以在类外部定义和初始化,但也不能使用auto,因为静态成员变量的类型也需要在类定义时确定。

数组定义:auto不能用于定义数组。数组需要明确指定其元素类型和大小,而Auto只能推导出一个单一的类型,无法同时确定数组的类型和大小。

模板参数:auto也不能作为模板参数。模板参数需要在模板实例化时具有确定的类型,而auto类型的推导是基于具体的使用上下文的,这在模板参数中并不适用。

🍑基于范围的for循环(C++11)

🍍范围for的用法

在C++98中for循环遍历的方式:

而在实际应用过程中,对于有范围的集合由程序员来说明范围,明显是多余的,有的时候还会犯错误。因此在C++引入了基于范围的for循环。for循环后的括号由冒号" :"分为两部分:第一部分是范围内用于迭代的变量,第二部分则表示被迭代的范围:

当然在新的for循环中continue和break的作用依然有效。

🍍范围for使用规则

范围for循环在C++中是一种方便遍历容器(如数组、向量、列表等)或数组元素的语法结构。使用范围for循环时,需要满足一些特定的条件:

迭代对象的范围必须明确:对于数组,这意味着必须知道第一个元素和最后一个元素的范围。对于类或其他容器,通常应提供begin和end方法,这些方法定义了for循环迭代的范围。如果范围不确定,编译器会报错。

迭代的对象必须支持"++"和"==" 操作:这是因为范围for循环在内部使用迭代器来遍历元素,它需要能够递增迭代器(通过++)并比较迭代器(通过 ==)来确定何时结束循环。

容器必须支持迭代器,并且有begin和end函数:例如,队列(queue)不支持迭代器,因此无法使用范围for循环来遍历队列。如果尝试这样做,编译器会报错,指出容器没有begin或end成员函数。

上图中写法就是错的,因为不知道数组a的大小。

还有就是关于迭代器这个问题,大家目前还没有学到,现在了解一下就可以了

🍑指针空值nullptr(C++11)

🍍C++98中的指针空值

在C++98中,指针的空值通常使用宏NULL来表示。NULL在C++标准库头文件cstddef(通常通过包含cstdlib或旧式的stdlib.h间接包含)中定义,其值通常被定义为整数0或(void*)0。C++98中,将指针初始化为NULL是一种常见的做法,用于表示指针不指向任何有效的内存地址。

🍍C++11中的指针空值

需要注意的是,在C++11及以后的版本中,引入了一个新的关键字nullptr,它提供了更好的类型安全性和更明确的语义来表示空指针。nullptr的类型是std::nullptr_t,它不能与整数0混淆,并且可以自动转换为任何指针类型。因此,如果你正在使用C++11或更高版本,就使用nullptr来初始化指针,而不是NULL,NULL在C++11或者更高版本中使用会报错。

C++入门篇的知识点就讲解完毕了,如果还有些知识点没讲到,欢迎大家指正,我会及时完善。


相关推荐
_oP_i11 分钟前
Pinpoint 是一个开源的分布式追踪系统
java·分布式·开源
mmsx14 分钟前
android sqlite 数据库简单封装示例(java)
android·java·数据库
bryant_meng17 分钟前
【python】OpenCV—Image Moments
开发语言·python·opencv·moments·图片矩
武子康40 分钟前
大数据-258 离线数仓 - Griffin架构 配置安装 Livy 架构设计 解压配置 Hadoop Hive
java·大数据·数据仓库·hive·hadoop·架构
若亦_Royi41 分钟前
C++ 的大括号的用法合集
开发语言·c++
资源补给站2 小时前
大恒相机开发(2)—Python软触发调用采集图像
开发语言·python·数码相机
豪宇刘2 小时前
MyBatis的面试题以及详细解答二
java·servlet·tomcat
秋恬意2 小时前
Mybatis能执行一对一、一对多的关联查询吗?都有哪些实现方式,以及它们之间的区别
java·数据库·mybatis
m0_748247552 小时前
Web 应用项目开发全流程解析与实战经验分享
开发语言·前端·php
6.942 小时前
Scala学习记录 递归调用 练习
开发语言·学习·scala