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

时间:2010-10-22 00:10:55

标签: c++ function inline member

我知道按定义,内联成员函数应该进入标题。但是如果不能将函数的实现放入标题呢?让我们来看看这种情况:

档案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文件中?

6 个答案:

答案 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)

我会从相反的方向来解决这个问题。

不要在函数中添加内联声明(除非你也需要)。

您需要将内联声明添加到函数/方法的唯一时间是在头文件中定义函数但在类声明之外。

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; }

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

答案 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)。内联函数应在每个使用它的翻译单元中定义。