【C++基础(四)】内联函数和auto关键字

博主CSDN主页:杭电码农-NEO

⏩专栏分类:C++初阶之路⏪

代码仓库:NEO的学习日记

关注我带你学习C++



内联函数

  • 1. 前言
  • 2. 内联函数概念
  • 3. 内联函数的特性
  • 4. auto关键字
  • 5. auto的使用规则
    • 5.1 对指针和引用的区别
    • 5.2 一行多次定义的场景
    • 5.3 auto无法使用的场景
  • 6. 基于范围的for循环
  • 7. 总结以及拓展

1. 前言

本章重点:

本节着重讲解内联函数的概念
和使用方法,并且介绍auto关键字,
拓展一个C++的范围for(只做了解)

【C++基础(四)】内联函数和auto关键字_第1张图片


2. 内联函数概念

基本概念:

  • 被inline修饰的函数被称为内联函数
  • 编译器会在编译时将内联函数展开
  • 展开后,没有函数调用建立栈帧的开销
  • 内联函数可以提升程序运行效率

举例说明:

inline int Add(int left, int right)
{
	return left+right;
}

这就是一个内联函数
它的汇编代码可以简单看一下:

【C++基础(四)】内联函数和auto关键字_第2张图片

在函数栈帧的创建与销毁中可知
调用一个函数,开辟栈帧时需要call指令
而这里并没有call指令出现
可见内联函数和普通函数确实有不同

对比说明:普通函数

int Add(int left, int right)
{
	return left+right;
}

它的汇编代码如下:

【C++基础(四)】内联函数和auto关键字_第3张图片

很明显这里使用了call指令


3. 内联函数的特性

特性:

  1. inline是一种以空间换时间的做法
    如果编译器将函数当成内联函数处理
    在编译阶段,会用函数体替换函数调用

缺陷:可能会使目标文件变大
优势:减少调用开销,提高运行效率


  1. inline对于编译器而言只是一个建议
    若一个函数代码很长
    则编译器不会将它变成内联

在《C++prime》中曾这样写到:

【C++基础(四)】内联函数和auto关键字_第4张图片


  1. 一般来说,函数代码在10行及以内时
    这时编译器会将它优化为内联函数
    有些编译器是在30行以内

综上所述:
定义函数为内联时
应当检查函数代码行数是否足够少


  1. 内联函数的定义和声明不能分开
    因为inline被展开后
    就没有函数地址了,链接时会找不到

内联函数的一些性质可以
在某些函数使用宏替换的地方
将函数定义为内联,也是同样的效果


4. auto关键字

在学习C++到后期的时候
经常会遇见类似于下面这种代码:

__list_iterator<InputTterator>::iterator it = tmp.begin();

这段代码看起来非常难理解
但事实上它和定义一个整型是一个意思
就是在定义一个变量

【C++基础(四)】内联函数和auto关键字_第5张图片

你可能会问:这和auto有啥关系?

auto是一个类型,类似于int,char
但是这个类型是由编译器自己推导出来的
什么意思?,举个例子:

int a = 10;
auto b = a;
auto c = 'a';

由于a是int类型的,将a的值赋值给b
编译器就推导出b的类型也是int
同理可得,c的类型就是char

了解了auto的用法后,来化简代码:

__list_iterator<InputTterator>::iterator it = tmp.begin();
//化简后
auto it = tmp.begin();

这两句代码意思相同
这极大的方便了我们的使用!


5. auto的使用规则

5.1 对指针和引用的区别

  1. 对指针来说*可有可无

请看以下代码:

int x = 10;
auto a = &x;
auto* b = &x;

a的类型是int*,此时的auto是int*
b的类型是int*,此时的auto是int

所以对于对象是指针来说
在使用auto时加不加*都无所谓

  1. 对引用来说必须加上&

请看以下代码:

int x = 10;
auto& c = x;
auto d = x;

c的类型是int的引用,此时的auto是int
d的类型是int,此时的auto是int

假设你想定义一个引用变量
请务必加上引用&符号


5.2 一行多次定义的场景

当在同一行声明多个变量时这些变量
必须是相同的类型,否则编译器将会报错
因为编译器实际只对第一个类型进行推导
然后用推导出来的类型定义其他变量

比如:

auto a = 1, b = 2; //没问题
auto c = 3, d = 4.0;  // 该行代码会编译失败,因为c和d的初始化表达式类型不同

事实上,当第一个变量被推导成int后
第二个变量默认也是int.
但是int类型不能存放double类型的值


5.3 auto无法使用的场景

  1. auto无法作为函数参数
void TestAuto(auto a)
{
	//...
}

此处编译器无法对a的实际类型进行推导

  1. auto无法用于声明数组
int a[] = {1,2,3};
auto b[] = {456};

感觉上,数组中都是整型
那么auto应该会自动识别为整型
但是实际上这样做是不行的,详情请看:
英文文献


6. 基于范围的for循环

C++11中支持这样遍历数组:

int arr[] = {1,2,3,4,5,6};
for(auto e : arr)
{
	cout<<e <<" ";
}

其中的for循环的框架就叫做范围for
它可以这样理解:

【C++基础(四)】内联函数和auto关键字_第6张图片

并且范围for是可读可写的!

int array[] = { 1, 2, 3, 4, 5 };
for(auto& e : array)
{
   e *= 2;
}

只需要将e的类型变为引用
就可以修改数组中元素

注:中间的:是范围for的规定写法,没有特殊意义

注意:与普通循环类似
可以用continue来结束本次循环
也可以用break来跳出整个循环


7. 总结以及拓展

本节的所有内容旨在为后面的C++
学习打基础,C++学习一环紧扣一环
环环都不能掉队!

拓展:

是不是感觉C++的范围for非常神奇?
但是实际上它是一个非常笨比的实现
它依赖一个叫迭代器的东西

底层实现上
必须有一个自定义函数叫begin()才能
满足范围for,就算你实现的功能和begin
函数一样,但是名字不一样
也不支持范围for,比如Begin

【C++基础(四)】内联函数和auto关键字_第7张图片

虽然C++后期的学习也会提到范围for
但是大家有兴趣可以提前了解
详情可以参考这篇文章:

C++ 中不同类型的基于范围的 for 循环迭代器


下期预告:类和对象(上)

你可能感兴趣的:(C++初阶之路,c++,开发语言)