内联函数的定义:以inline修饰的函数叫做内联函数,编译时C++编译器会在调用内联函数的地方展开,如果没有压栈的开销,内联函数提升程序运行的效率。
为什么使用内联函数:
1.内联函数最初的目的是代替部分#define宏定义
原因:a.宏是预处理指令,在预处理的时候把所有的宏名用宏体来替换;内联函数是函数,在编译阶段把所有调用内联函数的地方把内联函数插入
b.宏没有类型检查,无论对还是错都是直接替换;而内联函数在编译时进行安全检查
c.宏的编写有很多限制,例如只能写一行,不能使用return控制流程等
d.对C++而言,使用宏代码还有另一种缺点:无法操作类的私有数据成员(因为宏是在编译之前处理的,它不知道类的访问权限设置)
2.使用内联函数代替普通函数的目的是:提高程序的运行效率
原因:普通函数频繁调用的过程消耗栈空间,函数调用时要花费开辟栈区的时间和返回主函数寻址的时间;内联函数节省了开辟函数栈和寻址的时间。
如果是一个几十行的函数,函数本身执行就很耗时,那调用函数、创建栈帧(每个栈帧对应着一个未运行完的函数。栈帧中保存了该函数的返回地址和局部变量,其实就是函数运行时开辟的函数栈)的一两行可以忽略不计;但是如果一个函数本身就一两行,因为调用函数本身而产生的那一部分消耗就格外突出,而宏或者内联的提前置换就显得格外优秀,提高了效率。
注意: 1.函数前面加上inline不一定会有效果,使用inline关键字修饰函数只是一种提示,编译器不一定认
2.如果不加inline不一定不是内联函数,存在隐式内联,不用inline关键字,C++中在类内定义的所有函数都自动称为内联函数
3.内联函数不应定会展开,要看编译器认不认
4.首先需要满足有inline修饰或者是类中定义的函数,然后再由编译器决定的情况下内联函数会展开
内联函数的特点:
1.inline是一种以空间换时间的做法,省去调用函数,建立栈帧得额外开销,但是如果代码很长(一般是10行左右,具体取决于编译器),或者有递归函数,即使函数前面声明了inline,那么编译器也不会让该函数成为内联函数。
2.inline对于编译器而言只是一个建议,编译器会自动优化,如果定义的函数很长或者递归函数等等,编译优化时会忽略掉内联;而类的构造函数,析构函数和虚函数往往不是内联函数的最佳选择。
3.inline不可以声明和定义分离,.h文件中使用inline声明内联函数(内联展开是在编译时进行的,只有链接的时候源文件之间才有关系),.cpp文件中如果不使用inline定义函数,会报错链接错误。
内联函数与普通函数的区别:
1.内联函数在编译时展开,没有函数调用的开销,但可能会增加代码体积
2.普通函数在运行时进行调用,有一定的调用开销,但代码更紧凑
3.内联函数的定义通常放在头文件中,而普通函数定义放在源文件中,头文件只包含函数声明
定义:
在函数声明前加上"inline"关键字来定义内联函数
inline nint add(int a,int b)
{return a+b;
}
使用:使用时和普通函数一样调用即可
内联分为显式内联和隐式内联
显式内联:需要使用inline关键字,是在建议编译器将该函数作为内联函数处理。
// 显式内联函数定义
inline int add(int a, int b) {return a + b;
}
int main() {int result = add(3, 5);// 在这里,编译器可能会将add函数的代码直接插入到调用点return 0;
}
隐式内联:类内的成员函数的定义直接写在类的声明中时,不需要inline关键字,编译器会隐式地将其视为内联函数候选。
class Work {
public:// 隐式内联成员函数int multiply(int a, int b) {return a * b;}
};
int main() {Work w;int result = w.multiply(4, 6);// 这里编译器可能会将multiply函数的代码直接插入到调用点return 0;
}
内联函数的使用场景
1.当对程序执行性能有要求时,那么就适当使用内联函数
2.当想宏定义一个函数时,使用内联函数
3.写一些功能专一且性能关键的函数,这些函数的函数体不大,包含了很少的执行语句。通过inline声明,编译器不需要跳转到内存其他地址去执行函数调用,也不需要保留函数调用时的现场数据。
4.在类内部定义的函数会默认声明为inline函数,这有利于类实现细节的隐藏。(大部分是不推荐默认inline的)
不建议使用:
1.如果函数体内的代码比较长,使用内联将导致内存消耗代价较高。
2.如果函数体内出现循环或者开关语句还有递归;那么执行函数体内代码的时间要比函数调用的开销大,还有可能造成栈空间枯竭。