| |
|
开发:
C++知识库
Java知识库
JavaScript
Python
PHP知识库
人工智能
区块链
大数据
移动开发
嵌入式
开发工具
数据结构与算法
开发测试
游戏开发
网络协议
系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程 数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁 |
-> C++知识库 -> 【C++学习】C++入门知识(上) -> 正文阅读 |
|
[C++知识库]【C++学习】C++入门知识(上) |
到这里,本喵的C语言学习暂时就告一段落了,开始C++的学习了,同样的,本喵会在《C++学习》专栏中记录本喵的学习过程,分享自己的所学所得,下面开始C++的介绍。 C++入门(上)🍜什么是C++?
1979年,贝尔实验室的本贾尼等人试图分析unix内核的时候,试图将内核模块化,于是在C语言的基础上进行扩展,增加了类的机制,完成了一个可以运行的预处理程序,称之为C with classes。 语言的发展就像是练功打怪升级一样,也是逐步递进,由浅入深的过程。我们先来看下C++的历史版本。
总得来说,C++就是在弥补C语言的一些不足之处,所以它是完全兼容C语言的,而且在C语言的语法基础上产生了一些新的语法和新的用法。 下面我们来看看C++中的新语法。 🍜C++关键字(C++98)C++总计63个关键字,C语言32个关键字
🍜命名空间
🍛命名空间定义正常的命名空间定义: 来看一段程序:
这里就涉及到一个程序在编译时符号名的查找顺序,根据上面程序,我们知道,查找的顺序是先查找局部的,当局部中没有时再查找全局的。
但是在C++中,像上面这种符号名重复的情况是可以的,这个时候就需要使用到C++中的域,这里是指命名空间。
上面重名的这种情况就可以将全局变量rand放在命名空间中,代码如下:
namespace关键字:
通俗一点的理解就是,命名空间相当于给我们创建的变量建了一个围墙,别人是看不到围墙里的东西的,只有通过域作用限制符(::)将围墙里的东西告诉外面的人,别人才能知道里面有这么一个东西。
我们在C语言中是尽量避免使用全局变量的,因为全局变量很有可能在某个函数中使用到,从而造成全局变量的修改,而C++中使用了命名空间就很好了避免了这个问题。 比如要统计学校中大一大二和大三各个年级的人数:
有了命名空间,我们在变量命名的时候就不用再顾及那么多了。 命名空间可以嵌套: 当然,命名空间也是支持嵌套的,比如表示机械学院中大一大二大三中各个年级各个班中的人数。
同一个工程中允许存在多个相同名称的命名空间,编译器最后会合成同一个命名空间中: 在命名空间中,不仅能够定义变量,而且可以定义函数: 知道这里为什么报错吗? 因为将函数Add定义到了命名空间中,没有使用域作用限制符告诉编译器这里有Add函数,所以编译器找不到我们定义的这个函数。 这样就能正常打印出我们要的结果30了。 在C语言中写函数的时候,定义和声明是分开的,那么对于这种情况,命名空间是怎么使用的呢?
🍛命名空间使用加命名空间名称及作用域限定符: 这种方法在上面介绍命名空间的时候已经详细介绍过了。 使用using将命名空间中某个成员引入: 可以看到,我们使用命名空间中的变量的时候,命名空间的名字需要在每个变量名前面都写一次,这样做感觉的有的繁琐,如果使用的变量有100个呢?此时就需要写100次命名空间的名字。 有没有一种办法,像C语言一样,直接使用变量名就行呢?C++中提供了一种方法。
只有加上这句话,在后面的程序中就可以直接使用命名空间中的该变量,相当于将该变量放在了围墙外面。 还是上面的代码,可以看到,此时就不需要再写变量名所在的命名空间了,直接像C语言中一样使用变量就可以。 使用using namespace 命名空间名称引入 是否又发现了一个问题,现在是可以将命名空间中的某个变量在程序中直接使用了,不用再加命名空间,那么,如果命名空间中有1000个变量,并且都要使用呢?难道要写1000次上面那个语句吗? 这里C++又提供了一种方法
此时,命名空间中的所有变量都可以在下面的程序中直接使用了,都不用再写命名空间的名字了,也不用挨个将命名空间中的变量释放出来。
注意:
在C++程序中,我们通常在程序的最前面会看到 using namespace std 这样一个语句,这个语句的意思是什么呢?很多小伙伴都认为它是C++程序中必须有的,记住就行了,只要写C++程序就需要写这么一句话,这是错误的。 在上面我们也写了函数,而且是放在命名空间中的,C++中也有很多的库函数,像cout,cin等等,就类似于C语言中的print和scanf这样的库函数,官方提供的库函数都写在了一个名字为std的命名空间中。
下面看一个例子,回想一下,在学任何编程语言时,最开始都是在屏幕上打印hello world,我们就用这个来举列:
🍜输入和输出在上面我们用C++的语法打印出了hello world这个问候语,下面再演示输出一些别的内容。 输出数据
对比C语言中的printf你发现有什么不同了吗?
所以说,到底使用cout还是printf需要我们自己来决定,哪个方便用哪个,因为C++是完全兼容C语言的。 再来看一个输入的例子:
这里有几点说明:
🍜缺省参数🍛缺省参数概念来看一段代码:
这里将打印a的值封装在一个函数func中,在main函数中将实参a的值传给了形参a,从而打印出a的值。 如果这里不给形参会发生什么? 我们知道,在C语言中,必须有实参传过去才行,否则就会报错,但是在C++中就可以不传实参。
再来看一段代码:
这段代码的结果是什么?是10还是20,其中10函数func的缺省参数,20是调用func传递的实参。
根据定义就可以得出,有缺省参数的函数,在调用的时候,如果没有实参传入,那么在函数中就使用缺省参数,如果有实参传入就使用传入的实参。 🍛缺省参数分类
这种情况下,函数的形参全部都是缺省参数,有无实参传入都可以。
注意:
在使用缺省参数时,还有几个需要注意的事项,这是针对所有含有缺省参数的函数的。
为什么不能在函数的声明和定义中同时写缺省参数呢? 来看下面的这张图:
所以在函数声明和函数定义中都有缺省参数的情况时,仅在函数声明中写就可以了。
既有函数声明又有函数定义,但是将函数的缺省参数只写在了函数定义中,函数的声明中没有,所以就报错了。 编译器此时是听函数声明的,它认为这个函数没有缺省参数,所以必须有实参传入。
常量我们在上面已经看到了,下面我们来看变量的情况: 此时缺省参数的值采用的是全局变量a和b的值,结果和我们预想的一样是30。 再看局部变量的情况:
🍛缺省参数的应用说了那么多,缺省参数有什么作用呢?你可能觉得我以前C语言中的实参和形参对应就挺好啊,这个缺省参数有什么用呢? 那栈来举列,来看栈初始化的代码: 我们在对栈初始化的时候,需要开辟动态空间,这个空间该开辟多少个呢? 在【数据结构】栈和队列中我们采用的是realloc实现的,每次插入数据时都需要判断一下空间是否够用,不够用就扩容。 但是扩容是有代价的,原地扩容还好,只是在原来的空间的基础上再增加一些空间,但是异地扩容就需要将原本的数据在复制到一个新的位置。 我们这里采用在初始化的时候就将栈的空间开辟好,这样就避免了扩容,从而避免了扩容产生的不好后果。如上图中的代码,我们这里开辟了100个int型的空间。 可以看到,我们必须提前知道需要多少空间才能进行传参,进而开辟动态空间,但是如果我们不知道需要多少空间呢? 这个时候就用到缺省参数了:
当我们清楚的知道需要开辟多少个空间的时候也可以直接将实参传过去。 🍜函数重载🍛函数重载的概念
函数重载也是这样,即一个函数名对应着多个函数,如:
这种情况在C语言中是绝对不被允许的,函数名是不可以重名的,只能打印整数的函数用一个函数名,打印浮点数的函数用另一个函数名。 这就是C++中的函数重载。 🍛函数重载的类型
在调用该函数的时候,实参是int类型和int类型的时候,调用的就是形参是int和int类型的Add函数。 实参是double类型和double类型的时候,调用的就是形参是double和double类型的Add函数。 这对重载函数的参数类型不同。
上图中的代码,两个Add函数的参数个数是不同的,上面的参数个数是0个,下面的参数个是1个。 在调用该函数的时候,实参是没有参数的时候,调用的就是形参个数是0的类型的Add函数。 实参个是1个的时候,调用的就是形参个是1个的类型的Add函数。 这对重载函数的形参个数是不同的。
上图中的代码,两个Add函数的参数的类型顺序是不同的,上面的参数类型顺序是int,char,下面的参数类型顺序是char,int。 在调用该函数的时候,实参的类型顺序是int,char的时候,调用的是形参类型顺序是int,char的func函数。 实参的类型顺序是char,int的时候,调用的是形参类型顺序是char,int的func函数。 这对重载函数的参数类型顺序不同。 既然说到顺序不同也构成重载函数,那么看下面一段代码:
它们的顺序是不一样,但是这俩个形参的类型是一样的,都是int类型,所以不能构成重载函数。 构成重载函数时的形参类型顺序不同,形参类型必须是不同的。 知道了什么是函数重载以后,再结合下前面的知识,带有缺省参数的函数可以重载吗?
调用该函数的时候,由于俩次调用都传进去了int类型的数据,所以调用的都是下面的func函数。 我们知道,带有缺省参数的函数是可以不传实参的,再进行如下调用:
这个现象称为调用时的二义性。 通过上面俩段程序可以看出,带有缺省参数的函数是可以重载的,但是在调用的时候要明确调用哪个,像上面的例子第一个函数就无法调用,因为无法在调用时明确的调用。 总之,只要在调用的时候不产生二义性,带有缺省参数的函数也是可以重载的。 还记得前面在讲解输入输出的时候,cout函数和cin函数可以自动识别类型吗?到这里你应该明白了,它之所以能够自动识别变量的类型,也是因为函数重载,具体的实现在以后的学习中会给大家讲解。 🍛函数重载的实现现在已经知道了C++中有函数重载,那么函数重载是怎么实现的呢? 这里本喵简要的介绍一下,在后面的学习中会有更加深入的介绍。 在本喵的文章程序环境和预处理中曾讲解过,一个C程序运行起来需要经历以下几个阶段:预处理、编译、汇编、链接,C++程序也是这样的。
C语言中函数名的修饰只是简单的在函数名的前面加一个下划线_。 C++中的函数名也会被修饰,并且它的修饰规则比C语言中复杂很多,我们来看windows下的名字修饰规则: 再看上面我们写过的重载函数的代码: 该代码在编译的过程中,它俩个函数名都经过了修饰,修饰后的符号名分配了不同的地址,来看反汇编中的代码: 可以看到,给俩个函数名Add分配了俩个不同的地址,一个地址表示的是形参是int,int类型的函数,另一个地址表示的是形参是double,double类型的函数。 通过上面的分析我们知道,虽然我们写的重载函数的函数名是一样的,但是经过编译器修饰以后,函数名就不一样了,并且分配了不同的地址,在调用该函数的时候,编译器会自动匹配实参和形参的类型,去相应的地址调用相应的函数。 注意: 在了解了函数重载是怎么调用的以后,本喵提出一个问题,返回类型不同可不可以构成函数重载? 按照编译器将函数名进行修饰这个逻辑是可以的,无非就是再加一些符号表示不同的返回类型,这样就可以实现返回类型不同的函数重载。 但事实上并没有这么干,看下面程序:
虽然构成返回类型不同的重载函数理论上是可行的,但是我们在调用函数的时候是无法规定被调用函数的返回类型的,所以这种重载函数是不存在的。 总的来说,返回类型不同的函数无法构成重载函数的原因是调用时的二义性。 同样无法区分调用的哪个函数,因为调用时并不指定返回类型。 篇幅有限,我们下篇见。 |
|
C++知识库 最新文章 |
【C++】友元、嵌套类、异常、RTTI、类型转换 |
通讯录的思路与实现(C语言) |
C++PrimerPlus 第七章 函数-C++的编程模块( |
Problem C: 算法9-9~9-12:平衡二叉树的基本 |
MSVC C++ UTF-8编程 |
C++进阶 多态原理 |
简单string类c++实现 |
我的年度总结 |
【C语言】以深厚地基筑伟岸高楼-基础篇(六 |
c语言常见错误合集 |
|
上一篇文章 下一篇文章 查看所有文章 |
|
开发:
C++知识库
Java知识库
JavaScript
Python
PHP知识库
人工智能
区块链
大数据
移动开发
嵌入式
开发工具
数据结构与算法
开发测试
游戏开发
网络协议
系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程 数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁 |
360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年11日历 | -2024/11/23 9:54:17- |
|
网站联系: qq:121756557 email:121756557@qq.com IT数码 |