资讯专栏INFORMATION COLUMN

【C++从0到1】新手都能看懂的C++入门(上篇),建议收藏

xcold / 2079人阅读

摘要:上面这三种均不造成重载,现在来说明原因。结论对于引用返回,返回的对象必须是栈帧销毁后还存在的。全局,静态,未销毁的函数栈帧当中的都是可以的指针与引用如图两者底层实现差不多,引用是用指针模拟的。不建议声明和定义分离,分离会导致链接错误。


前言

C++入门是很多人头疼的问题,今日就与博主一同学习一些比较简单的基本概念,这些在之后很多地方的作用是十分大的。
看完之后,相信你会受益匪浅!!


一、命名空间

命名空间是什么,为什么要存在命名空间,首先我们如果以前有看过c++的代码一定少不了这两句。

#includeusing namespace std;

这个大家想必都看过,using在这里实际上就是展开命名空间的内容。

命名空间就是一个域,与外界隔离,使用域当中的东西要通过(域名+::)

当我们要使用当前引入库函数当中的函数名作为变量时,例如:如果我们引入头文件#include,我们会发现我们使用rand作为变量名会出错

这是因为我们rand在stdlib中是作为一个函数存在的,我们如果引了头文件,相当于在预处理的时候就会将头文件展开,我们就会看到rand作为函数的声明及实现。

这个时候我们就无法使用这个rand,命名空间却能帮我们解决

从上图可以看出,命名空间不受到其他域当中影响,因为在全局域展开并不会影响到命名空间。但是如果我们不展开命名空间的话,调用命名空间内部的函数时我们都要采用域限定符,所以我们在进行一些日常练习时才会去进行命名空间的展开。

需要注意的就是,如果有同名的命名函数,他们就会被合在一起。
对于命名空间,内部也可以在嵌套定义命名空间,使用的时候也要注意加上域作用限定符。

总结:我们使用命名空间的时候可以进行部分展开,对于常用的函数展开,这是一种折中的解决方案。


二、缺省函数

常见使用

在模拟顺序表的初始化的时候,我们可以用缺省参数控制我们要申请多大的空间,如果没有传参数,我们可以默认帮它设置。其中我们上面演示的为半缺省参数。

  1. 半缺省参数必须从右往左依次来给出,不能间隔着给
  2. 缺省参数不能在函数声明和定义中同时出现

解释第一条:因为如果从左开始给的话,如果我们左边想要默认的缺省值,就不合理了。
解释第二条:倘若声明和定义当中给的缺省值不一样,编辑器无法判断,所以制止这种写法,倘若要使用,则参照下图。


三、 函数重载

3.1常见使用


刚刚谈完的命名空间中一个域中不能出现重复的定义,但是c++在这里,允许了函数重载,只要函数的顺序(不同类型之间),类型不同,都可以造成函数重载。

上面这三种均不造成重载,现在来说明原因。原因与c++当中为何支持函数重载有关,相信看了下面你就能明白。


3.2重载底层实现

提前说明,以下为linux的解释说明,并且文件后缀不代表他是否为cpp文件,而是根据我们所调用的编辑器决定的。
先说结论:是因为他们的函数名修饰规则不同导致的。

我们先来看看linux下对于c的函数名和cpp当中的函数名在编译阶段是怎样的,这里我们用的是objudump -S,查看我们的.o文件

我们能在这里观察到对于linux平台下,链接时我们的函数是没有经过任何修饰的,通过这样的函数名在链接的时候重定位将函数的地址再填进去。在c中,这样子当我们重载的时候,两个同名的add即便构成重载,却因为两个相同的add构成了不确定导致无法进行链接
而c++当中对于函数进行了修饰,并且它的修饰规则比较简单_Z是固定的前缀,3表示函数名的长度,我们Add的长度正好是3,而剩下的ii/dd则就是参数名称。


3.3返回值不纳入重载原因

那么有人可能会想,为什么设计的时候不把返回值也作为函数重载的依据呢,设想一下,假如我们在函数名前面假如返回值的首字母作为修饰函数名,下面这种情况是不是也是存在异议的,也就是我们底层设计的时候虽然是可以支持到函数返回值也来修饰函数名,从语法层面,编辑器不能通过此特征来判断调用哪个函数。


四、extren C

我们在日常中如果采用c语言去写一个项目,如果我们要利用c++库的话,根据上面函数重载,我们c语言在链接时通过自己的函数名是没办法找到对应的c++的函数名的,而c++在c语言后面诞生,所以采用c++写的项目,调用c的库的时候是可以直接找到的。所以我们编写c++的库的时候,为了照顾到我们用纯c写项目的,就会在该函数的声明处加上extern “C”,这样c++和c都能同时调到这个函数。

比如谷歌提供tcmalloc库中就有若干函数如此。


五、引用

5.1常见使用


可以看出a为b的一个引用,别名,语法上是不占空间的,我们通过取地址也可以看出a和b指向的都是同一块内存。


引用的特点:引用必须初始化。引用只能对一块空间,不像指针可以转换指向内容。 一个变量可以有多个引用。


观察下面代码:

int main(){//这里是b赋值给a,还是a是b的引用呢?	int b = 10;	int& a = b;	int c = 20;	a = c;	return 0;}

答案揭晓:这里是b赋值给a。

因为我们接下来要讲到引用返回会遇到的种种情况,所以我们在这里先讲述临时变量是一个怎样的存在。


5.2临时变量的作用

思考这里的ret是怎么返回回去的,在函数栈帧中提到了调用完函数之后,空间会被释放,我们return ret 的时候他是将ret返回吗?不是的,因为ret在Add的栈帧中,如果他返回就会造成空间的越界访问。那么他是如何返回的呢。

答案:当返回的数据大小在4,8字节的情况下通常是由我们的寄存器eax带回来,如果超过这个范围的话,就会在main函数的栈帧中提前开设一块跟返回值的一份临时拷贝。临时数据具有常性。

带回我们的结构体做了若干操作,我们这里不详细讲解。对上面的答案进行简单的论证。

强制类型转换和隐式类型转换都是会创建一个临时变量进行接受的,像下面这张图,我们的r虽然是i的引用,但是他们却不是指向同一块空间的,而这里的r是指向谁了呢?就是我们的一个临时变量,临时变量具有常性,我们不能对他进行修改,所以我们要添加const表示只对该变量有读取的权限!

常引用如下:

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

引用和指针在sizeof中含义不同:引用结果为引用类型的大小(与类型有关),但指针始终是地址空间所占字节个数(32位平台下占4个字节),即与平台有关。


5.3引用返回常见错误

引用有作为参数,和返回值的两大作用,那么使用的时候返回值这块容易犯错误。

int& Add(int x, int y){	int ret = x + y;	return ret;}int main(){	int sum = Add(1, 2);	Add(3, 4);	cout << "Add(1,2): is " << sum << endl;	return 0;}

虽然上面的代码运行的结果是正确的,但是存在着很大的安全隐患,Add这个栈帧销毁过后再去访问,倘若系统对于回收的空间会进行处理的话,这块空间上的值就是随机值,vs2019在这块对于回收的内存是没有做处理的。

知道了上面的结论,再来看下面这段代码:只改了这一处返回值,这时候会发生什么呢?



甚至当你在Add那块空间被cout给覆盖之后,ret的内存空间甚至有可能是一些奇奇怪怪的值。

结论:对于引用返回,返回的对象必须是栈帧销毁后还存在的。全局,静态,未销毁的函数栈帧当中的都是可以的!!

5.4指针与引用

如图:两者底层实现差不多,引用是用指针模拟的。


六、内联函数

inline是一种以空间换时间的做法,省去调用函数额开销。所以代码很长或者有循环/递归的函数不适宜 使用作为内联函数。
inline对于编译器而言只是一个建议,编译器会自动优化,如果定义为inline的函数体内有循环/递归等 等,编译器优化时会忽略掉内联。
inline不建议声明和定义分离,分离会导致链接错误。因为inline被展开,就没有函数地址了,链接就会找不到。

内联函数替代宏的原因

#define SWAP(T,m,n) {T s; s=m, m=n, n=s;}//#define Add(a,b) a+b//#define Add(a,b) (a+b)//#define Add(a,b) ((a)+(b))int main(){	int a = 0;	int b = 1;	//宏的本质是替换,得看替换之后合不合理!!	//{T s; s=m, m=n, n=s;}	SWAP(int,a,b);	cout << a <<" "<< b << endl;	return 0;}

因为宏虽然功能强大,但是在使用的时候缺少类型检查,调试不方便,使用的比较别扭等因素,所以我们c++引入内联函数,在调用的地方展开。但是对编辑器只是一种建议。
c++当中建议用const,enum替换宏常量,内联函数替换宏函数。


七、nullptr


c++标准将NULL定义为0,通常情况下按照c语言,int* p=NULL,还是没有错的,但是在下面这种情况会有异议。所以我们推荐c++当中使用nullptr作为空指针。


总结

c++的入门就到这里啦,下一章会描述类和对象。
三连支持一下吧!!!

文章版权归作者所有,未经允许请勿转载,若此文章存在违规行为,您可以联系管理员删除。

转载请注明本文地址:https://www.ucloud.cn/yun/121543.html

相关文章

  • 终于有一篇小白能懂的智能指针详解了!

    摘要:在我以为我和缘分尚浅的时候,搬来救兵,智能指针横空出世,打败了内存泄漏,拯救了我们的关系。智能指针引入了智能指针的概念,使用了引用计数的想法,让程序员不再需要关心手动释放内存。它还增加了一个成员函数用于交换两个智能指针的值。 ...

    includecmath 评论0 收藏0
  • 我们一直谈论“写代码”,但你会“读代码”吗?

    摘要:只有能看懂代码,你才能快速准确地定位代码中的问题。要写出很的代码,少不了阅读优秀的源码。我们的论坛和答疑群里,有一些同学会查看并解答其他人的代码问题。实际上,我觉得就是没看懂你只是看懂了每一行代码的意思,但并没有理解整个代码的设计。 编程,又被称作 写代码 。这个说法有可能会带来一点点误解,让人觉得如何写是学习编程要解决的主要问题。但事实并非如此。尽管最终代码要在键盘上敲出来,但这个过...

    2i18ns 评论0 收藏0
  • 程序员如何自我学习?阿里资深技术专家这样做

    摘要:而程序员和医生律师的不同点在于持续学习上。两个小问题是需要收费,一年大概刀图书都是英文的。的视频基本都有英文字幕,配合作者的,英语不好的同学学习也没有问题。英文好的有技术功底的同学多发表一些观点,其他的同学都 摘要: 行业发展得太快,你必须学习,纯靠经验积累行不通,技术淘汰的速度远大于你经验积累的速度。 非鸡汤:不要和程序员谈自己的编程历史,很多的经验在今天已经不适用了。只要2-3年...

    Jacendfeng 评论0 收藏0
  • 《大型网站系统与Java中间件》读书笔记 (中)

    摘要:文本已收录至我的仓库,欢迎回顾上一篇大型网站系统与中间件读书笔记一这周周末读了第四章,现在过来做做笔记,希望能帮助到大家。没错,我们通过肯定是可以完成两个系统之间的通信的问题的。 前言 只有光头才能变强。文本已收录至我的GitHub仓库,欢迎Star:https://github.com/ZhongFuCheng3y/3y 回顾上一篇: 《大型网站系统与Java中间件》读书笔记(一)...

    fredshare 评论0 收藏0
  • 保姆级教程HTML两万字笔记大总结【建议收藏】(上篇

    摘要:标签不区分大小写,但推荐小写。标签可以嵌套,但不能交叉嵌套。标签也称为元素。比如行内标签亦可成行内元素。 ❤️HTML必备知识详解❤️ 第一部分:HTML框架简介...

    paulli3 评论0 收藏0

发表评论

0条评论

最新活动
阅读需要支付1元查看
<