| |
|
开发:
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++的输入和输出1.使用cout标准输出(控制台)和cin标准输入(键盘)时,必须包含< iostream >头文件以及std标准命名空间; 2.cout和cin是全局的流对象,endl是特殊的C++符号,表示换行,他们都包含在头文件中; 3.<<是流插入运算符,>>是流提取运算符; 4.使用C++输入输出更方便,不需增加数据格式控制(printf、scanf需手动控制格式),比如:整形–%d,字符–%c。C++的cout能够自动识别类型; 5.cout和cin分别是ostream和istream类型的对象,>>和<<也涉及运算符重载,后续再学习。
对于printf和cout,哪一个使用方便就用哪一个。 【注意】:早期标准库将所有功能在全局域中实现,声明在.h后缀的头文件中,使用时只需包含对应头文件即可(<iostream.h>),但是后来将其实现在std命名空间下,为了和C头文件区分,也为了正确使用命名空间,规定C++头文件不带.h();旧编译器(vc 6.0)中还支持<iostream.h>格式(没有命名空间),后续编译器已不支持,因此推荐使用 缺省参数(默认参数)缺省参数是声明或定义函数时为函数的参数指定一个默认值。在调用该函数时,如果没有指定实参,则采用该默认值,否则使用指定的实参。
全缺省
半缺省
【注意】:
函数重载函数重载概念一个词可以有多重含义,人们可以通过上下文来判断该词真实的含义,即该词被重载了。 函数重载: 是函数的一种特殊情况,C++允许在同一作用域中声明几个功能类似的同名函数,这些同名函数的形参列表(参数类型不同、参数个数 不同或 顺序不同)必须不同,常用来处理实现功能类似数据类型不同的问题。 函数重载的要求满足下面一条即可:
1.缺省值不同,不能构成重载
针对的是参数的类型,个数、顺序,这里类型相同,个数相同,顺序相同,所以不能构成重载。 2.能构成重载,但是存在问题
修饰后的函数名不同,这两个函数可以构成重载,但是在调用时,存在问题,F()到底是调用哪一个? 以下两个函数不能构成重载,参数类型,参数个数都相同,仅仅是参数名不同,并不能构成重载。
如果只是返回值不同,并不能构成函数重载(报错),因为调用的时候不能区分是哪个函数。 名字修饰windows下,VS是根据文件后缀去调用对应的编译器,.c就是c编译器;.cpp就是c++编译器。 在Linux下不用文件后缀来区分编译器,gcc就是c编译器,g++就是c++编译器。 为什么C不支持函数重载,C++支持函数重载? 在此之前,我们学习过在C/C++中,一个程序要运行起来,需要经历以下几个阶段:预处理、编译、汇编、链接。
1.预处理阶段:头文件在源文件中展开(展开后就没有头文件了)、宏替换、条件编译、删除注释(生成.i文件) 2.编译:检查语法、生成汇编代码(指令级语言代码)(生成.s文件) 3.汇编:汇编代码转换成二进制机器码、形成符号表(生成.o文件)每个源文件都会生成自己的符号表 4.链接:合并段表,生成可执行程序(a.out) 下面,在Linux下,分析为什么C语言不支持函数重载,而C++支持函数重载。 C语言不支持函数重载的原因:在编译时,两个重载函数,函数名相同,符号表中有两个相同的函数名,那么符号表中存在歧义和冲突,其次链接的时候也存在歧义和冲突,因为他们都是直接使用函数名去表示和查找,而重载函数的函数名相同,必然会有冲突。【在linux下,采用gcc编译完成后,函数名字的修饰没有发生改变。】 C++支持函数重载的原因:C++的目标文件符号表中不是直接用函数名来标识和查找函数,而是对函数名进行修饰。【在linux下,采用g++编译完成后,函数名字的修饰发生改变,编译器将函数参数类型信息添加到修改后的名字中。】 对于函数名的修饰规则,在不同的编译器下不同,在linux下,g++编译器中,函数修饰后变成【_Z+函数长度+函数名+形参类型的首字母】。
链接的时候,main函数里面去调用两个重载的函数,查找地址时,也是明确的。 注意:如果在当前文件有函数的定义,那么编译时就填上地址;如果当前文件只有函数声明,那么定义就在其他xxx.cpp文件中,编译的时候没有地址,只能在链接时去其他源文件的符号表中根据函数修饰名字去查找地址(声明的地址不是实际的地址,定义的地址才是真的地址),这就是链接的主要作用。 windows下函数名的修饰规则更加复杂,但是原理是相同的。可以阅读文章C/C++ 函数调用约定. 到这里我们就理解了C语言没办法支持重载,是因为同名函数没办法区分,在编译时就会报错。而C++是通过函数修饰规则来区分,只要参数不同,修饰出来的名字就不一样,就支持了重载。 引用引用的概念因为C语言中指针的使用比较复杂,所以C++中引入了“引用”的概念。引用不是重新定义一个变量,而是给已存在的变量取了一个别名,编译器不会为引用变量开辟内存空间,它和它引用的变量共用同一块内存空间。 引用的使用方法:类型& 引用变量名(引用实体的别名) = 引用实体; 看下面代码:
注意:引用类型必须和引用实体是同种类型的。 引用在语法层:没有开新空间,就是给原来的变量(空间)取了一个新的名字。 引用的特性1.引用在定义时必须进行初始化
引用在定义时必须进行初始化,因为你必须指明这个引用是哪个变量的别名。 2.一个变量可以有多个引用(一个变量可以有多个别名)
3.引用一旦引用一个实体,就不能再引用其他实体
指针是可以变的,可以指向这个变量,一会又可以指向另一个变量;但是引用不可以,引用从始至终只能是同一个变量的别名。 引用的使用场景1.引用做参数传参的三种方式:
上面3个swap函数构成函数重载,引用和值传递看成不同的参数类型,但是swap(x,y)在调用时存在歧义,不能区分到底是值传递还是引用传递。 引用的底层是指针实现,但是编译器编译时,并不会把引用替换成指针,转换成指令时才会替换成指针。在符号表中使用的是修饰后的函数名,使用的还是形参的类型,只要符号表中的函数名不同就能构成重载,语法层面的参数类型不同即可,并不会关注底层是怎么实现的。 指针的引用
在次之前,C语言部分学过输出型参数,在函数外部定义变量,然后传入该变量的地址,在函数内部改变该变量的值并返回,这样的参数是输出型参数。使用引用作为参数也可以实现该功能。
使用引用作为参数:
2.引用作为返回值看如下代码,使用传值返回
这里返回的并不是变量c,因为函数执行完毕,栈帧就销毁了,局部变量c我们就没有使用权限了(函数栈帧销毁之后,才会返回),即使能取到c的值(可能是正确的值,也可能是不正确的值,取决于栈帧销毁时请不清理空间),也是非法访问的。所以,为了解决这个问题,这里会生成一个临时变量tmp,把c的值拷贝给tmp,返回tmp,所以这里返回的是局部变量c的一份临时拷贝。 临时变量tmp存在哪里? 值传递中形参是实参的一份拷贝,同样的,所有的传值返回都会生成一个拷贝。 使用引用返回
传值返回,会拷贝给临时对象,临时对象返回;引用返回的意思就是不会生成c的拷贝再返回,而是直接返回c的引用(可以理解为返回c的引用int& tmp)。 但是这段代码存在问题: 1.存在非法访问内存,因为Add(10,20)的返回值是c的引用,所以Add栈帧销毁后,c已经销毁,再访问c就是非法访问内存; 2.如果Add函数栈帧销毁,并清理空间,那么取c值的时候取到的就是随机值,返回的也就是随机值,当然这个取决于编译器的实现(VS2019,对于malloc出来的空间,free释放后,一般会清理内存,函数调用结束后,栈帧销毁,不一定清理内存)。对于“非法写”编译器一般能检测出来,“非法读”编译器有时候检测不出来。 但是一般不建议使用引用返回,如果要使用,正确的使用方式如下: 如果函数返回时,出了函数作用域,如果返回对象还未还给系统(比如静态变量、全局变量等),则可以使用引用返回;如果已经还给系统了,则必须使用传值返回。
引用的价值: 1.做参数 – 提高效率;形参的修改可以改变实参(输出型参数)
2.做返回值 – 提高效率;修改返回变量
传值返回,会拷贝给临时对象,临时对象被返回; 不要返回局部变量的引用。 值传递、引用传递效率比较传值返回和传引用返回的区别:传值返回会有拷贝;传引用返回没有拷贝。 以值作为参数或者返回值类型,在传参和返回期间,函数不会直接传递实参或者将变量本身直接返回,而是传递实参或者返回变量的一份临时的拷贝,因此用值作为参数或者返回值类型,效率是非常低下的,尤其是当参数或者返回值类型非常大时,效率就更低。 以下代码测试值传递和引用传递的效率:
运行这段代码,结果如下: 总结:引用的作用主要体现在传参和传返回值 1.在有些场景下,可以提高性能。比如大对象+深拷贝对象 2.输出型参数和输出型返回值,也就是说,在有些场景下,形参的改变可以改变实参;有些场景下,引用返回,可以改变返回对象,后续学习再进行补充。 常引用
注意:使用引用时:权限不能放大,权限可以不变或者缩小。
假设x是一个大对象或者是以后要学习的深拷贝的对象,那么尽量用引用传参,减少拷贝。如果f函数中不改变x,建议尽量用常引用传参。
临时变量具有常属性
隐式类型转换:产生一个临时变量(中间变量),把临时变量赋值给左值;整型提升、算术转换操作的都是临时变量,并不会改变原来的值。 临时变量具有常性,不能被修改(临时变量是右值)。 引用和指针的区别在语法概念上引用就是一个别名,没有独立空间,和其引用实体共用同一块空间。 在底层实现上实际是有空间的,因为引用是按照指针方式来实现的。 引用和指针的不同点:
extern “C”有时候在C++工程中可能需要将某些函数按照C的风格来编译,在函数前加extern “C”,意思是告诉编译器,将该函数按照C语言规则来编译。比如:tcmalloc是google用C++实现的一个项目,他提供tcmallc()和tcfree两个接口来使用,但如果是C项目就没办法使用这两个接口,那么他就使用extern “C”来解决。 extern "C"只有C++能够认识,C语言不认识,所以extern "C"只能出现在C++代码中。 C++程序 调用C库,在C++程序中加"extern C" 内联函数内联的概念为了解决C语言宏使用比较麻烦的问题,C++引入了内联函数。 以inline修饰的函数叫做内联函数,编译时C++编译器会在调用内联函数的地方展开,没有函数压栈的开销,内联函数提升程序运行的效率。 如果在上述函数前增加inline关键字将其改成内联函数,在编译期间,编译器会用函数体替换函数的调用。 查看方式:
【总结】:长函数和递归函数不适合展开,展开后程序可能会变的很大。 特性
3.inline不建议声明和定义分离,分离会导致链接错误。因为inline被展开,就没有函数地址了,链接就会找不到。 宏的优缺点优点: 缺点: C++有哪些技术替代宏?
|
|
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/24 12:00:23- |
|
网站联系: qq:121756557 email:121756557@qq.com IT数码 |