Inline 函数

本文介绍了C++中内联函数的基本规则及其使用注意事项,包括递归调用、复杂流程控制、函数体长度限制等方面的内容。

                                  Inline 函数

1.   规则一、一个函数可以自已调用自已,称为递归调用(后面讲到),含有递归调用的函数不能设置为inline

 

2.   规则二、使用了复杂流程控制语句:循环语句和switch语句,无法设置为inline

 

3.   规则三、由于inline增加体积的特性,所以建议inline函数内的代码应很短小。最好不超过5行。

 

4.   规则四、inline仅做为一种“请求”,特定的情况下,编译器将不理会inline关键字,而强制让函数成为普通函数。出现这种情况,编译器会给出警告消息。

5.   规则五、在你调用一个内联函数之前,这个函数一定要在之前有声明或已定义为inline,如果在前面声明为普通函数,而在调用代码后面才定义为一个inline函数,程序可以通过编译,但该函数没有实现inline

 

void test()

 

// 中间调用test(),则没有实现inline

 

inline void test()

{

   //….

}

 

这里面顺便提一下,如果一个普通函数定义在.h文件里面,这个头文件被多个.cpp文件include的时候,会出现重复定义的错误,因为编译后每个.cppobj文件里面都有该函数的实现,所以一链接就出错,这和普通全局变量一样。解决的办法

a.   如果是简单的函数就可以让它变成内联函数。

b.   也可以加static,让其成为静态函数

c.   把其定义移到.cpp文件中去。

 

6.    规则六、为了调试方便,在程序处于调试阶段时,所有内联函数都不被实现。非类成员函数时

 

7.   关键字inline 必须与函数定义体放在一起才能使函数成为内联,仅将inline 放在函数声明前面不起任何作用。

如下风格的函数Foo 不能成为内联函数:

inline void Foo(int x, int y); // inline 仅与函数声明放在一起

void Foo(int x, int y)

{

}

而如下风格的函数Foo 则成为内联函数:

void Foo(int x, int y);

inline void Foo(int x, int y) // inline 与函数定义体放在一起

{

}

注意:把一个函数的定义放到一个头文件里面是一个规则性的东西。除非函数只是在一个单独的cpp文件中调用到了。特别的,如果你把内联函数放在一个cpp文件里面,而你从其他的cpp文件里面调用它,你会在连接器得到一个"unresolved external"错误。

inline functions 一般必须在头文件内,因为大多数构建环境在编译期间进行 inlining(内联化)。为了用被调用函数的函数本体替换一个函数调用,编译器必须知道函数看起来像什么。(有一些构建环境可以在连接期间 inline,还有少数几个——比如,基于 .NET Common Language Infrastructure (CLI) 的托管环境——居然能在运行时 inline。然而,这些环境都是例外,并非规定。inlining(内联化)在大多数 C++ 程序中是一个 compile-time activity(编译期行为)。)

templates 一般在头文件内,因为编译器需要知道一个 template 看起来像什么以便需要时对它进行实例化。(同样,也不是全部如此。一些构建环境可以在连接期间进行 template instantiation(模板实例化)。然而,compile-time instantiation(编译期实例化)更为普遍。)

所以说,inline 是一种“用于实现的关键字”,而不是一种“用于声明的关键字”。一般地,用户可以阅读函数的声明,但是看不到函数的定义。尽管在大多数教科书中内联函数的声明、定义体前面都加了inline 关键字,但我认为inline 不应该出现在函数的声明中。这个细节虽然不会影响函数的功能,但是体现了高质量C++/C 程序设计风格的一个基本原则:声明与定义不可混为一谈,用户没有必要、也不应该知道函数是否需要内联。

 

8.   定义在类声明之中的成员函数将自动地成为内联函数,例如

class A

{

public:

void Foo(int x, int y) {  } // 自动地成为内联函数

}

将成员函数的定义体放在类声明之中虽然能带来书写上的方便,但不是一种良好的编程风格,上例应该改成:

// 头文件

class A

{

public:

void Foo(int x, int y) // 不需要加上inline关键字

}

// 定义文件 .cpp

inline void A::Foo(int x, int y)

{

}

 

`inline` 函数C++ 中的一个关键字,用于建议编译器函数体直接插入到调用该函数的地方,而不是进行常规的函数调用。这样可以减少函数调用的开销(如压栈、跳转等),从而提高程序的执行效率,尤其适用于短小且频繁调用的函数。 ### 为什么使用 `inline`? 函数调用本身有一定的开销,包括: - 参数压栈 - 控制权转移 - 返回值传递 - 栈帧恢复 对于非常简单的函数(例如获取成员变量的 getter 函数),这些开销可能比函数本身的执行还要大。通过 `inline`,编译器会尝试将函数展开为内联代码,避免这些开销。 --- ### 使用方式 ```cpp #include <iostream> using namespace std; // 定义 inline 函数 inline int add(int a, int b) { return a + b; } inline int getMax(int a, int b) { return (a > b) ? a : b; } class Counter { private: int count; public: Counter() : count(0) {} // 类内定义的成员函数默认是 inlineinline void increment() { ++count; } inline int getCount() const { return count; } }; int main() { int x = 5, y = 10; cout << "Add: " << add(x, y) << endl; cout << "Max: " << getMax(x, y) << endl; Counter c; c.increment(); cout << "Count: " << c.getCount() << endl; return 0; } ``` --- ### 关键点解释: 1. **`inline` 是一个建议,不是强制命令** 编译器可以选择忽略 `inline` 请求,特别是在函数体较大或包含递归的情况下。是否真正内联由编译器决定。 2. **通常在头文件中定义 `inline` 函数** 因为多个源文件包含同一个头文件时,需要避免“多重定义”错误。`inline` 函数允许多次定义(只要定义相同),符合 ODR(One Definition Rule)的例外情况。 3. **类内部定义的成员函数自动为 `inline`** 在类声明内部实现的成员函数(如上面的 `increment()` 和 `getCount()`)会被隐式地视为 `inline`。 4. **不能内联的情况示例:** ```cpp inline void heavyFunction() { for(int i = 0; i < 1000000; ++i) { // 大量代码 } } // 编译器很可能忽略 inline ``` 5. **模板函数也常需定义在头文件中,通常配合 inline 思想使用** 虽然模板不一定要加 `inline`,但为了防止链接错误,通常也在头文件中定义。 --- ### 示例:头文件中的 inline 函数(推荐写法) **math_utils.h** ```cpp #ifndef MATH_UTILS_H #define MATH_UTILS_H inline int square(int x) { return x * x; } inline double average(double a, double b) { return (a + b) / 2.0; } #endif // MATH_UTILS_H ``` **main.cpp** ```cpp #include "math_utils.h" #include <iostream> using namespace std; int main() { cout << "Square of 5: " << square(5) << endl; cout << "Average of 3 and 7: " << average(3, 7) << endl; return 0; } ``` 这个结构是安全的,因为 `inline` 允许跨翻译单元多次定义。 --- ### 注意事项 - ❌ 不要滥用 `inline`。只对小型、频繁调用的函数使用。 - ✅ 建议仅对性能敏感的小函数使用。 - ⚠️ `inline` 不等于“更快”,过度使用可能导致代码膨胀(code bloat),反而影响缓存性能。 - 🔄 静态成员函数、普通函数、友元函数都可以是 `inline`。 --- ### 相关底层机制(可选了解) 现代编译器(如 GCC、Clang、MSVC)即使没有 `inline` 关键字,也会根据优化级别(如 `-O2`)自动进行函数内联。因此,`inline` 更多是给编译器的一个提示。 你也可以使用编译器扩展来强制内联,例如: ```cpp // GCC/Clang __attribute__((always_inline)) inline void func() { ... } // MSVC __forceinline void func() { ... } ``` 但这应谨慎使用。 ---
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值