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;

🍯特性

有以下几个特性:

  1. 引用在定义时必须初始化
  2. 一个变量可以有多个引用
  3. 引用一旦引用一个实体,再也不能引用其他实体
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;

🍯两种常见使用场景

  1. 做参数
void Swap(int& x, int& y)

	int tmp = x;
	x = y;
	y = tmp;

  1. 做返回值
int& Add(int x, int y)

	int z = x + y;
	return z;

引用做返回值时,一般分两种情况:返回的对象未归还系统和返回的对象归还系统。如果返回对象不归还系统,我们可以引用返回,否则就需要传值返回。

🍯传值和传引用效率比较

🍤以值作为参数或者返回值类型,在传参和返回期间,函数不会直接传递实参或者将变量本身直接返回,而是传递实参或者返回变量的一份临时的拷贝,因此用值作为参数或者返回值类型,效率是非常低下的,尤其是当参数或者返回值类型非常大时,效率就更低。

🍯引用和指针的区别

以下是二者的不同点:

  1. 引用在定义时必须初始化,指针没有要求
  2. 引用在初始化时引用一个实体后,就不能再引用其他实体,而指针可以在任何时候指向任何一个同类型实体
  3. 没有NULL引用,但有NULL指针
  4. 在sizeof中含义不同:引用结果为引用类型的大小,但指针始终是地址空间所占字节个数(32位平台下占4个字节)
  5. 引用自加即引用的实体增加1,指针自加即指针向后偏移一个类型的大小
  6. 有多级指针,但是没有多级引用
  7. 访问实体方式不同,指针需要显式解引用,引用编译器自己处理
  8. 引用比指针使用起来相对更安全

🌏内敛函数

🍅 以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关键字,编译器在编译期间会用函数体替换函数的调用。

下面是内敛函数的几个特性:

  1. inline是一种以空间换时间的做法,省去调用函数额开销。所以代码很长或者有循环/递归的函数不适宜使用作为内联函数。
  2. inline对于编译器而言只是一个建议,编译器会自动优化,如果定义为inline的函数体内有循环/递归等等,编译器优化时会忽略掉内联。
  3. 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;

有一下几种用法:

  1. 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;

运行结果如下:

  1. 在同一行定义多个变量(这些变量类型必须相同,编译器只对第一个类型进行推导)
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不能推导的两个常见

  1. auto不能作为函数的参数
  2. 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;

运行结果如下:

🌰条件

  1. for循环迭代的范围必须是确定的
    对于数组而言,就是数组中第一个元素和最后一个元素的范围;对于类而言,应该提供begin和end的
    方法,begin和end就是for循环迭代的范围。
  2. 迭代的对象要实现++和==的操作。

🌐总结

C++入门全篇就介绍到这,后面几天我会更新类和对象的博客,欢迎大家持续关注,喜欢的话三连支持一下~

以上是关于C++初阶第三篇——初始C++(引用+内敛函数+auto关键字+范围for循环)的主要内容,如果未能解决你的问题,请参考以下文章

C++初阶第十三篇—模板进阶(非类型模板参数+模板特化+模板的分离编译)

C++初阶第二篇——初始C++(详细讲解extern “C”)

C++初阶第六篇——类和对象(下)(初始化列表+explicit关键字+static成员+友元+内部类)

C++初阶第四篇——类和对象(上)(类的定义+封装+this指针)

C++初阶第八篇——模板初阶(泛型编程+函数模板+类模板)

数据结构初阶第三篇——单链表(实现+动图演示)[建议收藏]