为什么必须在类外部(但在头文件中)定义类成员函数?

时间:2018-06-02 18:31:42

标签: c++ function inline header-files member

我已经阅读了内联的两个含义的现有answers,但我仍然感到困惑。

我们假设我们有以下头文件:

// myclass.h

#ifndef INCLUDED_MYCLASS
#define INCLUDED_MYCLASS

class MyClass
{
   public:
      void foo(); // declaration
};

inline void MyClass::foo()
{
    // definition
}

#endif

为什么在文件的类外定义的void foo()必须使用inline明确定义?

2 个答案:

答案 0 :(得分:4)

这是因为您在头文件中定义了MyClass::foo。或者更抽象一点,该定义将出现在多个翻译单元中(包含标题的每个.cpp文件)。

在程序中有一个以上的变量/函数定义违反了一个定义规则,该规则要求每个变量/函数的单个程序中只能有一个定义。

请注意,标题保护不会对此进行保护,因为只有在同一文件中多次包含相同的标题时,它们才会受到保护。

将函数定义标记为inline,但意味着定义在多个翻译单元中始终相同。 1

实际上,这意味着链接器将只使用MyClass::foo的第一个定义并在任何地方使用它,而忽略其余部分,

1 :如果情况并非如此,那么您的程序就会形成错误,无需任何诊断。

答案 1 :(得分:3)

如果将MyClass::foo()放在头文件中并且未能将其声明为inline,则编译器将为#include标题的每个编译单元生成一个函数体,这些将发生冲突在链接时。链接器抛出的常见错误是Multiple definition of symbol MyClass::foo()或类似的行。声明函数inline可以避免这种情况,并且编译器和链接器必须对它有所了解。

正如您在评论中提到的那样,inline关键字也会对编译器执行提示,您希望函数实际内联,因为(大概)您称之为通常并且更关心速度而不是代码大小。编译器不需要遵守此请求,因此它可能会生成一个或多个函数体(在不同的编译单元中),这就是链接器必须知道它们实际上都是相同的并且它只需要保留其中一个的原因。他们(任何人都会这样做)。如果它不知道它们都是一样的那么它就不会知道该做什么,这就是为什么“经典”行为总是会引起错误。

鉴于目前编译器经常内联小函数,大多数编译器也有某种noinline关键字,但这不是标准的一部分。

有关cppreferenceinline的更多信息。