ARTICLE · INTELLIGENCE

战地情报 · 详情页

来自尧图项目组的一线实战观察与深度解析

【C++基础】命名空间与引用

【C++基础】命名空间与引用

1.命名空间

1.1命名空间的作用

在C++中,如果在局部和全局变量中创建同名的一个变量,那么调用的时候会优先调用局部变量,而在C++中要调用全局变量就需要用到命名空间了,这也是C++相对于C语言新增的功能

如图所示
同样的,命名空间可以防止变量名和函数名字冲突

可以看到,由于rand在头文件<stdio.h>中已被定义,所以调用会失败

可以看到,在命名空间中定义的变量就可以防止冲突。

本质上来说,命名空间是单独开出来的一个域来创建变量
C++中,一共有四个域,分别是函数局部域,全局域,命名空间域,类域 ,域实际上是通过编译时对函数,变量等进行隔离
此外,函数局部域和全局域还会影响变量的生命周期,命名空间域和类域则不会影响
所以在命名空间中的变量与头文件中的rand属于不同域,所以调用时不会冲突
命名空间只能定义在全局变量中,并且可以进行嵌套定义。

1.2命名空间的使用

命名空间共有三种使用方法
1.指定命名空间访问

像这种方式 ,::就是访问命名空间的操作符好
2.用using展开命名空间中的指定成员

3.直接展开整个命名空间(在项目中会=不推荐此写法)

2.C++输出流

c++的输入输出流是类似于c语言中的printf/scanf函数的,这里介绍三个常用的输出流:

  • cout:类似于prinf
  • cin: 类似于scanf
  • endl:相当于换行符,并且刷新缓冲区

这三个函数都放在⼀个叫std(standard)的命名空间中

与C语言不同的是,这些输入/输出流可以自动识别变量的类型,十分方便。
<<,>>在C++中被称为流插入和流体去运算符
举个例子

3.缺省参数

与C语言不同,C++在定义函数时,可以直接和函数的形参赋值,如果在调用时没有给实参,那么最后会直接使用默认的缺省参数

可以看到调用函数时未传递实参,编译器直接用缺省值计算
缺省函数分为全缺省和半缺省
全缺省就是全部形参给缺省值,半缺省就是部分形参给缺省值。C++规定半缺省参数必须从右往左
依次连续缺省,不能间隔跳跃给缺省值。
带缺省参数的函数调⽤,C++规定必须从左到右依次给实参,不能跳跃给实参。

intAdd(inta=10,intb=10,intc=10)//全缺省intAdd2(inta,intb=10,intc=10)//半缺省intmain{cin<<Add()<<endl;cin<<Add(10)<<endl;}

需要注意的是,当函数声明和定义分离的时候,必须在声明式就给缺省参数!

4.函数重载

在c++中,同一作用域内是可以有同名函数的,但要求函数的参数要不一样,要么是类型不同,要么是个数不同:

需要注意的是,返回类型不同时不能算作函数重载1,因此不算构成重载函数

编译器此时也给出了报错

5.引用

5.1概念和定义

引用相当于给变量起了一个别名,与指针不同的是,指针会创造额外的空间来储存地址,而引用不会。

5.2引用的特性

  1. 引用的时候必须初始化,这也是和指针不同的。
  2. 一个变量可以有多个引用。
  3. 一个引用也可以被引用。
  4. 一个引用只能引用一个对象。

5.3引用的使用


引用的主要作用是引用传参和引用做返回值,前者是为了改变引用的同时改变被引用对象的值(类似于传地址)

后者则是为了减少临时变量的创建和拷贝以提高效率

如上图所示,假如返回类型为int,那么在将值返回的过程中,会创建临时变量,导致效率变低,如果返回类型是int& ,则说明返回的是一个引用,并不会创建额外的变量

并且在特殊场景中,返回类型为引用还有特殊的作用,例如取栈顶元素的过程,如果用引用做返回类型,那么就可以直接更改栈顶元素,因为返回来的是栈顶元素的引用,改变它就相当于改变栈顶元素,十分方便

但返回类型为引用时要注意一个问题,假如想要引用的对象是在栈区上创建的,那么这个对象出了函数就会销毁,就会导致引用变成一个空引用(类似于空指针)

5.4const引用

被const修饰的变量也可以被引用,只不过必须被const引用引用

而const引用既可以引用普通变量,也可以引用被const修饰的变量

本质上是权限的放大缩小问题(权限可以缩小,不能放大)

权限放大时会报错

权限缩小时编译器通过

当原变量未被const修饰时,它的权限是较大的,因此它既可以被普通引用引用,也可以被const引用引用

当原变量被const修饰时,假如它要被普通引用引用,这是不行的,因为原变量不可以被更改,引用之后变成了可以被修改,使权限放大了,这是不行的

还有两种特殊情况

这两个报错其实根本上是同一个原因

a+b在被c引用的过程中会创建一个临时变量,相当于这个临时变量被c给引用了,而临时变量具有常量性,必须在前面用const修饰

第二个也是类似的,e原本类型是double,当要被d引用时,因为d引用是int类型引用,因此在引用的过程中会发生类型转换,在类型转换的过程中同样也会创建临时变量,临时变量具有常量性,所以前面必须用const修饰

5.5 引用和指针的区别

  1. 引用不会创建空间,指针会
  2. 引用必须初始化,指针可以不用初始化(建议初始化,避免野指针)
  3. 引用只能引用一个对象,指针可以改变它指向的对象
  4. 在使用sizeof时,指针的大小是取决于平台的类型的,32位平台4个字节,64位平台8个字节,引用则取决于引用对象的数据类型
  5. 引用可以直接访问对象,指针需要解引用才能访问
  6. 指针会经常出现空指针或野指针的情况,引用则不会

6内联函数

内联函数和宏函数很像,内联函数会在编译的时候展开函数,宏函数则会在预处理的时候直接进行文本的替换,展开函数,可因为宏函数的使用很容易出现bug ,所以c++中新增了内联函数来替代宏函数

我们先来回顾一下宏函数

#defineAdd(a,b)(a+b);#defineAdd(a,b)a+b#defineAdd(a,b)(a+b)

以上均为错误写法!!!

正确的写法为

#defineAdd(a,b)((a)+(b));

综上所述,宏函数写的时候时长会出现一些小bug,因此我们可以改用内联函数

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

inlineintAdd(inta,intb){returna+b;}

还有一个很有意思的点,为了避免程序员滥用内联函数,即使你加上了inline,如果编译器认为inline会导致消耗变多,那么它并不会展开函数,也就是说inline只是一个建议,如果编译器认为你的建议不合理,那么就不会听从你的建议
所以尽量在遇到函数内部较简单,并且此函数调用次数过多的时候,推荐使用内联函数
(对于递归函数,代码相对多⼀些的函数,加上inline也会被编译器忽略。)

在debug模式下,内联函数是默认不会展开的

7nullptr

nullptr和c语言中的NULL很像,但是由于NULL经常会被直接替换成0,所以c++中有了新的关键字nullptr,它只会隐式地转换为任意类型的空指针,并不会转换为0,因此可以避免想用指针时用到NULL的尴尬问题,所以在c++中,一般都采用nullptr

本篇文章到此就结束了,希望能对大家有所帮助,也希望大家多多指出文章的不足,让我们一起进步,谢谢大家观看!!!

RELATED READING

延伸阅读

更多一线实战笔记与深度复盘,助您持续精进