我知道按定义,内联成员函数应该进入标题。但是如果不能将函数的实现放入标题呢?让我们来看看这种情况:
档案A.h
#pragma once
#include "B.h"
class A{
B b;
};
文件B.h
#pragma once
class A; //forward declaration
class B{
inline A getA();
};
由于循环包含,我必须将getA
的实现放入
B.cpp
#include "B.h"
#include "A.h"
inline A B::getA(){
return A();
}
编译器会内联getA
吗?如果是这样,哪个内联关键字是重要的(标题中的那个或.cpp文件中的那个)?是否有另一种方法将内联成员函数的定义放入其.cpp文件中?
答案 0 :(得分:64)
引自C++ FAQ:
注意:这是必要的 函数的定义(部分 在{...}之间放置一个 头文件,除非函数是 仅在单个.cpp文件中使用。在 特别是,如果你把内联 函数的定义为.cpp文件 你从其他一些.cpp调用它 文件,你会得到一个“未解决的 来自链接器的外部“错误。
只要发现任何内联函数的使用,编译器就需要查看内联函数的定义。如果将内联函数放在头文件中,这通常是可能的。
编译器是否内联getA?
不,除非使用getA()
在B.cpp本身。
如果是这样,哪个内联关键字是重要关键字(标题中的那个或cpp中的那个)?
Best practice:仅在类体外的定义中。
是否有另一种方法可以将内联成员函数的定义放入其cpp文件中?
不,至少我不知道。
答案 1 :(得分:16)
它不能超出B.cpp的范围。编译器在每个编译单元的基础上运行,即它单独编译每个.cpp文件,因此如果它编译C.cpp,它将没有getA()的代码可用,并且需要执行函数调用和让链接器修复它(或者,如果它真的把你带走了并尝试内联,它最终会出现链接器错误。inline
具有与static
类似的特性。)
唯一的例外是LTCG,即链接时代码生成,可在较新的编译器上使用。
在这种情况下,一种方法是使用包含内联代码的另一个头文件(有时命名为* .inl文件)。
编辑:至于哪个内联是相关的 - 它是类定义中的那个,即在头文件中。请记住,许多编译器对可以和应该内联的内容有自己的想法。例如,gcc可以完全禁用内联(-O0),或者它可以内联任何它认为值得内联的内容(如-O3)。
答案 2 :(得分:9)
我会从相反的方向来解决这个问题。
不要在函数中添加内联声明(除非你也需要)。
您需要将内联声明添加到函数/方法的唯一时间是在头文件中定义函数但在类声明之外。
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.
// Never declare anything inline in the cpp file.
int X::getZ() { return 6; }
更具体的案例。
删除所有内联规范。他们没有做你认为他们正在做的事情。
答案 3 :(得分:7)
现在,大多数编译器都可以在链接时执行内联,以及编译时。如果您的函数可能会受益于内联,那么链接时优化器很可能就是这样做的。
当链接器到达它时,编译器输出的内联状态并不多,除了编译器将某些对象标记为可收集,例如因为内联函数或类模板实例出现在多个编译中单位,或者当多个符号共享一个名称时应该引发错误,例如两次定义的主函数。这些都不会影响它将生成的实际代码。
答案 4 :(得分:0)
这是我做的方式。
档案A.h
#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。
然而,正如你们许多人所解释的那样,这并不是真的有用。
答案 5 :(得分:0)
ISO / IEC 14882:2014
每个程序都应包含每个非内联的一个定义 在该程序中使用的函数或变量;没有诊断 需要。定义可以在程序中明确显示,也可以 可以在标准库或用户定义的库中找到,或者(在 适当的)它被隐含地定义(见12.1,12.4和 12.8)。内联函数应在每个使用它的翻译单元中定义。