为什么 class 定义在 class 之外(但在头文件中)的成员函数必须内联?
Why do class member functions defined outside the class (but in header file) have to be inlined?
关于inline的两种含义,我已经阅读了现有的answers,但我仍然很困惑。
假设我们有以下头文件:
// myclass.h
#ifndef INCLUDED_MYCLASS
#define INCLUDED_MYCLASS
class MyClass
{
public:
void foo(); // declaration
};
inline void MyClass::foo()
{
// definition
}
#endif
为什么在文件中 class 之外定义的 void foo()
必须用 inline
显式定义?
这是因为您在 header 文件中定义了 MyClass::foo
。或者更抽象一点,该定义将出现在多个翻译单元中(每个包含 header 的 .cpp 文件)。
在一个程序中定义多个 variable/function 违反了一个定义规则,该规则要求每个 variable/function 在一个程序中只能有一个定义。
请注意,header 守卫不会对此提供保护,因为它们仅在您在同一文件中多次包含相同的 header 时提供保护。
将函数定义标记为 inline
虽然意味着该定义在多个翻译单元中始终相同。1.
实际上,这意味着链接器将只使用 MyClass::foo
的第一个定义并在所有地方使用它,而忽略其余部分
1:如果不是这种情况,则您的程序 ill-formed 不需要任何诊断。
如果你把MyClass::foo()
放在一个头文件中并且没有声明它inline
那么编译器会为每个编译单元生成一个函数体#include
头文件和这些将在 link 时间发生冲突。 linker 抛出的通常错误类似于 Multiple definition of symbol MyClass::foo()
或类似的错误。声明函数 inline
可以避免这种情况,并且编译器和 linker 必须在这方面合作。
正如您在评论中提到的那样,inline
关键字还向编译器发出 提示 ,表明您希望函数实际内联,因为 (大概)你经常调用它并且更关心速度而不是代码大小。编译器不需要接受这个请求,所以它可能会生成一个或多个函数体(在不同的编译单元中),这就是为什么 linker 必须知道它们实际上都是一样的,而且它只是需要保留其中之一(任何一个都可以)。如果它不知道它们都是一样的,那么它就不知道该怎么做,这就是为什么 'classical' 行为总是抛出错误。
鉴于现在的编译器经常内联小函数,大多数编译器也有某种 noinline
关键字,但这不是标准的一部分。
有关 inline
的更多信息,请访问 cppreference。
关于inline的两种含义,我已经阅读了现有的answers,但我仍然很困惑。
假设我们有以下头文件:
// myclass.h
#ifndef INCLUDED_MYCLASS
#define INCLUDED_MYCLASS
class MyClass
{
public:
void foo(); // declaration
};
inline void MyClass::foo()
{
// definition
}
#endif
为什么在文件中 class 之外定义的 void foo()
必须用 inline
显式定义?
这是因为您在 header 文件中定义了 MyClass::foo
。或者更抽象一点,该定义将出现在多个翻译单元中(每个包含 header 的 .cpp 文件)。
在一个程序中定义多个 variable/function 违反了一个定义规则,该规则要求每个 variable/function 在一个程序中只能有一个定义。
请注意,header 守卫不会对此提供保护,因为它们仅在您在同一文件中多次包含相同的 header 时提供保护。
将函数定义标记为 inline
虽然意味着该定义在多个翻译单元中始终相同。1.
实际上,这意味着链接器将只使用 MyClass::foo
的第一个定义并在所有地方使用它,而忽略其余部分
1:如果不是这种情况,则您的程序 ill-formed 不需要任何诊断。
如果你把MyClass::foo()
放在一个头文件中并且没有声明它inline
那么编译器会为每个编译单元生成一个函数体#include
头文件和这些将在 link 时间发生冲突。 linker 抛出的通常错误类似于 Multiple definition of symbol MyClass::foo()
或类似的错误。声明函数 inline
可以避免这种情况,并且编译器和 linker 必须在这方面合作。
正如您在评论中提到的那样,inline
关键字还向编译器发出 提示 ,表明您希望函数实际内联,因为 (大概)你经常调用它并且更关心速度而不是代码大小。编译器不需要接受这个请求,所以它可能会生成一个或多个函数体(在不同的编译单元中),这就是为什么 linker 必须知道它们实际上都是一样的,而且它只是需要保留其中之一(任何一个都可以)。如果它不知道它们都是一样的,那么它就不知道该怎么做,这就是为什么 'classical' 行为总是抛出错误。
鉴于现在的编译器经常内联小函数,大多数编译器也有某种 noinline
关键字,但这不是标准的一部分。
有关 inline
的更多信息,请访问 cppreference。