C++ 定义内联函数的正确方法是什么?
假设我有一个X类(X.h): 应该以何种方式定义C++ 定义内联函数的正确方法是什么?,c++,inline,C++,Inline,假设我有一个X类(X.h): 应该以何种方式定义avgPrice() (课堂上): X.h (在与类相同的文件中,但在类定义之外): X.h 或(在单独的头文件中): X.h: X-inl.h: #include "X.h" inline double X::avgPrice() { return unitsSold ? revenue / unitsSold : 0; } inline double X::avgPrice() { return unitsSold ? revenu
avgPrice()
(课堂上):
X.h
(在与类相同的文件中,但在类定义之外):
X.h
或(在单独的头文件中):
X.h:
X-inl.h:
#include "X.h"
inline double X::avgPrice() {
return unitsSold ? revenue / unitsSold : 0;
}
inline double X::avgPrice() {
return unitsSold ? revenue / unitsSold : 0;
}
只要向编译器添加
inline
建议,您提供的三个选项将(必须)产生相同的编译代码
这总是考虑由标准编译器执行标准编译任务…这取决于在何处使用内联函数,以及使用内联函数的频率。如果内联函数的代码很短(像大多数getter/setter一样),并且(很可能)在许多地方使用它,那么直接将其放入类定义中是一种简单的方法
如果您的内联函数是“海量”的,并且只被类中的少数用户使用,那么最好将其放入单独的头中。在这些情况下,这会加快编译速度,即不需要内联,但需要您将额外的头文件传递给lib的用户。我想可能会对
inline
关键字和内联函数/方法产生一些混淆
关键字inline
告诉编译器应该将函数/方法代码复制到调用函数/方法的位置。例如:
/* [...] */
inline void sayHello() {
std::cout << "Hello" << std::endl;
}
int main(int argc, char **argv) {
sayHello();
return 0;
}
/* [...] */
class X {
private:
unsigned int unitsSold;
double revenue;
public:
/* [...] */
double avgPrice() {
if (unitsSold == 0) {
return 0.0;
}
return revenue/unitsSold;
}
};
这三个选项都是正确的 取决于这样的事情之后:
- 如果函数很短(如getter/setter),则更常见的情况是在类定义中直接定义函数
- 如果您的函数更大,最好在另一个标题中定义它,并在使用该函数的源代码中仅包含此标题。这只会加快编译速度。但是很少有
内联
大函数
inline
关键字,编译器才会内联函数。由编译器决定是否在其使用的每个地方使用该函数
标准中明确规定了这一点:
7.1.2/2函数说明符[dcl.fct.spec]
带有内联
说明符的函数声明声明内联函数。内联说明符向实现表明,在调用点对函数体进行内联替换要优于通常的函数调用机制在调用点执行此内联替换不需要实现;但是,即使省略了此内联替换,也应遵守7.1.2中定义的内联函数的其他规则
最后一件事:
大多数编译器已经优化了代码,以便在更方便的时候生成内联函数。此说明符仅指示此函数首选内联的编译器
正如jrok所述,
inline
主要用于避免违反一个定义规则。在这里,我们还可以引用标准的一小部分:
(§7.1.2/4)内联函数应在使用它的每个翻译单元中定义,并且在每种情况下具有完全相同的定义(3.2)
3.2一条定义规则[basic.def.odr]
任何翻译单元不得包含任何变量、函数、类类型、枚举类型或模板的多个定义
我会选择有利于可读性的每种方法,这取决于函数的大小:
- 单行函数-->选项1
- 小尺寸功能-->选项2
- 中等大小函数-->选项3
- 大尺寸函数-->确定要内联吗
X-inl.h
,而不是X.h
。如果您修改如下:
X.h:
X-inl.h:
#include "X.h"
inline double X::avgPrice() {
return unitsSold ? revenue / unitsSold : 0;
}
inline double X::avgPrice() {
return unitsSold ? revenue / unitsSold : 0;
}
然后,您可以像通常那样包含
X.h
。可能对内联
说明符的含义有一些误解。是的,它确实给了编译器一个提示,提示编译器最好内联代码,而不是调用,但编译器并不被迫遵守这个提示。inline
说明符的主要用途是避免违反
一旦你声明了一个函数inline
,就需要在它使用的每个翻译单元中定义它,并且每次定义都必须完全相同。这与您的标题所建议的方式不同——定义函数的位置的选择要求是否需要将其标记为inline
1) 2)一切都好。在第一种情况下,它隐式地内联
,在第二种情况下,您显式地声明了它。无论在何处包含标题,定义都是相同的
案例3)仅在编译并链接X_impl.h
为源文件时才起作用。在这种情况下,只有一个定义,inline
将是多余的。这样编译器就看不到其他翻译单元中的定义,这使得它无法内联函数,不管它是否是inline
如果
X_impl.h
的目的是减小页眉的可视大小,那么您应该以另一种方式进行操作,将其包含在X.h
的末尾<代码>内联必须保持在这种情况下。@JOhn,考虑到编译器会做任何他认为必须做的事情,这一点非常清楚。inline
指令只是一个建议,如果优化器考虑这样做,编译器可以拒绝该建议。这个问题没有明确的答案
/* [...] */
int main(int argc, char **argv) {
std::cout << "Hello" << std::endl;
return 0;
}
/* [...] */
class X {
private:
unsigned int unitsSold;
double revenue;
public:
/* [...] */
double avgPrice() {
if (unitsSold == 0) {
return 0.0;
}
return revenue/unitsSold;
}
};
#ifndef _CLASS_X_H_
#define _CLASS_X_H_
class X {
private:
unsigned unitsSold = 0;
double revenue = 0.0;
public:
double avgPrice();
};
#include "X-inl.h"
#endif
inline double X::avgPrice() {
return unitsSold ? revenue / unitsSold : 0;
}