可以在头文件中定义一个很长的 Class 函数成员吗?

Could a very long Class function member defined in header file?

我在头文件中定义了一个class,并在同一个头文件中实现了它的功能。我没有在函数定义中放置 inline 关键字,因为我认为默认情况下编译器会将其视为内联函数——但 inline 只是对编译器的提示,对吧?如果编译器因为它的长度而不将其视为内联函数怎么办?我在现实中从未收到错误消息 'multiple definitions'。

struct tmp {
    void print() {
       ...(very long)
     }
};

编辑 @Leon(下)表示我的回答(转载于下)是不正确的。正确答案描述为 here - 简而言之,如果编译器决定不使函数内联,它仍将其放入目标模块中。但是链接器随后将在不同模块中选择一个(可能很多)副本并丢弃所有其他副本。


你是对的:你不会得到 "multiple definition" 错误,因为每次编译器决定 将函数内联时,它会使函数 static 在当前模块中。这意味着您的代码中可能散布着大量大型函数的副本。

I didn't put inline keyword with function definition because I think compiler will regard it as a inline function by default

是的,在 class 的函数体中定义的成员函数隐式 inline。关键字不是必需的。

inline is only a hint to compiler, right? What if compiler doesn't regard it as inline function because of its length?

是的,有点。实际上,inline关键字有两个含义。

第一个是您正在考虑的那个,提示优化器在调用站点的函数体中内联代码的那个。正如您所说,这只是一个提示——如果优化器确定这样做会导致性能悲观(或者由于其他技术原因无法内联),则优化器可以随意忽略此请求。 inline 关键字的这种含义可以说已经过时了。现在所有的优化编译器都忽略了 inline 关键字,因为它们的作者认为他们的启发式方法比程序员更聪明。几乎总是如此,因此通过将函数标记为内联来尝试和猜测优化器变得毫无意义。

inline 关键字的第二个含义是放宽单一定义规则 (ODR),使链接器可以看到同一函数的多个定义是合法的。 (虽然链接器在这种情况下的行为是一个实现细节,但它们中的大多数只会任意选择一个定义。当然,只有在它们都相同的情况下才能很好地工作。) inline 关键字的这个含义仍然是非常重要,并解释了为什么它今天仍在代码中使用。

这就是您的代码受益的含义。由于在 class 的主体中定义的成员函数被隐式标记为内联,因此您不会从链接器中获得多重定义的符号错误。

如果您在头文件中定义了函数,但 不是 在 class 定义中——换句话说,如果您这样做了:

struct tmp {
    void print();
};

void tmp::print()
{ ... }

然后,一旦该头文件包含在两个或多个编译区(,翻译单元)中,您就会开始出现多重定义的符号错误。这是您需要在函数定义中添加 inline 关键字的地方,不是因为您希望编译器 "inline" 它,而是因为您想免除 ODR。