繁体   English   中英

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

[英]C++ inline member function in .cpp file

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

档案啊

#pragma once
#include "B.h"

class A{
    B b;
};

文件Bh

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

引用C ++ FAQ

注意:必须将函数的定义({...}之间的部分)放在头文件中,除非该函数仅在单个.cpp文件中使用。 特别是,如果将内联函数的定义放入.cpp文件中并从其他.cpp文件中调用它,则会从链接器中获得“未解析的外部”错误。

只要发现任何内联函数的使用,编译器就需要查看内联函数的定义 如果内联函数放在头文件中,这通常是可能的。

编译器内联getA吗?

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

如果是这样,哪个内联关键字是重要的关键字(标题中的那个或cpp中的那个)?

最佳实践 :仅限于类体外的定义。

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

不,至少我不知道。

它不能超出B.cpp的范围。 编译器在每个编译单元的基础上运行,即它单独编译每个.cpp文件,因此如果它编译C.cpp,它将没有getA()的代码可用,并且需要执行函数调用和让链接器修复它(或者,如果它真的把你带走了并尝试内联,它将最终出现链接器错误inline具有与static类似的特性)。

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

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

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

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

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

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

XH

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

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

目前,大多数编译器都可以在链接时执行内联,以及编译时。 如果您的函数可能会受益于内联,那么链接时优化器很可能就是这样做的。

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

这是我做的方式。

档案啊

#pragma once
#include "B.h"

class A {
    B b;
};

文件Bh

#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>();

文件Ch

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

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

只需包含“Ch”文件即可使用getA()方法。 原始代码的唯一变化是getA()方法必须定义为public而不是private。

但是,正如你们许多人所解释的那样,这并不是很有用。

ISO / IEC 14882:2014

每个程序应该只包含该程序中使用的每个非内联函数或变量的一个定义; 无需诊断。 该定义可以在程序中明确显示,可以在标准或用户定义的库中找到,或者(在适当的时候)隐式定义(见12.1,12.4和12.8)。 内联函数应在每个使用它的翻译单元中定义。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM