2010-05-14 64 views
10

在我的C++项目中,何时必须使用头文件的包含(#include "myclass.h")?何时必须使用班级的前向申报(class CMyClass;)?头文件包含/前向声明

+1

见http://stackoverflow.com/questions/553682/when-to-use-forward-declaration – ChrisN 2010-05-14 08:26:53

回答

16

通常首先尝试前向声明。这将减少编译时间等。如果不编译去#include。如果您需要执行以下任何操作,您必须去#include:

  1. 访问类的成员或函数。
  2. 使用指针算术。
  3. 使用sizeof。
  4. 任何RTTI信息。
  5. new/delete,复制等
  6. 按值使用它。
  7. 继承它。
  8. 成为会员。
  9. 实例中的功能。

(6,7,8,9-从@Mooing鸭)

他们很可能更多,但我没有得到今天我的语言法的帽子。

+4

你还需要将之列入按价值使用它。所以如果你从它继承,把它作为一个成员,或者在一个函数中有一个实例。 – 2012-01-13 19:08:34

10

如果你只需要一个指针类,你不需要对任何类的知识,而不是它的名字,你可以使用向前声明。

2

作为初学者,当你需要使用它们包含的类型或函数时,你应该总是#include头文件 - 不要试图通过向前声明东西来“优化”你的构建 - 即使在大型项目,只要项目设计良好。

唯一的一次,你绝对需要预先声明是这样的情况:

struct A { 
    void f(B b); 
}; 

struct B { 
    void f(A a); 
}; 

每个结构(或类)是指其他的类型。在这种情况下,你需要B的前向声明来解决问题:

struct B; // forward declaration 

struct A { 
    void f(B b); 
}; 

struct B { 
    void f(A a); 
}; 
+0

对具有一个大的“forward_declarations.h”文件的大型项目进行维护可能是一场噩梦,因为它经常混淆开发工具,并且很难浏览不熟悉的代码库。尽管减少代码中的耦合有时很重要,但不要自动将每个类都放入一个前向dec文件中。 – bd2357 2016-02-09 16:27:49

2

你应该努力朝这既是为了减少编译时间也与模块化和可测试性,以帮助减少你的#include秒。正如@ypnos所说,当你只需要指针时,类转发就非常出色。

有关如何减少头部依赖一些实用的技巧,例如见this article

11

有几个问题转发声明:

  • 这就像在多个地方存储你的类名 - 如果你改变它在一个地方,你现在必须改变它在其他地方。重构成为一个挑战,因为代码仍然可以用更改的类名正确编译,但由于前向声明指向未定义的类,因此链接将失败。如果包含头文件并且不使用前向声明,则在编译期间会捕获这些问题。
  • 前向声明很难让其他人维护。举例来说,如果一个头文件包含:

    include "MyProject/MyWidgets/MyFooWidgets/FooUtil/Foo.h" 
    

    ,而不是向前声明

    class Foo ; 
    

    很容易让别人找到类Foo声明那里。有了前瞻性声明,这不是 明显;当用户试图打开 变量的声明时,Eclipse等一些IDE可能会打开前向声明。

  • 当您在包含前向声明的代码中包含头文件但实际代码定义位于您未链接的某个其他库中时,链接可能会因未定义的符号错误而失败。在编译时遇到这个问题比如"Could not find file MyProject/MyWidgets/MyFooWidgets/FooUtil/Foo.h"这样的错误更方便,因为那样您就会知道在哪里查找相应的Foo.cpp并确定包含它的库。

如果您认为您的构建时间过长,则尝试仅在没有链接的情况下进行编译。如果你的代码需要10秒的时间来编译,10分钟的时间来链接,这个问题与一些额外的包含无关。同样,如果你的头文件包含很多东西,它实际上会导致性能问题,那么你可能需要将该文件的内容重构为多个较小的头文件。

那么什么时候可以转发声明?如果你在真正的声明中使用相同的头文件。

例子:

class Foo ; 

typedef Foo* FooPtr ; 
typedef Foo& FooRef ; 

class Foo 
{ 
    public: 
     Foo() ; 
     ~Foo() ; 
} 

OR

class TreeNode ; 

class Tree 
{ 
private: 
    TreeNode m_root ; 
} 

class TreeNode 
{ 
    void* m_data ; 
} ; 
+1

我同意@David列出的前向声明问题。但我不同意这个结论:“那么什么时候可以转发声明呢?如果你在与真实声明相同的头文件中进行声明。”正如其他人所指出的,前向声明是分离物理布局并加快构建的重要工具。 //越来越多我不知道我们是否应该#include“Foo.hf” - .hf为“除正向声明外不包含任何内容的头文件”。 //当然,我会自动生成。 – 2012-10-15 22:06:29