C++知识点-内联函数

内联函数是C++为了提高程序的运行速度而诞生的一项技术。要理解内联函数的作用必须对计算机组成和汇编原理有所了解。这里简单介绍下。

简介

我们知道当程序在运行时遇到函数调用,对应到CPU内部就会处理跳转指令,此时会需要将调用函数代码处下一条指令记录到寄存器中以便函数返回时能够继续往下顺序执行,并且还需要将函数参数复制到栈中。这显然会在程序运行过程中增加负担。

当调用内联函数,编译器会使用响应的函数代码替换函数调用。因此,程序无须进行两次跳转。内联函数的运行速度比常规函数稍快,代价就是需要占用更多的内存,如果程序在不同的地方调用了10次相同的内联函数,编译后该函数就会有10个内联函数的副本。
在这里插入图片描述

内联函数的使用

要使用这项特性,必须满足如下要求

  • 在函数声明前加上 inline
  • 在函数定义前加上 inline
    通常的做法是省略函数原型,将整个定义放在应提供原型的地方。要注意,有些编译器并不一定会满足内联函数的要求,比如函数体过大或者函数调用了自己(内联函数不能调用自己)

基本使用

#include <iostream>

// inline function definition
inline double square(double x) {
    return x * x;
}

int main() {
    using namespace std;
    double a, b;
    double c = 13.0;
    double d = 13.0;

    a = square(5.0);
    b = square(4.5 + 7.5);
    cout << "a = " << a << ", b = " << b << "\n";
    cout << "c = " << c;
    cout << ", c squared = " << square(c++) << "\n";
    cout << ", d squared = " << square(++d) << "\n";
    cout << "Now d = " << d << "\n";
    return 0;
}

output

a = 25, b = 144
c = 13, c squared = 169
, d squared = 196
Now d = 14

上述代码虽然没有给出内联函数的原型,但程序还能正常运行,这是因为在函数首次使用前出现的整个函数定义充当了原形。
内联函数也是按值传递参数,但是C语言中的宏就不能按值传递,其只是简单的复制。

类中的内联函数

It is also possible to define the inline function inside the class. In fact, all the functions defined inside the class are implicitly inline. Thus, all the restrictions of inline functions are also applied here. If you need to explicitly declare inline function in the class then just declare the function inside the class and define it outside the class using inline keyword.

类中的函数是隐式内联函数,如果要显示表明可以在函数定义出加上 inline。

#include <iostream>

using namespace ::std;
class Demo {
public:
    void show();
};

inline void Demo::show() {
    cout << "class inline function." << endl;
}

int main() {
    Demo d;
    d.show();
    return 0;
}

内联函数和虚函数

因为类中的函数都是隐式内联函数,那么我们自然能将内联函数和虚函数联系起来。

When the object is referenced via a pointer or a reference, a call to a virtual function cannot be inlined, since the call must be resolved dynamically. Reason: the compiler can’t know which actual code to call until run-time (i.e., dynamically), since the code may be from a derived class that was created after the caller was compiled.

Therefore the only time an inline virtual call can be inlined is when the compiler knows the “exact class” of the object which is the target of the virtual function call. This can happen only when the compiler has an actual object rather than a pointer or reference to an object. I.e., either with a local object, a global/static object, or a fully contained object inside a composite.

Note that the difference between inlining and non-inlining is normally much more significant than the difference between a regular function call and a virtual function call. For example, the difference between a regular function call and a virtual function call is often just two extra memory references, but the difference between an inline function and a non-inline function can be as much as an order of magnitude (for zillions of calls to insignificant member functions, loss of inlining virtual functions can result in 25X speed degradation! [Doug Lea, “Customization in C++,” proc Usenix C++ 1990]).

上述内容我们概括一下:

  • inline virtual 唯一可以内联的时候是:编译器知道所调用的对象是哪个类,这只有在编译器具有实际对象而不是对象的指针或引用时才会发生。
  • 大多数时候,因为虚函数的多态性,其只有在运行时才能知道具体调用哪个子类的代码,因而不能在编译期使用内联的技术。
#include <iostream>
using namespace std;
class Base {
public:
    inline virtual void show() {
        cout << "I am Base.\n";
    }
    virtual ~Base() {}
};

class Derived: public Base {
public:
    inline void show() {
        cout << "I am derived.\n";
    }
};

int main() {
    Base b;
    // 使用的是具体的类,内联有效
    b.show();

    Base *pt = new Derived();
    // 多态,内联无效
    pt->show();

    delete pt;
    pt = nullptr;

    return 0;
}

Reference

1.Are “inline virtual” member functions ever actually “inlined”?
2.《C++ Primer Plus 6th》

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值