头文件包含/转发声明

时间:2010-05-14 08:16:09

标签: c++ header-files forward-declaration

在我的C ++项目中何时必须使用头文件的包含(#include "myclass.h")?我什么时候必须使用类的前向声明(class CMyClass;)?

5 个答案:

答案 0 :(得分:20)

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

  1. 访问班级的成员或职能。
  2. 使用指针算法。
  3. 使用sizeof。
  4. 任何RTTI信息。
  5. new / delete,复制等。
  6. 按值使用。
  7. 继承它。
  8. 让它成为会员。
  9. 功能中的实例。
  10. (来自@Mooing Duck的6,7,8,9)

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

答案 1 :(得分:11)

如果您只需要指向该类的指针,并且您不需要任何有关该类的知识而不需要其名称,则可以使用前向声明。

答案 2 :(得分:11)

转发声明有几个问题:

  • 就像在多个地方存储您的班级名称一样 - 如果您在一个地方更改它,您现在必须在其他地方更改它。重构成为一个挑战,因为代码仍然可以使用更改的类名进行编译,但链接将失败,因为前向声明引用了未定义的类。如果包含头文件但不使用前向声明,则在编译期间将捕获这些问题。
  • 其他人难以维持前瞻声明。例如,如果头文件包含:

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

    而不是前向声明

     class Foo ;  
    

    其他人很容易找到声明类Foo的位置。有了前瞻性声明,它不是那样的 明显;某些IDE(如Eclipse)可能会在用户尝试打开时打开前向声明 声明变量。

  • 当您在包含转发声明的代码中包含头文件但实际代码定义位于您未链接的其他库中时,链接可能会因未定义的符号错误而失败。在编译时捕获此问题比使用"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 ;
} ;

答案 3 :(得分: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 );
};

答案 4 :(得分:2)

您应该努力最小化#include两者,以减少编译时间,同时也有助于模块化和可测试性。正如@ypnos所说,当你只需要指针时,前锋非常出色。

有关如何减少标头依赖关系的一些实用技巧,请参阅例如this article