c++ 基础(新手入门必看)_c++新手

阿里云国内75折 回扣 微信号:monov8
阿里云国际,腾讯云国际,低至75折。AWS 93折 免费开户实名账号 代冲值 优惠多多 微信号:monov8 飞机:@monov6

C++基础讲解用于C语言向C++的衔接

文章目录

命名空间

如果你以前看到过C++的程序那么你大概率会看到这样一行代码
在这里插入图片描述
这行代码就用到了命名空间的知识using就是使用的意思namespace就是命名空间std就是这个命名空间的名字。
C++的命名空间顾名思义就是在某一空间内对一些类型变量常量结构体函数等进行命名。
在这里我进行示范写下一个命名空间
在这里插入图片描述
注意这里命名空间内的两个变量是全局变量而不是局部变量。这里我就不得不提一下只有定义在函数内的变量才是局部变量为什么因为局部变量存储在栈区而函数的调用会创建栈帧函数结束时栈帧会销毁并且局部变量随之销毁。
而命名空间内的变量是全局变量它们存储在静态区。并且我顺便提一下局部变量存储在栈区全局变量存储在静态区动态内存开辟的空间存储在堆区。
还有就是我们头文件里的变量属于什么在预处理时头文件就被展开了所以头文件内的变量其实也属于全局变量。
并且编译器默认的查找规则是先在局部找再到全局找。并且如果有了命名空间直接去指定的命名空间内找当命名空间内也找不到这个这个名字的话就会报错而不会继续去别的地方找。
命名空间如何使用
在这里插入图片描述
这时候我们发现我们用不了a刚才不是说a是全局变量吗这里为什么用不了原因是命名空间就像无形的一堵墙一样它把它内部的变量全都关住了别人根本就找不到它。
如果要想使用就必须加上名称空间标示符。
在这里插入图片描述
但是如果我们要大量地使用a这个变量的话每次都加上名称空间标识符岂不是很麻烦
所以我们也有其他的方法
在这里插入图片描述
如果我们不只是频繁地使用这个命名空间中的一个变量而是频繁地使用其他变量的话也可以这样表示。

在这里插入图片描述
我们明白了这个之后再解释解释经常看到的那个命名空间。
在这里插入图片描述
std 是C++官方库内定义的命名空间。C++官方库内有许多文件每个文件内的命名空间都为std这样并不会导致冲突因为不同位置的同名命名空间会合并为同一个命名空间。
上面那条语句的作用相当于把std展开把它里面所有的东西都暴露出来这样使用就很方面了。
但是这样又有一些不足我们在日常写一些小程序的时候这样写没什么问题但是项目里不要这么写容易引起和自己定义的变量引起冲突。
我们在项目里面可以进行这样使用。
在这里插入图片描述
把常见的名字这样单独拿出来在自己起名字的时候避开这些常见的就可以了。

另外命名空间也是可以嵌套的比如
在这里插入图片描述

总结通常来说命名空间是唯一识别的一套文字这样当相同的名字却来自不同的地方的时候就不会含糊不清了。也就是说命名空间的使用可以避免命名的冲突。同时命名空间的展开又可以分为局部展开全部展开也可以不展开在使用的时候加上标识符即可。

C++输入输出

C++的输入输出我们作为新手不需要过多的了解只要会使用即可。
在这里插入图片描述
cin相当于C语言的输入函数cout相当于C语言的输出函数。与C语言中输入输出函数不同的是cin和cout可以自动识别变量的类型。

缺省参数

定义缺省参数是在函数声明或者定义时为函数的参数指定一个缺省值在函数调用时如果没有指定的实参则形参的值为缺省值否则就为指定的实参。
在这里插入图片描述
当函数的参数中有多个参数具有缺省值时则有不同的传参方法。

在这里插入图片描述
并且传参是连续的必须从左到右传参不能只给c传参而不给a和b传参。
注意函数的声明和定义中不能同时出现缺省参数防止出现声明和定义中缺省参数不一样的尴尬局面。如果函数同时有声明和定义的话要把缺省参数放在声明中。

函数重载

定义函数重载是函数的一种特殊情况C++允许在同一空间内定义功能类似且名字相同的函数这些函数的参数参数类型参数个数参数顺序不同常用来处理功能类似但数据类型不同的问题。

在这里插入图片描述
就像这样我们定义两个add函数实现函数重载就不用在意我们要相加的两个数是整数还是浮点数了。

但是函数重载不能与缺省参数结合起来使用就像这样。
在这里插入图片描述
你不传参进去编译器不知道你想调用哪一个函数。

为什么C语言不支持函数重载而C++可以C++存在名字修饰
C语言编译之后函数名不会发生变化。而C++编译之后编译器用根据函数的参数类型对编译器进行修饰这就是名字修饰。

为什么同名函数的参数相同而只有返回值不同不会进行函数重载
这并不是因为名字修饰时不会带上返回值的类型而是因为在调用函数的时候具有二义性编译器不知道函数要返回什么类型的值。

引用

引用就相当于给变量取别名使得变量在同一空间内有多个名字。
在这里插入图片描述
你对引用操作和对引用的实体操作的是一样的。
在这里插入图片描述

并且这和指针不一样指针是指向a这个变量的地址。而引用就是引用的实体它们两个是一样的。
对引用和引用的实体取地址你就明白了。
在这里插入图片描述
引用的特性

  1. 引用必须进行初始化
  2. 一个变量可以有多个引用
  3. 一个引用一旦引用了一个实体就不能引用其他实体了

Java和Python的引用是可以改的但C++不可以。
从这方面看C++的引用不可能会代替指针。就比如在写一个链表的时候如果要遍历一个链表我们会用到一个链表节点的指针并且不断改变这个指针的指向如果用引用的话就不能实现这个功能了。

引用的使用场景

  1. 作参数
    在这里插入图片描述
    这里也可以用指针但是用引用效率会更高一些。

  2. 作返回值
    引用是可以作为返回值的并且效率比较高但只适用于特定的情况下
    要明白这个道理首先我我们要明白传值返回和传引用返回的区别

在这里插入图片描述
这样是可以的为什么可以int类型的变量用static修饰之后会存储在静态区而不会存储在栈区这样在函数的栈帧销毁之后n这个变量就不会随之销毁了这个时候n还是存在的我们把它的值拷贝给ret当然是可以的。

在这里插入图片描述
这样也是可以虽然在函数栈帧销毁之后存储在函数栈帧的n也随之销毁但是在销毁之前会把n的值保存起来具体保存在哪里需要看变量的大小如果变量较小就会保存在寄存器中如果变量较大就会保存在上一层函数的栈帧中。所以这是可以的虽然n不存在了但是n的值已经被保存下来了我们可以将保存的这个值拷贝给ret。

在这里插入图片描述
这样呢我们将引用作为返回值返回的就不是n了而是n的引用。此时和第一种情况一样n仍然是存在的所以n的引用的值和n是相同的我们用ret是可以得到n的值了。

在这里插入图片描述
这样就会出现问题了编译时虽然可以通过并且ret的值也可能是我们想要的但是存在一些风险。
在返回引用时可就不会像第二种情况临时拷贝一份n的值并保存起来了而是直接返回不关心n是否被销毁。这样的话n已经被销毁再返回n的引用的我们可以根据引用来找到n但是得到的值是不确定的。
首先我们应该好好想想n被销毁了也就是说保存n的空间被销毁了。
空间被销毁了空间还存在吗存在只是没有了这个空间的使用权了而已。
空间被销毁了我们还能访问那可以只是访问得到的值不确定了这块空间上的值可能还是原来的值也可能值是随机的也可能空间被别人使用了从而值被修改了。

如果你不明白我给你打一个比方
空间的申请和释放就像住酒店你申请一块空间就像开一个房间你释放这块空间就像退房。假如你退房之后悄悄地赔了一把这个房间的钥匙然后你仍然可以进入这个房间虽然这是非法的。但是如果你原来在房间内放了一个苹果你再次进入这个房间之后这个苹果的情况你确定吗它可能还是原来的苹果也可能被别人咬了一口还有可能这个苹果被换成了梨。
那你空间释放之后你再访问这个空间的变量就像你再次非法进入了这个房间虽然你能访问虽然你能进去但是得到的值可能是原来的值苹果还是原来的苹果也可能值不确定了苹果被咬了一口还有可能这个值被其他的值替换了苹果被换成了梨
在这里插入图片描述
你也可以看下这种情况如果你返回引用并且用ret这个引用来接收那么ret就是n的引用我们打印ret的值ret可能是原来的值但是之后调用test2这个函数之后原来n的空间存的1就被100覆盖了这个时候ret的值也就变为100了。

说了这么多我就是要说明传引用返回在一些情况下是不适用的。

只有变量在被static修饰的时候传引用返回才是可以的这个时候我们就相当于是把苹果放在了酒店的前台不管我们上面时候去拿这个苹果它也都是原来的苹果。
在这里插入图片描述
并且当大量调用这个函数时用传引用返回是最好的因为它的效率比较高。
那么关于传引用返回的一些细节就介绍到这里。

关于引用也有一些奇妙的东西下面我们一起来看一下。

引用和指针一样在赋值时权限可以缩小但不能放大。
在这里插入图片描述
当变量是只读时引用的权限也只是只读。

很多时候用引用作参数都将引用设为了只读可以避免权限的放大。
在这里插入图片描述
但是有些要对变量进行修改的函数就不能作为const了比如swap。

并且用const修饰的实体可以为常量。
在这里插入图片描述

再来看一些好玩的东西。

我们知道类型转换的时候会产生临时变量
在这里插入图片描述
不管是加括号的强制类型转换还是隐形转换都是产生了一个转换后的临时变量然后将这个临时变量赋值给其他变量。

并且临时变量具有常性是不可以修改的。如果用要引用的实体和引用不同那么引用的实体也会产生一个转换后的临时变量然后将它赋值给引用同时因为临时变量不可修改引用必须要加const来修饰。
在这里插入图片描述

同时如果要用引用接收函数的返回值也要加const修饰。刚才我们提到返回值是临时拷贝了一份然后再赋值给接收的变量刚才我们又说临时变量是不可修改的所以用来接收返回值的引用也要加const修饰。
在这里插入图片描述

引用占空间吗引用在语法上面它只是一个名字是不占空间的。但是在底层实现上引用是用指针实现的它是占有一定空间的。

引用和指针的对比

  1. 引用在概念上是一个变量的别名而指针是存储变量的地址。
  2. 引用必须初识化而指针不用
  3. 引用在引用一个实体之后就不能引用其他实体但指针可以改变指向。
  4. 没有NULL引用但有NULL指针
  5. 使用sizeof括号内是引用得到引用的实体的大小括号内是指针得到存储地址的大小。
  6. 引用自加则实体也会自加而指针自加表示则向后偏移一个类型的大小
  7. 有多级指针但是没有多级引用
  8. 引用的解引用编译器会处理而指针的解引用需要程序员来处理
  9. 引用比指针更加安全

内联函数

定义以inline关键字修饰的函数是内联函数在如果调用该内联函数编译时会直接将函数体展开在程序中而不会建立栈帧从而提升了程序运行的效率是一种以空间换时间的做法
若要大量使用某个函数同时又不想建立栈帧C语言可以使用宏来进行处理。
但是宏是有很多确定的

  1. 宏不可以进行调试
  2. 宏没有类型安全的检查
  3. 宏会因为优先级的问题而产生许多不可预料的结果

基于这个方面C++的方案是内联函数。
在这里插入图片描述
这样的话就既有了函数的优点又具有了宏的优点。

不是所有的函数都适合内联比如递归函数和比较长的函数就不适合一般内联函数都是在十行以内。

关于内联函数我们需要知道以下几点

  1. inline是一种以时间换空间的做法若使用内联函数在编译阶段就会将该调用内联函数的地方替换为函数体就不需要进行函数栈帧的创建和销毁了。这样做的缺点是会使目标文件变大优点是不需要进行函数栈帧的创建和销毁大大提高了程序的运行效率
  2. 内联函数的使用是向编译器发出了一个使用的建议而具体使用不使用还是取决于编译器如果内联函数规模较大就是比较长具体标准是多少取决于编译器或者用到了递归又或者是频繁地调用编译器就会忽略这个内联的特性。为什么会这样防止代码膨胀
  3. 如果使用内联函数定义和声明不能分离在不同文件中分离会导致链接错误。因为在编译阶段内联函数就被展开了地址也就不存在了链接也就找不到了。

auto关键字

在这里插入图片描述
使用auto声明指针类型时auto和auto*没有区别但是使用auto声明引用类型必须使用auto&。

在这里插入图片描述
auto不能作为函数参数并且auto也不能声明数组。

基于范围for循环

它就是用来更方便地遍历一个数组
在这里插入图片描述

这样写没有效果不能真的将数组元素乘2为什么
在这里插入图片描述
因为x只是数组元素的临时拷贝

正确的写法是这样的
在这里插入图片描述
并且这里我们不能用指针因为我们每次取到的是每个元素的值而不是每个元素的地址

在这里插入图片描述
就比如你在这个函数内对arr进行sizeof得到的只是arr这个数组首元素地址的大小而已。

指针空值 – nullptr

在C++中空指针有两种表示方式。
在这里插入图片描述
并且NULL的值就是0
在这里插入图片描述
这是因为
在这里插入图片描述可以看到NULL可能被定义为字面常量0或者被定义为无类型指针(void*)的常量。不论采取何种定义在使用空值的指针时都不可避免的会遇到一些麻烦比如
在这里插入图片描述
这样就存在二义性了程序本意是想通过f(NULL)调用指针版本的f(int*)函数但是由于NULL被定义成0因此与程序的初衷相悖。
在C++98中字面常量0既可以是一个整形数字也可以是无类型的指针(void*)常量但是编译器默认情况下将其看成是一个整形常量如果要将其按照指针方式来使用必须对其进行强转(void *)0。

语言的更新有一个原则就是不变动原来的语法规则随意变动原来的语法规则会导致原来的许多程序崩溃而是加入新的特性。

所以在C++11中我们引入nullptr这个关键字。

注意

  1. 在使用nullptr表示指针空值时不需要包含头文件因为nullptr是C++11作为新关键字引入的。
  2. 在C++11中sizeof(nullptr) 与 sizeof((void*)0)所占的字节数相同。
  3. 为了提高代码的健壮性在后续表示指针空值时建议最好使用nullptr。

好啦看到这里你已经走出了C++的新手村继续向后学习吧

阿里云国内75折 回扣 微信号:monov8
阿里云国际,腾讯云国际,低至75折。AWS 93折 免费开户实名账号 代冲值 优惠多多 微信号:monov8 飞机:@monov6
标签: c++