编程语言

面向对象程序设计第四节-内联函数(2020-01-29)

2020-01-29  本文已影响0人  _NewMoon

下棋真没意思,还是把上午学的记录一下

内联函数(Inline function)

1.调用函数的额外开销(Overhead for a function call)

先来看一下当我们调用函数时会发生哪些事,我们知道,本地变量都保存在堆栈区,当我们调用函数时,会将本地变量以及相关的参数一个一个入栈,接着按照函数内部的代码对这些值操作,然后,如果栈顶不是返回值,就出栈,直到栈顶元素是函数的返回值,向主函数返回此值。
从以上过程我们可以看出,当我们调用一个函数时,会在堆栈上进行一系列的入栈出栈操作,如果将函数调用的地方替换成等价的表达式,根据汇编语言的结果(这里网上的解释非常多,本人还没有学习汇编语言,此处就先跳过了),会发现少了很多步骤,即降低了程序的运行时间。

2.内联函数的引入

这时C++为我们提供了一个可以减少调用函数调用开销的方法,将函数声明成内联函数:

inline void function();

将函数声明成内联函数之后会发生什么样的变化?简单来说,当程序运行到调用函数的地方时,会将函数体嵌入到调用的地方,就不会进行堆栈的相关操作,从开减少运行时开销,我们看《C++ Primer》上的例子:
这里有一个比较两个字符串长度的函数:

const string &shorterString(const string &s1, const string &s2)
{
    return s1.size()<=s2.size()? s1:s2;
}

现有如下调用:

cout << shorterString(s1, s2) << endl;

将在编译过程中展开成类似于下面的形式:

cout << (s1.size() <= s2.size() ? s1:s2 )<< endl;

3.几个需要注意的地方

可能有人会对此产生疑问,将函数声明成内联函数不是减少了函数调用时的开销了么,为什么编译器会拒绝这种“对自己有益的事”,别急!下面两点注意就会提到。

这下我们就知道了为什么编译器可能会拒绝你的请求了,如果一个函数体很长,将它内嵌到调用的地方时不大现实的,如果函数是递归的,也不能声明成内联函数,因为递归函数是肯定需要用到堆栈的操作的。

在第一节中我们提到,一般在编写类时,将类的声明写在一个".h"文件中,类中只有函数的声明没有定义,将这些成员函数的定义写在一个".cpp"文件中,再写一个"main.cpp"程序作为启动的地方,但是如果我们将类的成员函数声明成内联函数,就不要那个".cpp"文件,函数的声明以及定义全都放在".h"文件中,这是因为在"main.cpp"文件中,我们引入了".h"文件,当调用类的成员函数(已被声明成内联的)时,因为内联函数需要将函数体嵌入到调用点,而程序在同一时间里只能看到一个文件,所以它无从得知函数体,就会发生错误。一般情况下,如果类中的成员函数声明和定义写在一起或者函数体很短只有两三行,编译器会将这些函数自动内联~

上一篇下一篇

猜你喜欢

热点阅读