网上学习资料一大堆,但如果学到的知识不成体系,遇到问题时只是浅尝辄止,不再深入研究,那么很难做到真正的技术提升。
一个人可以走的很快,但一群人才能走的更远!不论你是正从事IT行业的老鸟或是对IT行业感兴趣的新人,都欢迎加入我们的的圈子(技术交流、学习资源、职场吐槽、大厂内推、面试辅导),让我们一起学习成长!
💡本章重点
- 了解
C++
入门基础语法 - 了解
C++11
的新特性
🍞一.命名空间
💡命名空间:
- 在
C++
中,变量、函数和类都是大量存在的,这些变量、函数和类的名称将都存在于全局作用域中,可能会导致很多冲突 - 使用命名空间的目的是对标识符的名称进行本地化,以避免命名冲突或名字污染,
namespace
关键字的出现就是针对这种问题的
👆简单来说:
- 就是很好的解决了
C语言
中的命名冲突的问题【Eg:自己写的函数名字与官方库里函数名字相冲突】 - 做到了名字隔离的作用
➡️命名空间定义: namespace
➕命名空间名字➕{命名空间的成员}
namespace
:为C++
中的关键字- 命名空间的成员:可以是函数、变量、类……
- 命名空间整体组成了一个域:命名空间域
👉示例:
👆通过上述的示例不难看出:
- 红色框框住的为
std库
中的库函数,打印出来的便是库函数的函数地址 - 黄色框框住的为
Dream_Y_ocean
这个命名空间域的strlen
、scanf
这两个变量,打印出来便是这两个变量的地址
❗这里便涉及两个知识点:
- 1️⃣在搜索变量的时候,程序遵循的是
就近原则
:即先从局部域
开始寻找,如果没有匹配的再去全局域
【包括:全局变量、头文件(库)】中寻找 - 但并不会进
命名空间域
里寻找,即命名空间域
对于程序来说是个独立的空间,没有使用者的允许,是不会主动进去寻找的,这也就是为什么说命名空间域
很好的解决了命名冲突的问题,起到了名字隔离的作用 - 这也解释了示例中为什么前两个打印的是库中函数的函数地址
- 2️⃣域作用限定符(
::
)
🥐Ⅰ.域作用限定符
💡域作用符:
- 要想要调用
命名空间域
中的成员的话,我们需要用到域作用限定符(::
) - 简单来说:就是限定域作用限定符(
::
)后面的成员是来自前面空间名字对应的命名空间域 - 即一个命名空间就相当于定义了一个新的作用域,命名空间中的所有内容都局限于该命名空间中
➡️用法: 想要调用的命名空间域的空间名➕::
➕调用的命名空间域的成员
❓这里我们便可以思考一下如下代码经常出现在C++语言中的含义
using namespace std;
如上代码就代表着:
- cpp为了防止命名冲突,把自己库里面的东西都定义在一个叫
std
的命名空间中 - 而我们如果要调用std库里的成员,就有三种方式:
std::
➕要调用的成员 :此方式是最规范的写法using namespace std;
:此方式相当于把std
这个命名空间域里所有成员展开到全局域中
- 虽然方便日常的我们使用,但会使我们后续的命名可能会与标准库中的命名相冲突
- 所以在规范的工程项目中是不推荐这种方式的
using std::
➕要调用的成员:此方式就是介于前两种之间,可以用于对常用的成员进行展开,这样后续再调用这些成员就更加方便,也更加规范了
❗特别注意:
- 若单独
::➕要调用的成员
,这样子表示在全局域中寻找要调用的这个成员
🥯Ⅱ.总结
⭐综上:
- 命名空间中的内容,既可以定义变量,也可以定义函数
- 命名空间是可以嵌套的【相对应的:调用的时候也需要嵌套调用】
- 同一个工程中允许存在多个相同名称的命名空间,编译器最后会自动合成同一个命名空间中
🍞二.缺省参数
💡缺省参数:
- 缺省参数是声明或定义函数时为函数的参数指定一个默认值
- 在调用该函数时,如果没有指定实参则采用该默认值,否则使用指定的实参
👉示例:
1️⃣全缺省参数【即给函数的所有参数都给上缺省值】
👆从示例中不难发现:
- 我们对
MoonCake
函数的缺省值为0
- 若调用
MoonCake
函数的时候没有传参数,则函数会利用缺省参数的值(0
)充当参数,进而在函数内部被使用 - 若调用
MoonCake
函数的时候有传参数,则函数会利用实参的值赋值给形参(100
),进而在函数内部被使用
2️⃣半缺省参数【即给函数的部分参数给上缺省值】
👆从示例中不难发现:
- 我们对
MoonCake
函数的形参nums
没有给缺省值,形参size
给的缺省值为10
- 若调用
MoonCake
函数的时候没有传形参size
,则函数会利用其缺省参数的值(10
)充当形参size
参数,进而在函数内部被使用 - 若调用
MoonCake
函数的时候有传参数,则函数会利用实参的值赋值给形参(100
),进而在函数内部被使用
❗特别注意:
- 半缺省参数必须从右往左依次来给出,不能间隔着给【这是因为参数是从左往右传给形参的,若中间隔着给缺省值的话,程序便不知道哪个实参对应哪个形参(但实际形参入栈的时候:是从右往左入栈)】
- 缺省参数最好不要在函数声明和定义中同时出现【若两个位置提供的缺省值不同,会给编译器造成歧义不知道该用哪个缺省值】
- 缺省值必须是常量或者全局变量
🥯Ⅰ.总结
⭐综上: 缺省参数是C++中新添加的语法,使调用函数时变得更加灵活了
🍞三.函数重载
💡函数重载:
- 是函数的一种特殊情况,C++允许在同一作用域中声明几个功能类似的同名函数
- 这些同名函数的形参列表(参数个数 或 类型 或 顺序)必须不同,常用来处理实现功能类似数据类型不同的问题
👆简单来说:
- 即实现了允许可以同时有多个同名函数的存在,且同名函数可以用来解决不同的实际问题【即赋予了函数不同的意义】
- 本质是为了解决C语言中不允许同名函数问题而出现的
❗特别注意:
-
构成函数重载,必须满足(三者满足其一即可):
- 函数参数的个数不同
- 函数参数的类型不同
- 函数参数的顺序不同
👉示例:
👆从示例中不难发现:
-
我对写了两个名字同为
Add
的函数,它们之间构成函数重载(因为函数参数的类型不同) -
可以看出编译器会根据我们函数参数的类型去匹配相对应的函数进行调用
-
其中之所以第二个
Add
函数也输出2
,是因为其返回值的类型为int
,使其原本返回类型为double
的值被强制转换类型为int
- 这也侧面反映了:构成函数重载的因素只与
参数
有关,与返回值得类型
无关
- 这也侧面反映了:构成函数重载的因素只与
❓想必同学们都会产生如下例子中的问题:下列两个函数是否构成函数重载
⭐答案是:构成函数重载,但并不能通过编译
- 这是因为这种代码在执行的时候有可能产生歧义,导致编译器不知道该执行哪个函数,最终调用不明确,编译失败
🥯Ⅰ.面试真题
💡在面试中,会经常出现如上知识点的相关问题:
- C语言为什么不支持函数重载
- C++又是怎么支持函数重载的
👆以上问题,可以都归结于一个原因:
- 函数名修饰规则
➡️简单来说:
-
我们调用函数,在汇编时期本质是通过指令
call 函数实现的汇编指令的地址
的 -
而对于函数是声明和定义分开在不同的文件时,并不会一开始就找到函数实现的汇编指令的地址:
-
1️⃣而是因为有了
函数声明
,在编译阶段就让这个指令暂时通过(即地址处暂时空出),此时编译器会认为函数定义
在其它地方,后续链接
时再找函数定义的地址 -
2️⃣
链接
的时候:拿着函数名去找其函数实现的汇编指令的地址,具体是在其它文件的符号表中搜索地址- 只要找到就放入地址
- 找到不到就相当于
链接失败
-
-
⭐所以这也就为什么:
- C语言中不支持函数重载,是因为C语言中函数实现的汇编指令的地址是根据函数名称去匹配的,面对同名函数编译器链接的时候无法区分,所以链接失败
- 而C++支持函数重载,是因为函数名经过了
函数名修饰规则
【即现在的函数名不是直接拿原函数名作为名字,而是通过_Z+原函数名的长度+原函数名+函数参数的类型的首字母
的规则进行修饰,这也就为什么构成重载函数的三个要求都与函数参数
有关】,这样就可以同名函数从而链接到地址
🥯Ⅱ.总结
⭐综上: 正是有函数名修饰规则
的加持下,让C++相较于C语言上有了更加丰富的实现
🍞四.引用
💡引用:
- 引用不是新定义一个变量,而是给已存在变量取了一个别名,编译器不会为引用变量开辟内存空间,它和它引用的变量共用同一块内存空间
👆简单来说:
- 就是对一个已有的变量起一个别名【类似于指针,只不过指针是指向变量的地址,但需要给指针这个变量开辟空间】
- 而引用本质还是自己,只是自己有了一个新的名字,但本体还是自己,所以对引用的修改会影响自身
❗特别注意:
- 引用类型必须和引用实体是同种类型的
- 引用在定义时必须初始化
- 一个变量可以有多个引用
- 引用一旦引用一个实体,再不能引用其他实体
👉示例:
👆从示例中不难发现:
- 我将变量
MoonCake
起了一个别名MoonCake1
- 通过打印地址也可以证明它们其实是在同一块空间,这也就证明了
引用
本质就相当于对引用对象的那块空间起多一个变量名字而已
🥯Ⅰ.权限问题
1️⃣权限放大问题
const int MoonCake = 10;
int& YueBing = MoonCake;
❓同学们觉得如上操作是正确的的吗
❗其实是错误的,这是因为:
MoonCake
这个变量被const
所修饰,变成常变量,拥有常属性,在这种情况下后续的操作中是不允许对MoonCake
这个变量的值进行修改的- 而如果用
int&
进行引用的话,那YueBing
这个别名就表示可以对MoonCake
本身就行读和写 - 即
const
修饰的变量只允许读,不能写,而现在别名
竟然可以对自身读和写,这样就属于对自身权限放大
问题
👆那我们该如何修改呢:只需要匹配权限即可
- 即在引用类型将
int&
改为const int&
即可权限相匹配
2️⃣权限缩小问题
int MoonCake = 10;
const int& YueBing = MoonCake;
❓同学们觉得如上操作是正确的的吗
❗是正确的,这是因为:
- 变量本体是允许读和写,而引用后这个
别名
的权限只有读
- 但这样并不会影响本体,因为
别名
的权限小于本体
✨综上:
- 只要引用后的
别名
权限<=
本体权限即可
🥯Ⅱ.常引用
❓同学们觉得如下操作是正确的的吗
int MoonCake = 10;
double& YueBing = MonnCake;
👆在解答上述问题前,我们先了解一下这个机制:以如下代码为例子
int c = 10;
double d = 1.11;
d = c;
➡️同学们肯定知道上述代码在d = c
中会发生隐式类型转换
- 但
隐式类型转换
并不是将c
的值直接转换后赋值给d
- 而是编译器会自动产生一个临时变量(我们看不见),类型为转换后的类型,最后再将这个临时变量的值赋值给
d
【即我们接收的是临时变量的值】
✨综上:
- 不仅仅是
隐式类型转换
,还是强制类型转换
or函数值返回
……只要会发生类型偏差的,本质并不是对本体产生影响,而是产生一个值相同、转换类型后的临时变量(具有常属性)
✊有了以上的了解补充后,我们再看回最初的疑问:操作其实是错误的
- 因为
double&
引用的是隐式类型转换后的临时变量,而非MoonCake
- 又因为临时变量具有
常属性
,所以这属于权限放大
问题,只有引用类型为const double&
才匹配权限 - 且这样的引用后续如果修改
MoonCake
的值,对YueBing
这个别名是没有任何影响的,因为我们本质是引用一个临时变量
而非MoonCake
🥯Ⅲ.使用场景
💡引用常见的使用场景有两个:
- 做参数
- 做返回值
🧇1.做参数
- 以上这种情况属于做
输出型参数
🧇2.做返回值(少数情况)
💡在深入了解前,我们先作补充:
既有适合小白学习的零基础资料,也有适合3年以上经验的小伙伴深入学习提升的进阶课程,涵盖了95%以上大数据知识点,真正体系化!
由于文件比较多,这里只是将部分目录截图出来,全套包含大厂面经、学习笔记、源码讲义、实战项目、大纲路线、讲解视频,并且后续会持续更新
- 做参数
- 做返回值
🧇1.做参数
- 以上这种情况属于做
输出型参数
🧇2.做返回值(少数情况)
💡在深入了解前,我们先作补充:
[外链图片转存中…(img-efNj2ZN8-1715111020306)]
[外链图片转存中…(img-95lRjWfb-1715111020306)]
[外链图片转存中…(img-TSZbOqNt-1715111020307)]
既有适合小白学习的零基础资料,也有适合3年以上经验的小伙伴深入学习提升的进阶课程,涵盖了95%以上大数据知识点,真正体系化!
由于文件比较多,这里只是将部分目录截图出来,全套包含大厂面经、学习笔记、源码讲义、实战项目、大纲路线、讲解视频,并且后续会持续更新