前言
C++快速入门已经更新完毕,前两篇见:C++系列2-1:C++快速入门之命名空间和输入输出和
七:引用
情景导入:在第一次学习C语言指针时,许多教材上都会给出一个交换变量值的函数的例子,开始我们认为这样交换就可以成功
voidswap(inta,intb){inttemp=a;
a=b;
b=temp;
}intmain(){inta=1;intb=2;
swap(a,b);
}
但学习完指针后,就明白了这样的操作是不行的,因为每当进行一个函数就会为该函数的形参开辟一个新的空间,函数结束之后,形参的空间也就被销毁了,所以不可能交换成功。于是正确的写法应该是这样
voidswap(int* x,int* y){inttemp=*x;
*x=*y;
*y=temp;
}intmain(){inta=1;intb=2;
swap(&a,&b);
}
而在C++中我们引入一个新的概念——引用
(1)引用的概念
简单点来说:引用就是起别名,这一片内存空间名字叫a,然后再给它额外起一个名字,叫做b,a和b操控的是同片内存空间。
从下面的这个动态调试的过程中,大家可以深刻的体会到引用这种取别名的意思
(2)地用的地点
- 引用在定义时必须初始化,不初始化有点像野指针的感觉
- 一个变量可以有多个引用,也就是有多个外号
- 一个引用一旦引用了一个实体,就不能再引用其他实体了。
(3)常引用
C语言中我们就知道,如果定义一个长整形,表示这个整形变量是不可以修改的,如果用普通引用则不行
intmain(){constinta=10;int& b=a;//错误,权限被放大,之前只可读,赋值后却可读可写了}
那么面对这样的变之后如之后然使用之前的引用方式是不可行的,这涉及到一个权限问题,变量a自身只能可读,但是它被int& b引用后,反倒可以修改了,这就矛盾了。所以要解决这种权限问题,必须使用常引用
intmain(){constinta=10;constint& b=a;//常引用}
- 指针和引用在赋值时,权限不能放大,但是可以缩小(这也就是int strlen(const char* str))中形参是const类型的
intmain(){inta=10;constint& b=a;//这样的做法是可以的,权限被缩小的}
- 常数具有常性,所以引用常数时,必须使用常引用
intmain(){int& c=1;//错误constint& c=1;//正确}
- C语言中,浮点型转换为整型时,有一个中间过程,会涉及到一个中间变量,这个中间变量具有常性,必须使用常引用
intmain(){doublea=3.14;intb=a;//隐式转换//如果用int型引用double型,引用不是那个double,而是double转换为int时//的那个中间变量,因为它具有常性int& ps=a;//错误constint& ps=a;//正确}
关于常引用,确实C++在这方面有点麻烦,但是这个常引用也是有好处的,尤其体现在引用做形参。我们一般使用常引用作为形参,根据以上叙述,所以其实参可以是变量也可以是常量,同时如果实参和形参存在类型转换,这也是无妨的,也可以传递
voidtest(constDataType& x){//形参使用常引用好处多多
(4)引用的应用场景
A:做参数
回到之前的情境导入,根据以上的叙述在C++中交换两个变量的值就可以使用引用了。
voidSwap(int& x,int&y){inttemp=x;
x=y;
y=temp;
}intmain(){inta=1;intb=2;
Swap(a,b);
}
B:做返回值
实参传给形参时,如果不用指针或引用,那么形参就要拷贝一份,这一点相信大家是很明白的。但是,函数的返回值也属于传值,也就是它不是直接返回给调用函数的变量,而是先给寄存器或内存(如果数据大的话要开辟更多空间)
当然,引用也可以用于返回值。让函数返回引用,在让调用它的地方引用,相当于一次拷贝。
其实上面的代码是有一定的问题,虽然可以正确执行,通过调试可以发现,receive和ret地址是一样的,他们都是那一片内存空间的别名。
如果在后面再调用一次sum函数,最终输出结果成了7了
使用调试,会感受到这个过程
而如果再加入一句毫不相干的代码,会发现最后输出的竟然是一个随机值,这是因为到这里的时候ret早就还给系统了。
所以:如果函数返回时,已经出了作用域,此时如果返回对象还未归还给系统,那么可以使用引用返回,但是如果已经还给系统了,则必须使用传值返回。
(5)引用和指针
语法角度上讲,引用是实体的别名,与实体共用统一内存空间,而从底层实现角度上讲,引用其实是按照指针的方式进行的
从汇编角度可以看出这一点
引用和指针的区别如下
引用 | 指针 |
引用定义必须初始化 | 指针没有要求 |
引用只能一个实体 | 指针在任何时候指向任何同类型的实体 |
没有NULL引用 | 但有NULL指针 |
使用sizeof()表示引用类型的大小 | 使用sizeof表示地址空间所占字节数 |
++引用表示引用的实体增加1 | ++指针表示指针向后偏移一个类型的大小(字节) |
没有多级引用 | 但有多级指针 |
引用较安全 | 指针较不安全 |
八:内联函数
情境导入:在之前的排序或者是其他的联系中,我们经常使用到一个自己构造的函数,那就是交换函数。函数如果被调用,就会产生压栈的开销,为了解决这样的问题。在C语言中,我们可以使用宏函数
define max(a,b) a>b?a:bintmain()
{intret=max(1,2);return0;
}123456
而在C++中可以使用内联函数解决
(1)内联函数的概念
使用inline修饰的函数叫做内联函数,编译时编译器会在调用内联函数的地方展开,它没有函数压栈的开销,因此提高了程序运行的效率
下面的函数没有用inline修饰,其汇编代码中存在call指令
如果使用inline将其修饰为内敛函数,在编译期间编译器会用函数体替换函数的调用。由于在debug模式,编译器不会对代码进行优化,所以可以在release模式下查看汇编代码中是否存在call指令
(2)内联函数的特性
- inline实则是一种以空间换时间的做法,所以对于递归,循环则不适合作为内联函数
- inline不要把声明和定义分离,分离会导致链接错误,一旦inline被展开,就没有函数地址了。
九:auto关键字(C++11)
(1)auto简介
auto其实一直存在,早期C/C++人们赋予auto的含义是:使用auto修饰的变量,是具有自动存储器的局部变量
C++11赋予了auto新的含义:auto不再是一个指示器,而是一个新的类型指示符来指示编译器,auto声明的变量必须由编译器在编译时期推导获得。
- 注意:使用auto定义变量时必须对其进行初始化,在编译阶段编译器需要根据初始化表达式来推导auto的实际类型,所以auto并非是一种类型的声明,而是一种类型的占位符,编译器会在编译时会将auto替换为其实际的变量类型
(2)auto使用注意事项
1.auto声明指针类型时,既可以使用auto也可以使用auto*,但是在声明引用时必须加上&
2.在同一行声明多个变量时,这些变量必须是同一类型
intmain(){autoa=1,b=2;//正确autoc=3,d=4.0;//错误}
3.auto不能作为函数参数
voidtest(autoa){//编译错误,调用函数需要开栈帧,但此时编译器无法对a的类型进行推导}
4.auto不能用于声明数组
十:基于范围得到for循环(C++11)
情境导入:在C/C++中遍历一个数组,我们的做法是下面这样的
intmain(){intarray[]={1,2,3,4,5};for(inti=0;i<sizeof(array)/sizeof(array[0];++i))
{std::count<<array[i];
}
}
对于这种有范围的集合,去遍历它时,其中for循环中的范围其实是多余的,所以C++11中引入了基于范围的for循环来实现它,这种风格的for循环有点像python中的for循环
(1)基于范围的for循环
所以我们可以将上面的代码改变成下面这样
你可能会问,之前的for循环我可以遍历是我可以对数组内的元素进行操作或修改,这里怎么办呢?其实结合咋们上面讲过的引用,就可以实现这一点
十一:指针空值nullptr(C++11)
(1)NULL的缺陷
无论是谁,学习C语言时,总听过如果一个指针暂时没有合法的指向,可以将其定义为空指针
intmain(){int* p=NULL;
}
从字面上讲,NULL很好理解,不就是空嘛。如果将其转到定义的地方,可以发现NULL可能被定义为了字面常量0或void*
这样的做法是有缺陷的,甚至有的时候会干扰到我们。
如下两个同名函数,一个的形参是int类型的,另一个的形参则是int*类型的,调用这个函数,参数分别传入0,NULL,(int*)NULL,结果显示,前两个全部调用了第一个函数
- NULL的那一个本来想调用第二个,但是它被解释为了0,所以调用了第一个
(2)nullptr
为了解决上述缺陷,C++11引入了nullptr,需要注意的是nullptr是C++的关键字可以发现,它调用的正是我们想要调用的函数
结语
C++入门系列已经更新完毕,如果想要看对应视频请点击
声明:本文部分素材转载自互联网,如有侵权立即删除 。
2. 分享目的仅供大家学习和交流,您必须在下载后24小时内删除!
3. 不得使用于非法商业用途,不得违反国家法律。否则后果自负!
4. 本站提供的源码、模板、插件等等其他资源,都不包含技术服务请大家谅解!
5. 如有链接无法下载、失效或广告,请联系管理员处理!
6. 本站资源售价只是赞助,收取费用仅维持本站的日常运营所需!
7. 如遇到加密压缩包,请使用WINRAR解压,如遇到无法解压的请联系管理员!
8. 精力有限,不少源码未能详细测试(解密),不能分辨部分源码是病毒还是误报,所以没有进行任何修改,大家使用前请进行甄别
丞旭猿论坛
暂无评论内容