内联成员函数(函数体内联)和其他普通成员函数(单独的.cpp文件中的函数体)之间是否有任何区别?
例如,
class A
{
void member(){}
};
和
// Header file (.hpp)
class B
{
void member();
};
// Implementation file (.cpp)
void B::member(){}
答案 0 :(得分:7)
绝对没有区别。
两者之间的唯一区别是类中的成员被隐式标记为内联。但这没有任何实际意义。
文档说内联标记是编译器(由开发人员)提示应该内联方法的提示。所有现代编译器都忽略了这个提示,并使用自己的内部启发式方法来确定何时应该内联一个方法(因为人类出了名而且做出了这个决定)。
内联的另一个用途是它告诉链接器它可能期望看到方法的多个定义。当函数定义在头文件中时,获取头文件的每个编译单元都将具有该函数的定义(假设它不是内联的)。通常这会导致链接器生成错误。使用内联标记,编译器可以理解为什么有多个定义,并且将从应用程序中删除除一个以外的所有定义。
关于内联进程的注意事项:方法不需要在头文件中内联。现代编译器有一个完整的应用程序优化过程,即使它们已经在不同的编译单元中编译,也可以考虑所有函数进行内联。由于内联标志通常被忽略,因此如果将方法放在标题或源文件中,则没有任何区别。
答案 1 :(得分:3)
忽略此处的内联词和编译器提示,因为它不相关。
A和B的重大实际区别在于它们在不同的库中使用。
对于A的情况,你可以#include标题,不需要链接任何东西。因此,您可以在不使用任何特殊链接的情况下使用来自不同应用程序/库的此类。
对于B的情况,你需要B.cpp,这应该只编译成一个库/应用程序。需要使用此类的任何其他库或应用程序都需要链接到包含代码实际主体的库。
对于某些设置/实现,您需要将类专门标记为库之间的“导出”或“导入”(例如,使用Windows,您可以使用dllimport / dllexport,使用GNU,您可以使用属性(visibility =“default”))
答案 2 :(得分:2)
第一个是隐式inline
,即建议编译器在呼叫站点扩展它。
答案 3 :(得分:1)
除了内联之外,你可以在class B
的定义和函数定义之间加入更多定义。
例如,B.cpp
可能包含B.hpp
没有的头文件,这可能会对大型项目的构建过程产生重大影响。
但即使没有单独的翻译单元,您偶尔也可以通过分离定义来解决循环依赖关系。例如,函数可能采用在定义B之前向前声明的类型的参数,然后由定义函数的时间定义。如果该类型在其自己的定义中使用B的定义,则不能仅在B之前定义。