注意这不是关于如何使用内联函数或它们如何工作的问题,更多的是为什么它们以它们的方式完成。
类成员函数的声明不需要将函数定义为inline
,它只是函数的实际实现。例如在头文件中:
struct foo{
void bar(); // no need to define this as inline
}
那么为什么类函数的内联实现必须在头文件中呢?为什么我不能将内联函数放在 .cpp
文件中?如果我尝试将内联定义放在 .cpp
文件中,我会收到如下错误:
error LNK2019: unresolved external symbol
"public: void __thiscall foo::bar(void)"
(?bar@foo@@QAEXXZ) referenced in function _main
1>C:\Users\Me\Documents\Visual Studio 2012\Projects\inline\Debug\inline.exe
: fatal error LNK1120: 1 unresolved externals
inline
出现在定义中而不是先前声明与 反之亦然的情况。如果是这样,这可能会有所帮助:stackoverflow.com/questions/4924912/…
inline
函数的定义不必在头文件中,但由于内联函数的一个定义规则 (ODR),必须存在一个相同的函数定义在每个使用它的翻译单元中。
实现这一点的最简单方法是将定义放在头文件中。
如果要将函数的定义放在单个源文件中,则不应声明它 inline
。未声明的函数 inline
并不意味着编译器不能内联该函数。
您是否应该声明一个函数 inline
通常是您应该根据哪个版本的定义规则对您来说最有意义的选择;添加 inline
然后受到后续约束的限制几乎没有意义。
有两种查看方式:
内联函数在头文件中定义,因为为了内联函数调用,编译器必须能够看到函数体。对于一个简单的编译器来说,函数体必须与调用在同一个翻译单元中。 (现代编译器可以跨翻译单元进行优化,因此即使函数定义在单独的翻译单元中,也可以内联函数调用,但这些优化代价高昂,并不总是启用,并且并不总是被头文件中定义的函数必须标记为内联,否则,包含头文件的每个翻译单元都将包含函数的定义,并且链接器将抱怨多个定义(违反单一定义规则)。 inline 关键字抑制了这一点,允许多个翻译单元包含(相同的)定义。
这两种解释实际上归结为 inline
关键字并不完全符合您的预期。
只要不改变程序的可观察行为,C++ 编译器可以随时自由地应用内联优化(用被调用函数的主体替换函数调用,节省调用开销)。
inline
关键字通过允许函数定义在多个翻译单元中可见,使编译器更容易应用此优化,但使用关键字并不意味着编译器具有 来内联函数,而 not 使用关键字并不禁止编译器内联函数。
这是 C++ 编译器的限制。如果你把函数放在头文件中,所有可以内联的cpp文件都可以看到你的函数的“源代码”,并且内联可以由编译器完成。否则内联必须由链接器完成(每个 cpp 文件分别编译在一个 obj 文件中)。问题是在链接器中执行此操作要困难得多。 “模板”类/函数也存在类似问题。它们需要由编译器实例化,因为链接器在实例化(创建专用版本)它们时会遇到问题。一些较新的编译器/链接器可以执行“两遍”编译/链接,其中编译器执行第一遍,然后链接器完成其工作并调用编译器来解决未解决的问题(内联/模板......)
c++ inline
关键字具有误导性,它并不意味着“内联此函数”。如果一个函数被定义为内联,它仅仅意味着它可以被定义多次,只要所有定义都相等。标记为 inline
的函数是一个被调用的真实函数,而不是在调用它的地方内联代码,这是完全合法的。
模板需要在头文件中定义一个函数,因为模板类并不是真正的类,它是一个类的模板,您可以对其进行多种变体。为了让编译器能够在您使用 Foo 模板创建 Foo 类时生成例如 Foo<int>::bar()
函数,Foo<T>::bar()
的实际定义必须是可见的。
inline
就被内联(也不声明它{1 } 保证它不会被内联)。
原因是编译器必须实际查看定义才能将其放置在调用的位置。
请记住,C 和 C++ 使用非常简单的编译模型,编译器一次只能看到一个翻译单元。 (导出失败,这是只有一个供应商实际实施它的主要原因。)
我知道这是一个旧线程,但我认为我应该提到 extern
关键字。我最近遇到了这个问题并解决如下
助手.h
namespace DX
{
extern inline void ThrowIfFailed(HRESULT hr);
}
助手.cpp
namespace DX
{
inline void ThrowIfFailed(HRESULT hr)
{
if (FAILED(hr))
{
std::stringstream ss;
ss << "#" << hr;
throw std::exception(ss.str().c_str());
}
}
}
因为编译器需要查看它们才能内联它们。头文件是通常包含在其他翻译单元中的“组件”。
#include "file.h"
// Ok, now me (the compiler) can see the definition of that inline function.
// So I'm able to replace calls for the actual implementation.
内联函数
在 C++ 中,宏只不过是内联函数。所以现在宏在编译器的控制之下。
重要提示:如果我们在类中定义一个函数,它将自动变为内联
内联函数的代码在被调用的地方被替换,减少了调用函数的开销。
在某些情况下,函数的内联不起作用,例如
如果在内联函数中使用静态变量。
如果功能复杂。
如果递归调用函数
如果函数的地址被隐式或显式地采用
如下在类外定义的函数可能会变成内联函数
inline int AddTwoVar(int x,int y); //This may not become inline
inline int AddTwoVar(int x,int y) { return x + y; } // This becomes inline
类内定义的函数也变为内联
// Inline SpeedMeter functions
class SpeedMeter
{
int speed;
public:
int getSpeed() const { return speed; }
void setSpeed(int varSpeed) { speed = varSpeed; }
};
int main()
{
SpeedMeter objSM;
objSM.setSpeed(80);
int speedValue = A.getSpeed();
}
这里 getSpeed 和 setSpeed 函数都将变成内联函数
不定期副业成功案例分享
+1
!