何时包含不需要?

时间:2011-07-12 04:41:06

标签: 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;
// ...

有人可以向我解释为什么B和C不需要包含Helper吗?此外,组织的优点/缺点包括这种方式? (除了显而易见的打字之外。)

感谢。

4 个答案:

答案 0 :(得分:5)

#include某个标头(或其他)文件放入.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 ++中看到这一点,它只显示预处理的文件。

在您目前的问题环境中,您必须在#include之前/之前helper.h B.h和之前出现的C.h并声明这些类型的对象。< / p>

此外,依靠头文件的排列来使代码工作是不好的做法,因为一旦你改变排列很少,整个层次结构就会崩溃并出现几个编译错误。

如果你正在使用它,那么#include文件中的所有内容,你可以使用#ifndef警卫来避免多次包含:

//helper.h
#ifndef HELPER_H
#define HELPER_H

// content of helper file

#endif

答案 1 :(得分:2)

如果BC的类定义实际上没有引用Helper类的任何成员,那么编译器不需要查看完整定义其头文件中的Helper类。 <{1}}类的前向声明就足够了。

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

Helper

如果class Helper; class B { // <SNIP> Helper* helper; // <SNIP> void help(const Helper& helper); // <SNIP> }; 类的定义使用B类的实例(即,它需要知道Helper实例的大小),或者以其他方式引用定义对于Helper类(在模板函数中),那么你需要使Helper类的完整定义可见(最有可能包括定义的头文件) Helper类):

Helper

何时使用包括与前向声明的规则相对简单:尽可能使用前向声明,并且包括必须的时间。

这样做的好处很明显:你拥有的内容越少,头文件之间的依赖性就越少(你的编译速度就越快)。

答案 2 :(得分:1)

将#include视为字面上包含此文件中另一个文件的文本 - 它与您复制它的方式完全相同。所以在这种情况下,B和C不需要包含Helper的原因是因为你已经将它包含在同一个“编译单元”中,这就是调用.cpp文件及其所有包含的组合。

答案 3 :(得分:0)

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

例如,boost::shared_ptr<T>实现仅向前声明boost::weak_ptr<T>,即使它在两个构造函数中使用。以下是从http://www.boost.org/doc/libs/1_47_0/boost/smart_ptr/shared_ptr.hpp剪切的代码:

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

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