C++入门

目标

C++是在C基础上容纳进去面向对象的编程思想,并增加了许多有用的库,本文主要目标
1.补充C语言语法不足,以及如何进行优化的 2.为类和对象的学习打基础

1.命名空间

在全局作用域中用到的变量,函数和类的名称会面临命名冲突的问题:1.跟库冲突 2.程序员相互之间的冲突。C语言没法解决该问题,于是C++提出namespace来解决。

在这里插入图片描述
1.首先了解namespace关键字,后面跟命名空间的名字,然后接一对{},空间中为成员名。
2.需要通过using namespace 空间名;来展开,否则编译时不会去命名空间域中搜索。
3.可以通过using ywb::a;使用using将命名空间中某个成员引入。

在这里插入图片描述

  1. ::为域作用限定域,用来指定访问命名空间域,::左边为空代表全局变量
    2.通过结果打印可以看出访问域的顺序为 局部域—>全局域—>展开了的命名空间域or指定访问命名空间域

在这里插入图片描述
1.需要注意直接展开命名空间域会有风险,我们如果定义跟库重名将报错。该段代码若展开,定义的rand和头文件<stdlib.h>中将冲突。建议项目指定访问,不要轻易展开命名空间!
2.该段代码第一次打印通过::指定访问命名空间域来打印rand,第二次由于没有在main函数中定义rand局部变量,编译器会到全局作用域查找,在预处理阶段展开的头文件中包含rand的定义,编译器将视为对rand的调用,通过%p来打印标准库中rand的地址

在这里插入图片描述
1.命名空间中可以定义变量,函数和类型
2.命名空间中可以嵌套,如图中ywb套用lyh
3.同一工程中允许存在多个相同名称的命名空间,编译器最后合成同一个命名空间中

2.C++输入&&输出

在这里插入图片描述
1.std是C++标准库中的命名空间名,C++将标准库的定义实现都放到这个命名空间中
2.标准输出对象(控制台)cout,标准输入对象(键盘)cin,使用时必须包含头文件,cout和cin是全局流对象,endl是特殊的C++符号,表示换行输出
注意:为了和C头文件区分,也为正确使用命名空间,规定C++头文件不带.h

在这里插入图片描述
1.<<是流插入运算符,>>是流提取运算符,C++的输入输出可以自动识别变量类型
2."“用于界定字符串字面量,是用来表示字符串的。图中” "中间空格用来形成分隔,和下行C的输出对比功能类似。

std命名空间使用惯例:
1.日常练习可直接using namespace std,很方便
2.展开std标准库就全部暴露出来了,存在冲突问题。在项目开发中代码较多规模大,容易出现该问题。所以在项目开发中std::cout或using std::cout,使用指定命名空间和展开常用的库对象或类型的方式较推荐

3.缺省参数

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

3.1缺省参数的分类

  • 全缺省参数

在这里插入图片描述

  • 半缺省参数

在这里插入图片描述

3.2注意

1.缺省参数应当出现在函数声明中,若在定义中同时出现,编译器会因为无法确定使用哪个默认值而报错。
在函数声明中出现有一下好处:
1.1分离接口与实现,便于维护
1.2编译器处理机制中,编译阶段调用函数依赖函数声明中信息,若缺省参数在定义中,可能因无法获取默认值而报错。可避免二义性,若声明和定义分离且声明中未指定缺省值,调用时需显示传参会触发编译错误。
1.3特殊情况:若直接在函数内部定义(隐式内联),则声明和定义合二为一,此时缺省参数可直接写在函数定义中
2.缺省值必须是常量或全局变量
3.半缺省参数必须从右往左依次给出,不能间隔着给,未缺省的参数必须位于左侧。参数传递遵循从左到右的顺序,若允半缺省参数间隔存在,调用时无法明确参数对应关系。调用时只能省略右侧参数,确保左侧参数必须显示赋值,避免遗漏。
4.C语言编译器不支持

4.函数重载

概念:C++允许在同一作用域中声明几个功能类似的同名函数,这些函数的形参列表(参数个数 或 类型 或 类型顺序)不同。返回值没要求

在这里插入图片描述
在这里插入图片描述

在这里插入图片描述
可以看出不仅需要判断是否构成重载,还需要注意有效性

4.1C++支持重载函数的原理-函数名修饰过程(编译链接)

在这里插入图片描述
Windows下vs的修饰规则过于复杂,而Linux下g++修饰规则简单易懂,下面采用g++演示修饰后的名字

采用C语言编译器的后果。在Linux下采用gcc编译完成后函数名字修饰没变
在这里插入图片描述
采用C++编译器的后果。在Linux下采用g++编译完成后函数名字修饰变化,编译器将函数参数类型信息加到修改后的名字中。
在这里插入图片描述
通过这里就理解了C语言没办法支持重载,因为同名函数没办法区分。而C++是通过函数修
饰规则来区分,只要参数不同,修饰出来的名字就不一样,就支持了重载。 如果两个函数函数名和参数是一样的,返回值不同是不构成重载的,因为调用时编译器没办法区分。

5.引用

概念:引用不是新定义一个变量,而是给已存在变量取了一个别名,编译器不会为引用变量开辟内存空间,它和它引用的变量共用同一块内存空间。

类型& 引用变量名(对象名) = 引用实体:引用类型必须和引用实体是同种类型的
在这里插入图片描述

5.1引用特性

  1. 引用在定义时必须初始化
  1. 一个变量可以有多个引用
  2. 引用一旦引用一个实体,再不能引用其他实体

5.2使用场景

5.2.1做参数

在这里插入图片描述
在这里插入图片描述
可以代替指针操作,使用起来更加方便。引用做参数(输出型参数),引用做参数(减少拷贝提高效率)

5.2.3做返回值

在这里插入图片描述
return返回的不是n本身,而是一份临时拷贝,存储在count的栈帧中,若用static修饰将存储在静态区,不会随栈帧的销毁而改变。

在这里插入图片描述
可以看出引用做返回值,可以直接修改返回值
以值作为参数或者返回值类型,在传参和返回期间,函数不会直接传递实参或者将变量本身直接返回,而是传递实参或者返回变量的一份临时的拷贝,因此用值作为参数或者返回值类型,效率是非常低下的,尤其是当参数或者返回值类型非常大时,效率就更低。

总结:基本任何场景都可以引用传参,谨慎引用返回值,出了函数作用域,对象不在了,就不能引用返回,还在就行。

5.2.4权限问题

在这里插入图片描述

权限放大指通过引用或指针获得了比原变量更高的访问权限
引用过程中权限不能被放大,临时变量具有常性,指不可被修改的特性,表现为默认const修饰,仅作为中间值使用防止意外修改。图中只能修改x而不能是z

在这里插入图片描述
比较两图发现若是引用过程中权限被放大的话,需要加const修饰

必须使用const修饰的场景:
1.常量绑定,否则权限放大
2.临时变量:函数返回的临时对象或类型转换(跨类型引用)产生的中间变量默认具有常性,必须用const接收
3.函数参数传递:若函数参数需要接收常量或临时变量需用。

5.2.5引用和指针的区别

汇编代码对比
在这里插入图片描述

引用和指针不同点
在这里插入图片描述

6.内联函数

概念:以inline修饰的函数叫做内联函数,编译时C++编译器会在调用内联函数的地方展开,没有函数调用建立栈帧的开销,内联函数提升程序运行的效率。

与宏定义函数的相比
优点-- 不需要建立栈帧,提高调用效率
缺点-- 复杂,容易出错、可读性差、不能调试

在这里插入图片描述
在这里插入图片描述
在汇编代码中func通常是自定义的函数标签,用于标记一段可重复调用的代码块。call func()表示调用函数地址,inline就没有这一步。汇编语言中func:()表示一个函数的起始地址,作为函数标签入口,在函数重载中可参考。

辨析:1.假如有一个编译后为50行指令的func函数不是inline,有1000个位置调用它,每次调用它时call func获取地址,合计有1000+50行指令 2.假如func是inline,那么将在1000个位置展开,总共有1000*50行代码。由此可知内联函数不是适用于所有函数的。

内联函数特性:
1.使用于短小且频繁调用的函数
2.inline对于编译器仅是一个建议,最终是否成为inline,编译器自己决定。像类似一下函数加了inline也会被否决 2.1比较长的函数 2.2递归函数
3.inline不能声明与定义分离,分离会导致链接错误,因为inline被展开,就没有函数地址了,链接找不到。所以inline通常在头文件中声明定义一起,这样需使用时只需包含头文件即可

默认debug模式下,inline不会起作用,否则不方便调试。在release模式下会查看编译器生成的代码中是否存在call func。所以需要对debug模式下进行设置
在这里插入图片描述

7.auto关键字

概念:是一个可自动推导类型的指示符,auto声明的变量必须由编译器在编译时期推导而得。

使用规则:
1.auto定义变量时必须对其进行初始化,在编译阶段根据初始化表达式来推导auto的实际类型。因此auto并非是一种类型的声明,而是一个类型声明时的占位符,编译器在编译阶段会将auto替换为实际类型的变量。
2.auto声明指针类型时,用auto和auto*没有任何区别,但用auto声明引用类型时必须加&
3.当在同一行声明多个变量时,这些变量必须是相同的类型,否则编译器将会报错,因为编译器实际只对第一个类型进行推导,然后用推导出来的类型定义其他变量。
4.auto不能作为形参类型,因为编译器无法对a的实际类型进行推导
5.auto不能直接用来声明数组

8.基于范围的for循环

for循环后的括号由冒号“ :”分为两部分:第一部分是范围内用于迭代的变量,第二部分则表示被迭代的范围。
在这里插入图片描述
现在是初步了解,后续将继续了解关于迭代器的问题

9.指针空值nullptr

NULL实际是一个宏,在传统的C头文件(stddef.h)中,可以看到如下代码:
在这里插入图片描述
C语言中被定义为无类型指针(void*)的常量,而C++禁止void*隐式转换为其他类型被定义为字面常量0。C++引用nullptr的概念解决NULL二义性问题

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值