内联成员函数和普通成员函数有什么区别?

4

内联成员函数(函数体内联)和其他普通成员函数(函数体在单独的.cpp文件中)有什么区别吗?

例如,

class A
{
  void member(){}
};

并且。
// Header file (.hpp)

class B
{
  void member();
};

// Implementation file (.cpp)

void B::member(){}
4个回答

7

这两者完全没有区别。

唯一的区别在于类内部的成员被隐式标记为inline,但这没有实际意义。

参见:inline and good practices

文档表示,inline标签是开发人员向编译器提示一个方法应该被内联的提示。所有现代编译器都会忽略这个提示,使用自己的内部启发式算法来确定何时应该内联一个方法(因为人类在做出这个决定方面非常糟糕)。

inline的另一个用途是告诉链接器可能会看到多个方法的定义。当函数定义在头文件中时,每个得到头文件的编译单元都会有一个函数定义(假设它没有被内联)。通常这会导致链接器生成错误。使用inline标签,编译器理解为什么会有多个定义,并将从应用程序中删除所有除一个之外的定义。

关于内联过程的注意事项:方法不需要在头文件中才能内联。现代编译器具有完整应用程序优化的过程,即使它们已经在不同的编译单元中编译,所有函数也可以被视为内联。由于inline标志通常被忽略,因此将方法放在头文件或源文件中都没有区别。


1
问题是关于类声明内的成员函数体,而不是关于inline关键字的。 - Nikolai Fetissov
@ Nikolai N Fetissov:添加了一行说明为什么我谈论内联。 - Martin York

3
忽略此处的"inline"和编译器提示,因为它们与问题无关。
A和B之间的重要实际区别在于它们在不同库中的使用方式。
对于A,您可以#include头文件而无需链接任何内容。因此,您可以在不同的应用程序/库中使用此类,而无需进行任何特殊的链接。
对于B,您需要B.cpp,并且这应该只编译到一个库/应用程序中。任何其他需要使用此类的库或应用程序都需要链接到包含实际代码主体的库。
对于某些设置/实现,您需要在库之间将类明确标记为“已导出”或“已导入”(例如,在Windows上,您可以使用dllimport / dllexport,在GNU上,您可以使用attribute(visibility="default)")。

2
第一个是隐式的inline,即建议编译器在调用处展开它。

4
那是一个红鲱鱼。大多数编译器(所有现代编译器)都会忽略这个建议,因此该标志在内联方面基本上没有任何作用。 - Martin York
是的,整个语言都有点可疑 :) - Nikolai Fetissov

1

除了内联的东西之外,还有一个区别是你可以在class B的定义和函数的定义之间放置更多的定义。

例如,B.cpp可能包含B.hpp没有的头文件,这对于大型项目的构建过程可能会产生重大影响。

但即使没有单独的翻译单元,您也可以偶尔遇到通过分离定义来解决的循环依赖关系。例如,该函数可能会接受一个类型参数,在B被定义之前进行前向声明,然后在函数定义时进行定义。如果该类型在其自身的定义中使用B的定义,那么它不能仅在B之前定义。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接