Cpp 文件中的 C + + 内联成员函数

我知道根据定义,内联成员函数应该放在头部。但是,如果不可能将函数的实现放入标头中,该怎么办呢?让我们看看这个情况:

文件 A

#pragma once
#include "B.h"


class A{
B b;
};

文件 B.h

#pragma once


class A; //forward declaration


class B{
inline A getA();
};

由于通知的包含,我不得不把 getA的实现放进去

心肺复苏

#include "B.h"
#include "A.h"


inline A B::getA(){
return A();
}

编译器会内联 getA吗?如果是,那么哪个 inline 关键字是有意义的关键字(标题中的关键字或。Cpp 文件) ?是否有其他方法将内联成员函数的定义放入其。Cpp 文件?

77936 次浏览

不行,超出了 B.cpp 的范围。编译器基于每个编译单元进行操作,也就是说,它编译每个。Cpp 文件,所以如果它编译 C.cpp,它不会有 getA ()的代码可用,需要执行一个函数调用,并让链接器修复它(或者,如果它真的让你的单词和尝试内联,它将以一个链接器错误结束。inline具有与 static相似的特性。

唯一的例外是 LTCG,即链接时代码生成,它可以在较新的编译器上使用。

在这种情况下,一种方法是使用另一个包含内联代码的头文件(有时命名为 * . inl 文件)。

编辑: 至于哪个内联是相关的——它是类定义中的内联,也就是头文件中的内联。请记住,许多编译器对于什么可以内联、什么应该内联都有自己的想法。例如,gcc 可以完全禁用内联(- O0) ,或者它可以内联任何它认为值得内联的东西(比如-O3)。

引自 C + + 常见问题解答:

注意: 当务之急是 函数的定义 之间的{ ... })放置在一个 头文件,除非该函数是 仅在单个.cpp 文件中使用 特别是,如果你把内联 函数的定义放到一个.cpp 文件中 你可以从其他的.cpp 调用它 文件,你会得到一个“未解决的 来自链接器的“外部”错误。

每当编译器发现该内联函数的任何用途时,它都需要查看该内联函数的 定义。如果将内联函数放在头文件中,则通常可以做到这一点。

编译器内联是否会得到 A?

不,除非 getA()的使用是在 B.cpp 本身中。

如果是,哪个 inline 关键字是重要的关键字(标题中的关键字还是 cpp 中的关键字) ?

最佳实践 : 仅在类主体之外的定义中。

还有其他方法将内联成员函数的定义放入它的 cpp 文件中吗?

不,至少我不知道。

现在,大多数编译器可以在链接时执行内联,也可以在编译时执行内联。如果您的函数可能从内联中获益,那么 Link Time 优化器可能正是这样做的。

当链接器到达它的时候,编译器输出的内联状态已经不可用了,除了编译器将标记某些对象为可收集对象,例如,因为内联函数或类模板实例出现在多个编译单元中,或者当多个符号共享一个名称时,它应该引发一个错误,例如主函数被定义了两次。所有这些都不会影响它将生成的实际代码。

我会从相反的方向做这件事。

不要将内联声明添加到函数中(除非您也需要)。

唯一需要将内联声明添加到函数/方法的情况是在头文件中定义函数,但不在类声明中。

X.H

class X
{
public:
int getX()   { return 4;} // No inline because it is part of the class.
// The compiler knows that needs an inline tag
int getY();
int getZ();
};


inline
int X::getY()  { return 5;}       // This needs to be explicitly declared inline.
// Otherwise the linker will complain about
// multiple definitions in compilation units.

X.cpp

 // Never declare anything inline in the cpp file.


int X::getZ() { return 6; }

更具体的案子。
删除所有的内联规范。他们没有做你认为他们正在做的事情。

我是这么做的。

文件 A

#pragma once
#include "B.h"


class A {
B b;
};

文件 B.h

#pragma once


class B {
public:
template<class T> inline T getA() {
assert(NULL); // Use 'getA<A>()' template specialization only!
return NULL;
}
};


class A; // Forward declaration
template<> inline A B::getA<A>();

文件 C.h

#pragma once
#include "A.h"
#include "B.h"


// Implement template specialization here!
template<> inline A B::getA<A>() { return A(); }

只要包含“ C.h”文件就可以使用 getA ()方法。原始代码的唯一变化是 getA ()方法必须定义为 public 而不是 private。

然而,正如你们许多人解释的那样,这并不是真正有用的。