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

时间:2016-06-14 11:29:47

标签: c++ class inline

我在头文件中定义了一个类,并在同一个头文件中实现了它的功能。我没有将inline关键字与函数定义放在一起,因为我认为编译器默认将它视为内联函数 - 但是内联只是编译器的一个提示,对吧?如果编译器因其长度而不将其视为内联函数会怎么样?我从来没有收到错误消息'多个定义'实际上。

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

2 个答案:

答案 0 :(得分:2)

  

我没有将inline关键字与函数定义放在一起,因为我认为编译器默认将它视为内联函数

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

  

inline只是编译器的一个提示,对吧?如果编译器由于其长度而不将其视为内联函数会怎么样?

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

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

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

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

如果你在头文件中定义了这个函数,但是在类定义中不是 - 换句话说,如果你这样做了:

struct tmp {
    void print();
};

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

然后,只要该头文件包含在两个或更多个compilands(,翻译单元)中,您就会开始获得多重定义的符号错误。这是您需要在函数定义中添加inline关键字的地方,而不是因为您希望编译器能够"内联"它,但因为你想要免除ODR。

答案 1 :(得分:0)

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

你是对的:你不会得到“多重定义”错误,因为每次编译器决定将函数内联时,它会使函数static在当前模块。这意味着您可以通过代码填充大量功能的大量副本。