我刚与同事讨论了头文件中的代码:
他说,头文件中定义的代码将始终由编译器内联(如我的示例头中的函数GetNumber()中的代码)。我说有时,只要编译器决定这样做,它就会被内联。那么我们哪一个人必须带上一块蛋糕才能说出肮脏的谎言?或者也许我们都错了......?
MyClass.hpp
class MyClass
{
public:
MyClass();
~MyClass();
int GetNumber() const
{
//...;
return m_number;
};
private:
int m_number;
};
答案 0 :(得分:12)
在类中定义的任何函数(如GetNumber示例)而不是刚刚声明的函数是隐式inline
。这意味着它与使用inline
关键字无关,因此由于这些函数的多个定义,标题的多个包含不会导致链接错误。
大多数现代编译器都将inline
视为链接命令,仅此而已。有些编译器提供了更强大的关键字,例如CL __forceinline
,这意味着'如果可以的话,可以内联这个'。
所以你们两个都是正确的,而且都是错误的。
答案 1 :(得分:7)
你的朋友错了,你是对的。
内联不取决于代码的位置(标头与否)。预处理后,没有标题或非标题。整个单元是一个单独的文件,它包含所有包含的东西。
尝试运行gcc预处理器,然后你会看到:
gcc -E some_source_file_with_includes
答案 2 :(得分:4)
实际上两者都是正确的。你们的意思是有点不同。 (我猜)
来自内联函数的C ++标准文档,
- 功能声明(8.3.5,9.3, 11.4)使用内联说明符声明内联函数。
醇><强> 2。在类中定义的函数 定义是内联函数。
正如你的同事所说,确实是内联函数。
但内联函数的代码替换而不是正常的函数调用取决于编译器。 (我希望这就是你的意思)即使编译器没有替换它仍然是一个内联函数。
希望它能解决你的担忧..
答案 3 :(得分:3)
这取决于“内联”的含义。如果在头文件中定义了某些内容,它将被单独编译到包含它的每个编译单元中。是否内联的任何调用将由编译器决定。
答案 4 :(得分:2)
类成员函数定义 (与声明的相反)在类定义中 隐式 inline
。标头中的其他代码不是。
您可以轻松地检查:创建一个带有标题和两个实现文件的小型C ++项目,定义一个函数
void print(std::ostream& os)
{
os << "Hello, world!\n";
}
标题中的并在两个实现文件中包含该标头。链接器现在会抱怨函数定义了两次。在函数定义之前放置inline
,错误将消失。
然而,还有一些违规行为。例如,常量定义将自动获得外部链接。因此,一个
const int answer = 42;
标题中的不会让链接器抱怨answer
的多个定义,而
int question;
意愿。
答案 5 :(得分:1)
这不是真的,如果在类声明中指定,则只会内联成员函数中的代码(如果编译器决定这样做)。它必须允许定义成员,因此它们可能被声明为C的static
(它将允许在编译单元中使用,但不能链接到其他目标文件),这将在每个目标文件中放置一个版本。自己尝试一下,你会注意到除非你为类声明之外的任何东西指定inline关键字,否则你会得到重复。
答案 6 :(得分:1)
编译器决定。即使使用_inline
也只是告诉编译器您更喜欢内联代码,但编译器的成本/收益分析器可以做出其他决定。
如果您使用Microsoft C++来使代码内联,则可以使用_forceinline
,但这可能会导致更大的二进制文件。