C++初阶第三篇——初始C++(引用+内敛函数+auto关键字+范围for循环)
Posted 呆呆兽学编程
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了C++初阶第三篇——初始C++(引用+内敛函数+auto关键字+范围for循环)相关的知识,希望对你有一定的参考价值。
⭐️今天·这篇博客我要来和大家一起聊一聊初始C++中一些新的知识,引用和内敛等,希望对大家有所帮助。
⭐️博客代码已上传至gitee:https://gitee.com/byte-binxin/cpp-class-code/tree/master/test_1_15
🌏引用
🍯概念
🍤引用不是新定义一个变量,而是给已存在变量取了一个别名,编译器不会为引用变量开辟内存空间,它和它引用的变量共用同一块内存空间。也就好比我们给同学取了一个外号一样。
用法: 类型&引用变量名(对象名)= 引用实体;
例子:
int main()
int a = 10;
int& ra = a;// ra是a的引用
cout << a << endl;
cout << ra << endl;
return 0;
🍯特性
有以下几个特性:
- 引用在定义时必须初始化
- 一个变量可以有多个引用
- 引用一旦引用一个实体,再也不能引用其他实体
int main()
int a = 10;
int b = 20;
//int& ra;//引用必须初始化
int& ra = a;
int& rra = a;
//int& ra = b;//引用不能改变
return 0;
🍯常引用
🍤引用在引用实体时,该引用的使用权限必须小于或等于 实体,否则不能够被引用。
看下面例子:
int main()
const int a = 10;
// 权限不变 都是常量
const int& ra = a;
// 权限变小 常量引用变量
int b = 20;
const int& rb = b;
// 权限放大 变量引用常量,权限放大,编译器报错
int& rra = a;
double d = 10.0;
int& rd = d;//d是double类型的,rd是int类型的引用,此时赋值会发生隐式类型转换,
//d会先存放在临时变量中,临时变量是常量,所以权限放大了,编译器报错
// 权限不变
const int& rd = d;
return 0;
🍯两种常见使用场景
- 做参数
void Swap(int& x, int& y)
int tmp = x;
x = y;
y = tmp;
- 做返回值
int& Add(int x, int y)
int z = x + y;
return z;
引用做返回值时,一般分两种情况:返回的对象未归还系统和返回的对象归还系统。如果返回对象不归还系统,我们可以引用返回,否则就需要传值返回。
🍯传值和传引用效率比较
🍤以值作为参数或者返回值类型,在传参和返回期间,函数不会直接传递实参或者将变量本身直接返回,而是传递实参或者返回变量的一份临时的拷贝,因此用值作为参数或者返回值类型,效率是非常低下的,尤其是当参数或者返回值类型非常大时,效率就更低。
🍯引用和指针的区别
以下是二者的不同点:
- 引用在定义时必须初始化,指针没有要求
- 引用在初始化时引用一个实体后,就不能再引用其他实体,而指针可以在任何时候指向任何一个同类型实体
- 没有NULL引用,但有NULL指针
- 在sizeof中含义不同:引用结果为引用类型的大小,但指针始终是地址空间所占字节个数(32位平台下占4个字节)
- 引用自加即引用的实体增加1,指针自加即指针向后偏移一个类型的大小
- 有多级指针,但是没有多级引用
- 访问实体方式不同,指针需要显式解引用,引用编译器自己处理
- 引用比指针使用起来相对更安全
🌏内敛函数
🍅 以inline修饰的函数叫做内联函数,编译时C++编译器会在调用内联函数的地方展开,没有函数压栈的开销,内联函数提升程序运行的效率。
先看下面一串代码:
inline int Add(int x, int y)
return x + y;
int main()
int z = Add(1, 2);
return 0;
在release下查看汇编代码,先看不加inline的汇编代码:
再看加了inline的汇编代码:
如果加了inline关键字,编译器在编译期间会用函数体替换函数的调用。
下面是内敛函数的几个特性:
- inline是一种以空间换时间的做法,省去调用函数额开销。所以代码很长或者有循环/递归的函数不适宜使用作为内联函数。
- inline对于编译器而言只是一个建议,编译器会自动优化,如果定义为inline的函数体内有循环/递归等等,编译器优化时会忽略掉内联。
- inline不建议声明和定义分离,分离会导致链接错误。因为inline被展开,就没有函数地址了,链接就会找不到。
例子:一个相同的函数,一个加了inline 关键字,一个没加,加上一个函数要执行10条指令,文两个函数分别调用1000次要执行多少条指令?
普通函数:1000+10(一次调用1次指令,加起来就是1000条,每次调用都是call函数,函数不展开就是10条)
内敛函数:1000*10条指令(展开就是每次调用都是10条指令)
所以说,内敛函数展开,会让程序变大,所以代码很短的函数可以考虑有内敛,长函数和递归函数不适合用内敛。
🌏auto关键字(C++11)
🍁C++11中,标准委员会赋予了auto全新的含义即:auto不再是一个存储类型指示符,而是作为一个新的类型指示符来指示编译器,auto声明的变量必须由编译器在编译时期推导而得。
int main()
int a = 10;
auto b = a;// 自动推导b的类型为int
auto c = 'c';// 自动推导类型为char
cout << typeid(b).name() << endl;
cout << typeid(c).name() << endl;
//auto d;必须初始化
return 0;
有一下几种用法:
- auto与指针和引用结合起来使用(auto和auto*无区别)
int main()
int a = 10;
// auto和auto*无区别
auto pa1 = &a;
auto* pa2 = &a;
auto& ra = a;// ==> int& ra = a;
cout << typeid(a).name() << endl;
cout << typeid(pa1).name() << endl;
cout << typeid(pa2).name() << endl;
cout << typeid(ra).name() << endl;
return 0;
运行结果如下:
- 在同一行定义多个变量(这些变量类型必须相同,编译器只对第一个类型进行推导)
int main()
auto a = 3, b = 4;
auto c = 3.4, d = 5.5;
cout << typeid(a).name() << endl;
cout << typeid(b).name() << endl;
cout << typeid(c).name() << endl;
cout << typeid(d).name() << endl;
return 0;
运行结果如下:
auto不能推导的两个常见
- auto不能作为函数的参数
- auto不能直接用了声明数组
🌏基于范围的for循环(C++11)
🌰语法
for(类型 e: 被迭代的范围)
类型可以用auto关键字来进行推导,被迭代范围一般可以说数组和容器等。
迭代范围的内容按照接受类型一个一个地给e赋值
举例:
int main()
int arr[10];
int i = 0;
for (auto& e : arr)
e = i++;
for (auto e : arr)
cout << e << " ";
return 0;
运行结果如下:
🌰条件
- for循环迭代的范围必须是确定的
对于数组而言,就是数组中第一个元素和最后一个元素的范围;对于类而言,应该提供begin和end的
方法,begin和end就是for循环迭代的范围。 - 迭代的对象要实现++和==的操作。
🌐总结
C++入门全篇就介绍到这,后面几天我会更新类和对象的博客,欢迎大家持续关注,喜欢的话三连支持一下~
以上是关于C++初阶第三篇——初始C++(引用+内敛函数+auto关键字+范围for循环)的主要内容,如果未能解决你的问题,请参考以下文章
C++初阶第十三篇—模板进阶(非类型模板参数+模板特化+模板的分离编译)
C++初阶第二篇——初始C++(详细讲解extern “C”)
C++初阶第六篇——类和对象(下)(初始化列表+explicit关键字+static成员+友元+内部类)