头文件包含/前向声明

发布于 2024-09-01 16:26:59 字数 115 浏览 11 评论 0原文

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

In my C++ project when do I have to use inclusion (#include "myclass.h") of header files? And when do I have to use forward declaration of the class (class CMyClass;)?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(5

惟欲睡 2024-09-08 16:26:59

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

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

(来自 @Mooing Duck 的 6,7,8,9)

它们可能更多,但我今天还没有戴上语言法帽子。

As a rule try the forward declaration first. This will reduce compile times etc. If that doesn't compile go for the #include. You have to go for the #include if you need to do any of the following:

  1. Access a member or function of the class.
  2. Use pointer arithmetic.
  3. Use sizeof.
  4. Any RTTI information.
  5. new/delete, copy etc.
  6. Use it by value.
  7. Inherit from it.
  8. Have it as a member.
  9. Instance in a function.

(6,7,8,9 from @Mooing Duck)

They're are probably more but I haven't got my language law hat on today.

风筝有风,海豚有海 2024-09-08 16:26:59

转发声明有几个问题:

  • 这就像将类名存储在多个位置 - 如果您在一个位置更改它,那么您现在必须在其他地方更改它。重构成为一个挑战,因为代码仍然可以使用更改后的类名正常编译,但由于前向声明引用未定义的类,链接将失败。如果包含头文件并且不使用前向声明,您将在编译过程中发现这些问题。
  • 前向声明对其他人来说很难维护。例如,如果头文件包含:

    包含“MyProject/MyWidgets/MyFooWidgets/FooUtil/Foo.h”
    

    而不是前向声明

     类 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( ) ;
}

class TreeNode ;

class Tree
{
private:
   TreeNode m_root ;
}

class TreeNode
{
   void* m_data ;
} ;

There are several problems to forward declaration:

  • It is like storing your class name in multiple places -- if you change it in one place, you now have to change it everywhere else. Refactoring becomes a challenge since the code will still compile fine with the changed class name, but linking will fail since the forward declarations refer to an undefined class. If you include the header file and do not use forward declarations, you will catch these problems during compilation.
  • Forward declarations are difficult for others to maintain. For instance, if a header file contains:

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

    rather than the forward declaration

     class Foo ;  
    

    it is easy for others to find where the class Foo is declared. With forward declaration, it is not that
    obvious; some IDEs like Eclipse may open the forward declaration when the user tries to open
    the declaration of a variable.

  • Linking can fail with undefined symbol errors when you include a header file in your code that contains a forward declaration but the actual code definition is located in some other library that you did not link with. It's more convenient to catch this problem at compile time with errors like "Could not find file MyProject/MyWidgets/MyFooWidgets/FooUtil/Foo.h" since then you will know where to look for the corresponding Foo.cpp and identify the library that contains it.

If you think your build is taking too long, then try doing a compile only with no link. If your code takes 10 seconds to compile and 10 minutes to link, the problem has nothing to do with a few extra includes. Similarly, if your header file contains so much stuff in it that it is actually causing a performance problem then it is probably time for you to refactor the content of that file into multiple smaller header files.

So when is it OK to forward declare? If you do it in the same header file as the real declaration.

Example:

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 ;
} ;
妄断弥空 2024-09-08 16:26:59

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

If you only need a pointer to the class and you don't need any knowledge about the class rather than its name, you can use the forward declaration.

残龙傲雪 2024-09-08 16:26:59

作为初学者,当您需要使用它们包含的类型或函数时,您应该始终 #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 );
};

As a beginner, you should always #include header files when you need to use the types or functions they contain - do not try to "optimise" your build by forward declaring things - this is hardly ever necessary, even on large projects, provided the project is well architected.

The only time you absolutely need a forward declaration is in situations like this:

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

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

where each struct (or class) refers to the type of the other. In this case, you need a forward declaration of B to resolve the issue:

struct B;   // forward declaration

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

struct B {
   void f( A a );
};
女中豪杰 2024-09-08 16:26:59

您应该努力尽量减少 #include,这不仅是为了减少编译时间,也是为了帮助实现模块化和可测试性。正如 @ypnos 所说,当您只需要指针时,类转发非常出色。

有关如何减少标头依赖性的一些实用技巧,请参阅本文

You should strive towards minimizing your #includes both in order to reduce compilation times but also to help with modularity and testability. As @ypnos says, class forwards are excellent when you only need pointers.

For some practical tips on how to reduce header dependencies, see e.g. this article.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文