一.内联函数
1.定义
通过inline修饰的函数我们称之为内联函数,下面我们将通过实例进行说明:
#include <iostream>
using namespace std;
int Add(int left, int right)
{
return left + right;
}
int main()
{
int ret = Add(1, 2);
cout << ret << endl;
return 0;
}
调试代码我们通过转到反汇编我们可以发现,正常使用函数时,我们会去进行函数调用:
当我们修改Add函数在其前面加上inline修饰后即:
inline int Add(int left, int right)
{
return left + right;
}
我们会发现在编译期间函数的调用被直接替换成了函数体:
(注:以上是debug模式下的操作,debug下要查看到该变化可能需要对编译器进行设置,VS通常是在项目-属性中,将C/C++中调试信息格式改为程序数据库(/Zi),将内联函数扩展改为 只适用于 __inline(/0b1),可以通过搜索查找修改)
综上,C++在编译时会在调用内联函数的地方展开,这样会减少函数调用时建立栈帧的开销从而提升程序运行的效率。
2.特性
1.inline通常不建议将声明和定义分离,因为当inline被展开时,就没有函数地址了,链接会找不到从而导致链接错误。
如:
//以下为Add.h
#include <iostream>
using namespace std;
inline int Add(int left, int right);
// 以下为Add.cpp
#include "Add.h"
inline int Add(int left, int right)
{
return left + right;
}
//以下为main.cpp
#include "Add.h"
int main()
{
int result = Add(1, 2);
cout << result << endl;
return 0;
}
当运行以上代码时,编译器会报错如下:
2.inline提高效率的本质是以空间换时间,即使用inline可能会使目标文件变大但会提高运行效率。
3.inline对于编译器来说仅仅是一个建议,编译器可以选择忽略这个请求,且不同编译器对于inline实现的机制可能不同,一般来说,通常函数规模较小、非递归且频繁使用的函数可以采用inline修饰,否则编译器可能会忽略inline特性。
二.auto关键字
1.定义
早期C/C++给auto的含义为:使用auto修饰的变量,表示具有自动存储器的局部变量,但很少会有人去使用,在C++11中,标准委员会赋予了它全新含义:auto不再是一个存储类型的指示符,而是作为一个新的类型指示符来指示编译器,auto声明的变量必须由编译器在编译时期推导而得,我们可以理解为auto可以根据你所给的变量自动推导其类型。
int test()
{
return 1;
}
int main()
{
int n1 = 10;
auto n2 = n1;
auto n3 = 'a';
auto n4 = test();
cout << typeid(n1).name() << endl;
cout << typeid(n2).name() << endl;
cout << typeid(n3).name() << endl;
cout << typeid(n4).name() << endl;
return 0;
}
我们可以得到以下结果:
我们可以看到根据不同的情况auto会自动推导成不同的类型。也因为这样所以我们在使用auto定义变量时必须初始化。假如我们如下使用:
int main()
{
auto n;
return 0;
}
则会报错如下:
思考:
我们为什么需要用到auto关键字呢?难道我们直接表明变量的类型不是更好吗?或许大家有这样的想法,其实是因为随着我们学习的深入,程序会越来越复杂,程序中用到的类型也可能越来越复杂甚至有很长一串,我们在使用时可能会出现类型难拼写、含义不明确等错误,我们可以联想到我们有时候为什么要用typedef对一些很长的名称取别名。
2.使用
1.结合指针和引用使用
当我们用auto声明指针类型时,使用auto和auto*没有任何区别,但用auto声明引用变量时必须+&:
int main()
{
int n = 10;
auto n1 = &n;
auto* n2 = &n;
//以上两种方式无区别
auto& n3 = n;//必须+&
return 0;
}
2.声明定义多个变量
当同一行声明多个变量时,这些变量必须时相同的类型,其原理是根据第一个变量的类型进行推导从而定义后面的变量。
int main()
{
auto n1 = 10,n2 = 100;//正确
auto n3 = 20,n2 = 20.2;//错误,会编译失败,结果如下图
return 0;
}
注意:
1.auto不能做函数参数;
2.auto不能用于声明数组;
3.auto在C++11中只保留了auto作类型指示符的用法从而避 免与C++98混淆。
三.基于范围的for循环
1.使用
直接上代码:
int main()
{
int array[] = { 1, 2, 3, 4, 5 };
for(auto& n : array)
{
n++;
}
for(auto n : array)
{
cout << n << endl;
}
return 0;
}
输出结果:
我们可以看到以上代码的功能为:取array数组中的每一个数进行自加1并打印。两个for的用法即为范围for的用法,即:**for循环后的括号由冒号分为两部分:前者是范围内用于迭代的变量,后者表示被迭代的范围。**即依次将array中的数取到n中进行自加1和打印操作,auto用于自动推导n的类型(这也是auto的另一个常使用的方式),这里改为int效果相同。
注:范围for也可以通过continue跳过本次循环,通过break结束循环。
2.使用条件
1.循环迭代的范围必须确定。
int main()
{
int array[];
//int array[10]; 可以
for (auto& n : array)
{
cout << n << endl;
}
return 0;
}//由于array数组未定义,不知道其大小范围,导致范围for的范围不确定,因此会报错如下:
2. 迭代的对象要实现++和==的操作。(具体原因需要了解范围for的底层原理以及迭代器的使用,我们后续学到后再具体谈)
本篇文章到此结束,有错误欢迎各位大佬讨论指正,谢谢。