C++——入门基础(上)

从今天开始就步入C++的学习道路了,又是一条漫长的学习道路。


目录

C++关键字

命名空间

        命名空间的定义

        命名空间的使用

C++输入和输出

缺省参数

        全缺省参数

        半缺省参数

函数重载

        extern  "C"

引用

        引用的特性

        常引用

        使用场景

        引用和指针的区别


C++关键字

       C语言中有关键字,比如sizeof等,在C++中也同样有关键字,而且C++兼容C语言,所以C语言中的关键字在C++中也可以使用。

       C++总计63个关键字,C语言32个关键字:
C++——入门基础(上)_第1张图片

       虽然在这里把关键字都罗列出来,但是并不会去挨个介绍,留到后面再去讲解,有了例子介绍这些关键字也方便记忆。


命名空间

       在C/C++中,变量、函数和后面要学到的类都是大量存在的,这些变量、函数和类的名称将都存在于全局作用域中,可能会导致很多冲突。使用命名空间的目的是对标识符的名称进行本地化,以避免命名冲突或名字污染,namespace关键字的出现就是针对这种问题的。namespace也是我们要介绍的第一个关键字。
       简单来说,在以后的工作中,每个人写一个模块,最后把这些拼到一起时,总会出现变量名或者函数名的冲突,那个人也不愿意改,因为很麻烦,那怎么办呢?
       这样命名空间就起到了作用,每个人把自己的命名放到自己创建的命名空间中就不会冲突了,在写代码之前先讲清楚命名空间的名字,不要起冲突,但是C语言就做不到,所以C++也可以说是填补C语言的坑,或者把C语言中不好用的改进。讲到这里看不懂不要紧,认真看下面的讲解你就明白了。
在这之前多多少少都会看到这样的C++代码:

        命名空间的定义

       定义命名空间,需要使用到namespace关键字,后面跟命名空间的名字,然后接一对{}即可,{}中即为命名空间的成员。
C++——入门基础(上)_第2张图片

        命名空间的使用

定义完了就该讲讲怎么用了

C++——入门基础(上)_第3张图片

       这里报错了,可是我上面明明定义了一个a,在命名空间n1中啊,那下面就介绍命名空间的使用方式。

第一种:加命名空间名称及作用域限定符

C++——入门基础(上)_第4张图片

这个符号 " :: " 就是作用域限定符, 在变量前加上就可以使用这个命名空间中的变量了.

第二种:  使用using将命名空间中成员引入

C++——入门基础(上)_第5张图片

  

第三种:  使用using namespace 命名空间名称引入

C++——入门基础(上)_第6张图片

       在最后还要说一点就是,在以后的工作中不要直接把std标准命名空间直接展开,可以用哪个展开哪个, 展开常用的。


C++输入和输出

Hello World!!!又和我们见面了,同样在C++中也来写一个简单的代码吧。

C++——入门基础(上)_第7张图片

说明:

1. cout是标准输出(控制台)cin是标准输入(键盘), 使用这两个必须包含< iostream >头文件以及std标准命名空间
2. 使用C++输入输出更方便, 不需增加数据格式控制, 也就是在C语言中, 想要输入和打印必须使用%d之类的, 输入的时候的&也不能忘, 但是C++就要方便很多。
C++——入门基础(上)_第8张图片

而且C++还可以自动识别类型

C++——入门基础(上)_第9张图片省去了很多麻烦的操作,再也不用因为丢失&而报错了。 

但是这样写就不能像printf一样可以指定域宽和小数点后几位了。


缺省参数

缺省参数,一个好笑的讲法就是:C++函数参数的备胎。

缺省参数是声明或定义函数时为函数的参数指定一个默认值。在调用该函数时,如果没有指定实参则采用该默认值,否则使用指定的实参。
C++——入门基础(上)_第10张图片

        全缺省参数

C++——入门基础(上)_第11张图片

全缺省参数必须从左往右依次来给出,不能说给b的值不给a
C++——入门基础(上)_第12张图片

        半缺省参数

C++——入门基础(上)_第13张图片

这样函数传参至少要传一个 。

注意:

       1. 半缺省参数必须从右往左依次来给出,不能间隔着给,比如b是缺省参数,a和c都不是,这样就不行。
C++——入门基础(上)_第14张图片

       2. 缺省参数不能在函数声明和定义中同时出现,比如在头文件中声明的缺省参数是10,在.cpp文件中定义的缺省参数是20, 这样编译器就不知道该用哪个值了。
C++——入门基础(上)_第15张图片
3. 缺省值必须是常量或者全局变量
4. C语言不支持(编译器不支持)

函数重载

       函数重载:是函数的一种特殊情况,C++允许在同一作用域中声明几个功能类似的同名函数,这些同名函数的形参列表( 参数个数 类型 顺序 )必须不同,常用来处理实现功能类似数据类型不同的问题。
C++——入门基础(上)_第16张图片
判断函数重载最重要的就是上面标红的: 形参的 参数个数类型顺序这些必须不同。

为什么C++支援函数重载,而C语言不可以了?
这里我们要回顾一下以前的知识,在运行到执行文件前,要经过:预编译,编译,汇编,链接这些阶段其实问题就出在编译完之后的汇编阶段,因为在这里C++和C语言有着些许的不同,这里使用linux操作系统可以明确地看出区别。

下面我们来看看:

采用C语言编译器编译下: 

C++——入门基础(上)_第17张图片

注意红色的箭头

采用C++编译器编译下

C++——入门基础(上)_第18张图片

注意红色箭头 

       可以看出, 用C语言编译的函数名字的修饰没有发生改变; 而C++编译的函数名字的修饰发生了改变。

       这就得提到Linux下的修饰规则:

C语言函数修饰不变, 而C++的函数修饰后变成了【_Z+函数长度+函数名+类型首字母】

       这里看不懂没有关系简单来说就是: C语言的函数名字没有修饰, C++的函数名字会修饰。

       通过这里就理解了C语言没办法支持重载,因为同名函数没办法区分。而C++是通过函数修饰规则来区 分,只要参数不同,修饰出来的名字就不一样,就支持了重载。
       另外我们也理解了, 为什么函数重载要求参数不同了, 而跟返回值没关系,因为返回值的类型也不会像参数类型一样被修饰到函数名上。

        extern  "C"

       有时候在C++工程中可能需要将某些函数按照C的风格来编译在函数前加extern "C",意思是告诉编译器,将该函数按照C语言规则来编译。
       所以当我们使用C语言来编译的时候, 使用到了C++的接口, 那么这个问题就可以使用entern "C"来解决。

引用

       引用不是新定义一个变量,而是给已存在变量取了一个别名,编译器不会为引用变量开辟内存空间,它和它引用的变量共用同一块内存空间。
        
       类型& 引用变量名(对象名) = 引用实体
       &这个符号在这里就不是取地址的意思了。
 
       定义一个变量a, 然后b是a的别名, 可以看到一开始都是0, 改变a, b也跟着改变, 改变b, a也跟着改变, 最后两个变量的地址是一样的, 也就是共用同一块内存空间。
C++——入门基础(上)_第19张图片

引用类型必须和引用实体同种类型

        引用的特性

1. 引用在定义时必须初始化

C++——入门基础(上)_第20张图片

如果不初始化就相当于起了一个别名不知道是给谁的。 

2. 一个变量可以有多个引用

C++——入门基础(上)_第21张图片

  

3. 引用一但引用了一个实体, 再也不能引用其他实体

C++——入门基础(上)_第22张图片

        常引用

首先我们来看一下这段代码为什么会出错

C++——入门基础(上)_第23张图片

看最下面那个错误,无法从"const int"转换为"int &",const修饰的a只有读的权限,而引用的ra具有读写的权限,这是明显的权限被放大了,改为const int& ra = a;就可以了。

权限放大不可以,那权限缩小可不可以呢?

C++——入门基础(上)_第24张图片

答案是可以的,从可读可写变成只读,所以权限不能放大,但是可以缩小

C++——入门基础(上)_第25张图片

这个改为const int& b = 10; 就可以了,因为10是常量,所以用const修饰一下就可以用了。

C++——入门基础(上)_第26张图片

这里改为const double& rd = i; 就可以了,这是为什么呢?

       因为整型转换成浮点型会有一个隐式类型转换,在这个过程中i会产生一个临时变量,这个临时变量是double类型的,再把这个临时变量赋值给rd,临时变量是具有常性的,常性的权限是只读的,如果不加const是可读可写的,所以必须用const修饰才可以使用。

       常引用和之前讲解的const常量修饰是一个道理,在函数传参的时候,如果参数不改变,那么尽量用const引用传参

        使用场景

1. 做参数

C++——入门基础(上)_第27张图片

2. 做返回值

在介绍这个使用场景之前,先来看一下这两个程序

C++——入门基础(上)_第28张图片C++——入门基础(上)_第29张图片

      

       左图调用函数, 在静态区创建了n, 因为static定义的全局变量, 当Count函数调用完之后, 这块函数栈帧会被销毁, 返回位于静态区的n。C++——入门基础(上)_第30张图片

        右图在调用完函数后, n的值记录在寄存器中, Count函数栈帧被销毁, 再返回寄存器中的值。C++——入门基础(上)_第31张图片

上面这两段属于传值返回, 都会生成一个返回对象, 返回这个对象中拷贝的返回值。

再看一下这两段程序

C++——入门基础(上)_第32张图片C++——入门基础(上)_第33张图片

       左图Count函数的返回类型是引用, 下图的tmp相当于n的别名, 当Count函数栈帧销毁后, n这块空间就返还给操作系统了, 操作系统清理栈帧的时候会置成随机值, 但这块儿空间还是被返回到了ret中, 形成了越界访问, 虽然最后的值是正确的, 原因可能还没有来得及置成随机值。所以这段程序使用引用返回本质上是不对的

 C++——入门基础(上)_第34张图片

       右图的意思是tmp和ret都是n的别名, tmp是在返回的时候定义的, Count函数栈帧销毁的时候, 还是把这块空间返回到了main函数的栈帧中。

C++——入门基础(上)_第35张图片

       和左图说的一样, 这里打印的还是这块已经还给操作系统空间的值, 第一次打印, 操作系统可能没来得及置成随机值, 但第二次就是随机值。

 C++——入门基础(上)_第36张图片

所以, 出了函数作用域, 返回对象就销毁了的一定不能用引用返回, 必须用传值返回。  

       综合以上观点,这样写才能用引用返回,因为创建的全局变量在静态区,函数栈帧在栈区创建,它的作用域不会销毁。

C++——入门基础(上)_第37张图片

  

       以值作为参数或者返回值类型,在传参和返回期间,函数不会直接传递实参或者将变量本身直接返回,而是传递实参或者返回变量的一份临时的拷贝,因此用值作为参数或者返回值类型,效率非常低下,尤其是当参数或者返回值类型非常大时,效率就更低。

        引用和指针的区别

语法概念上引用就是一个别名,没有独立空间,和其引用实体共用同一块空间。
但在底层实现上实际是有空间的,因为引用是按照指针方式来实现的。

C++——入门基础(上)_第38张图片

例如这段代码,我们可以通过调试来看看,转到反汇编的界面

C++——入门基础(上)_第39张图片

       左边是用引用的,右边是用指针的,不需要看懂它是怎么操作的,但是可以看出左右两边的操作都是一样的。

       从语法角度而言,引用没有开辟空间,指针开了4或8字节;从底层角度而言,引用底层是用指针实现的。

引用和指针的不同点:
从介绍引用到现在,已经提到过这两者很多的不同点。
介绍引用的特性时:
1. 引用在定义时必须初始化,指针没有要求。
2. 引用在初始化时引用一个实体后,就不能再引用其他实体,而指针可以在任何时候指向任何一个同类型实体。
指针和引用的用途基本是相似的
1. 引用结果为引用类型的大小,但指针始终是地址空间占4或8字节。
引用比指针使用起来相对更安全:
指针更强大,更危险,更复杂;引用相对局限一些,但是更安全。

你可能感兴趣的:(C++,c++,c语言)