C++ 什么时候不需要包含?

C++ 什么时候不需要包含?,c++,include,C++,Include,我承认我有点天真,当涉及到包括。我的理解是,如果您在类中使用它,您需要包含它或向前声明它。但后来我通过一些代码看到了: // file: A.cpp #include "Helper.h" #include "B.h" #include "C.h" #include "A.h" // ... // file: A.h B b; C c; // ... // file: B.h Helper h; // ... // file: C.h Helper h; // ... 有人能给我解释一下

我承认我有点天真,当涉及到包括。我的理解是,如果您在类中使用它,您需要包含它或向前声明它。但后来我通过一些代码看到了:

// file: A.cpp
#include "Helper.h"
#include "B.h"
#include "C.h"
#include "A.h"
// ...

// file: A.h
B b;
C c;
// ...

// file: B.h
Helper h;
// ...

// file: C.h
Helper h;
// ...
有人能给我解释一下为什么B和C不需要包含Helper吗?此外,以这种方式组织有哪些优点/缺点?(除了明显的少打字之外。)

谢谢

把#include想象成将另一个文件的文本包含在这一个文件中——它与您在其中复制的文本完全相同。因此,在本例中,B和C不需要包含Helper的原因是因为您将它包含在同一个“编译单元”中,这就是.cpp文件及其所有包含项的组合所调用的。

当您将某个头文件(或其他)包含到
.cpp
文件中时,
#include
语句只需替换为头文件的内容。例如:

//header.h
int i;
float f;

// file.cpp
#include"header.h"
int main()
{}
在预处理阶段之后,file.cpp将如下所示:

int i;
float f;

int main()
{}
可以使用
g++-E file.cpp>TEMP
在g++中看到这一点,它只显示预处理的文件

在您当前的问题上下文中,您必须在
B.h
C.h
之前/之前包含
helper.h
,并声明这些类型的对象

此外,依靠头文件的排列来让代码正常工作也不是一个好的做法,因为一旦稍微改变排列方式,整个层次结构就会崩溃,并出现几个编译错误

相反,如果您正在使用文件,请在文件中包含所有内容,并且可以使用
#ifndef
防护装置来避免多次包含:

//helper.h
#ifndef HELPER_H
#define HELPER_H

// content of helper file

#endif

如果
B
C
的类定义实际上没有引用
Helper
类的任何成员,那么编译器不需要在其头文件中查看
Helper
类的完整定义。
Helper
类的转发声明就足够了

例如,如果
B
类的定义仅使用指向
Helper
的指针或引用,则建议使用正向引用

class Helper;

class B {
    // <SNIP>
    Helper* helper;
    // <SNIP>
    void help(const Helper& helper);
    // <SNIP>
};
何时使用include和forward声明的规则相对简单:在可以的时候使用forward声明,在必须的时候使用include


这样做的好处很明显:包含越少,头文件之间的依赖关系就越少(编译速度就越快)。

对于模板,即使头文件中引用了前向声明类型的成员,前向声明也可能足够了

例如,
boost::shared\u ptr
实现仅向前声明
boost::weak\u ptr
,即使它在两个构造函数中使用。以下是从中截取的代码:

namespace boost
{
// ...
模板类弱ptr;
// ...
模板类共享\u ptr
{
// ...
公众:
// ...
模板
显式共享\u ptr(弱\u ptr const&r):pn(r.pn)//可能抛出
{
//现在可以安全地复制r.px,因为pn(r.pn)没有抛出
px=r.px;
}
模板
共享_ptr(弱_ptr const&r,boost::detail::sp_nothrow_标记):px(0),pn(r.pn,boost::detail::sp_nothrow_标记())//从不抛出
{
如果(!pn.empty())
{
px=r.px;
}
}

在这种情况下,向前声明
boost::weak_ptr
就足够了,因为除非向前声明的
boost::weak_ptr
的定义包含在使用这些构造函数的编译单元中,否则这两个构造函数不会被实例化。

这是错误的,您从哪里看到的?如果这些确实是在您显示给我们的文件的顶部,那么至少B.h需要包含定义Helper的文件,该文件可能是Helper,也可能不是Helper。h@Benjamin林德利,谢谢。你说得对,助手。h在B.h和C.h之前就已经包括在内了。它们不需要只是在同一个翻译单元中,它们需要顺序正确。在这种情况下,它们实际上是n谢谢你的回答。你对这种做法的警告是很好的。这就是我第一次发现的原因:我做了一个改变,然后得到了一长串编译错误。
#include "helper.h"

class B {
    // <SNIP>
    Helper helper;
    // <SNIP>
    void help(Helper helper);
    // <SNIP>
};
namespace boost
{
// ...
template<class T> class weak_ptr;
// ...
template<class T> class shared_ptr
{
// ...
public:
// ...
    template<class Y>
    explicit shared_ptr(weak_ptr<Y> const & r): pn(r.pn) // may throw
    {
        // it is now safe to copy r.px, as pn(r.pn) did not throw
        px = r.px;
    }

    template<class Y>
    shared_ptr( weak_ptr<Y> const & r, boost::detail::sp_nothrow_tag ): px( 0 ), pn( r.pn, boost::detail::sp_nothrow_tag() ) // never throws
    {
        if( !pn.empty() )
        {
            px = r.px;
        }
    }