1. inline的作用
在预编译的时候,编译器将程序中出现的内联函数的调用表达式的地方,直接插入用内联函数的代码
2. 内联机制
内联函数的“可调式”不是说它展开后还能调试,而是在程序的Debug版本里它根本就没有真正内联,编
译器像普通函数那样为它生成含有调试信息的可执行代码。在程序的Release版本里,编译器才会实施真正
的内联。
3. 替代C中表达式形式的宏定义(macros)
template <typename T>
inline const T& std::max(const T& a,const T& b)
{return a<b?b:a}
对于形似函数的宏,最好改用inline函数替换#dfine
4. inline函数与宏定义对比
1. 宏的缺点
宏不可以调试,而内联函数是可以调试的
无法操作类的私有数据成员
2. inline函数的优点
函数被内联后,编译器就可以通过上下文相关的优化技术对结果代码执行更深入的优化,而这种优化
在普通函数体内是无法单独进行的
5. 内联函数的使用
1. 如果想把一个函数定义为内联函数,则需要在函数名前面放置关键字 inline,内联函数的定义必须出
现在内联函数第一次调用之前。
2. 关键字 inline 必须与函数定义体放在一起才能使函数成为内联,
仅将 inline 放在函数声明前面不起任何作用。
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 与函数定义体放在一起
Tips:尽管在大多数教科书中内联函数的声明、定义体前面都加了inline 关键字,但我认为inline不应该出现在函数的声明 中。这个细节虽然不会影响函数的功能,但是体现了高质量C++/C 程序设计风格的一个基本原则:声明与定义不可混为一谈,用户没有必要、也不应该知道函数是否需要内联。
6. 类中使用内联函数
定义在类声明之中的成员函数将自动地成为内联函数,例如:
class A { public: void Foo(int x, int y) { ... } // 自动地成为内联函数 }
但是编译器是否将它真正内联则要看 Foo函数如何定义。
内联函数应该在头文件中定义,这一点不同于其他函数。编译器在调用点内联展开函数的代码时,必须能够找到 inline 函数的定义才能将调用函数替换为函数代码,而对于在头文件中仅有函数声明是不够
的。
当然内联函数定义也可以放在源文件中,但此时只有定义的那个源文件可以用它,而且必须为每个源文件拷贝一份定义(即每个源文件里的定义必须是完全相同的),当然即使是放在头文件中,也是对每个定义做一份拷贝,只不过是编译器替你完成这种拷贝罢了。但相比于放在源文件中,放在头文件中既能够确保调用函数是定义是相同的,又能够保证在调用点能够找到函数定义从而完成内联(替换)。
内联函数可以在程序中定义不止一次,只要 inline 函数的定义在某个源文件中只出现一次,而且在所有源文件中,其定义必须是完全相同的就可以。在头文件中加入或修改 inline 函数时,使用了该头文件的所有源文件都必须重新编译。
7. 慎用内联
- 如果函数体内的代码比较长,使用内联将导致可执行代码膨胀过大;
- 如果函数体内出现循环或者其他复杂的控制结构,那么执行函数体内代码的时间将比函数调用的开销大得多,因此内联的意义并不大;
- 构造函数和析构函数不建议为内联函数,但是可以内联;
- 虚函数可以是内联函数,内联是可以修饰虚函数的,但是当虚函数表现多态性的时候不能内联。内联是在编译器建议编译器内联,而虚函数的多态性在运行期,编译器无法知道运行期调用哪个代码,因此虚函数表现为多态性时(运行期)不可以内联。inline virtual 唯一可以内联的时候是:编译器知道所调用的对象是哪个类(如 Base::who()),这只有在编译器具有实际对象而不是对象的指针或引用时才会发生。