前置声明的目的是什么?

发布于 2024-09-06 13:28:33 字数 104 浏览 8 评论 0原文

例如,在下面的示例中,通过在定义类之前声明该类可以获得什么额外的好处?

class test;

class test
{
  .....
};

In the following example, for instance, what additional benefit could be gained by declaring the class before defining it?

class test;

class test
{
  .....
};

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

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

发布评论

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

评论(6

¢好甜 2024-09-13 13:28:33

C++(与 C 一样)被设计为可由单遍编译器实现。如果编译器需要在实际定义类之前知道符号引用该类,则需要前向引用。典型的例子是两个类需要包含指向彼此的指针。即,

class B;

class A {
  B* b;
};

class B {
  A* a;
};

如果没有对 B 的前向引用,编译器将无法成功解析 A 的定义,并且您无法通过将 B 的定义放在 A 之前来解决问题。

在像 C# 这样需要两遍编译器的语言中,您不需要前向引用,

class A {
  B b;
}

class B {
  A a;
}

因为编译器的第一遍只是简单地获取所有符号定义。当编译器进行第二遍时,它可以说“我知道 B 是一个类,因为我在第一遍中看到了定义”。

C++ (like C) was designed to be implementable by a single-pass compiler. Forward references are necessary in cases where the compiler needs to know that a symbol refers to a class before the class is actually defined. The classic example of this is when two classes need to contain pointers to each other. i.e.

class B;

class A {
  B* b;
};

class B {
  A* a;
};

Without the forward reference to B, the compiler could not successfully parse the definition for A and you can't fix the problem by putting the definition of B before A.

In a language like C#, which needs a two-pass compiler, you don't need forward references

class A {
  B b;
}

class B {
  A a;
}

because the compiler's first pass simply picks up all symbol definitions. When the compiler makes its second pass, it can say "I know B is a class because I saw the definition on my first pass".

轮廓§ 2024-09-13 13:28:33

如果访问该类的成员/方法或者需要知道其大小,则编译器需要该类的定义。在其他情况下,前向声明就足够了。这可以节省您的编译时间。
示例:

class A { 
  B m_b; 
  C* m_ptrC;
}; 

对于此类,您需要 B 的定义(需要大小)并且仅需要 C 的声明(指针具有固定大小)。您只需要包含 B 的标头,而不是 C 的标头。C 的前向声明就足够了。

ah:

#ifndef A_H
#define A_H

#include <b.h>
class C;

class A
{
  B m_b;
  C* m_ptrC;
}
#endif

c 的前向声明(而不是包含 ch,这也是可能的)可以节省您在包含 ah 时解析 ch 的时间。跨大型项目,这可能会节省大量编译时间。
另一个好处是,在这种情况下,ch 中的更改不会触发 a 的重新编译。我不知道如果您包含 ch 而不是向前声明它,编译器是否会识别这一点。

要了解更多信息,请尝试了解 pimpl-idiom(只需 google 即可。您会得到很多结果)。

当然 - 在 a.cpp 中,如果您实际上使用指向 c 的指针执行某些操作(例如 m_ptrC->Add()),则需要包含 ch 但 a.cpp 仅在读取头文件的地方读取一次 n对于大型项目中经常使用的类,使用大 n 的次数。

前向声明还允许循环依赖。
示例:

class B;

class A {
 B* m_ptrB;
}

class B {
 A* m_ptrA;
}

请记住 - 您不能使用任何有关尺寸和尺寸的信息。方法(如果您使用前向声明)。两个类相互包含时也是这种情况(但其中一个类不需要前向引用)。我个人认为循环引用是不好的风格,如果可能的话应该避免它们。

有关更多信息:C++ 常见问题解答

感谢您对循环依赖项的评论,我只是忘记了它们。

The compiler needs the definition of a class if member/methods of that class are accessed or if the size needs to be known. In other cases, a forward declaration is sufficient. This saves you compile time.
Example:

class A { 
  B m_b; 
  C* m_ptrC;
}; 

For this class, you need the definition of B (size needed) and only the declaration of C (pointers have fixed size). You only need to include the header of B, not the one of C. A forward declaration of C is sufficient.

a.h:

#ifndef A_H
#define A_H

#include <b.h>
class C;

class A
{
  B m_b;
  C* m_ptrC;
}
#endif

The forward declaration of c (instead of including c.h which is also possible) saves you parsing c.h whenever you include a.h. Across a large project, this may save a lot of compile time.
Another benefit is, that changes in c.h do not trigger a recompile for a in this case. I do not know if compiler recognize this if you include c.h instead of forward declaring it.

For more information, try understanding the pimpl-idiom (just google for it. you'll get lots of hits).

Of course - in a.cpp if you actually do something with the pointer to c (e.g. m_ptrC->Add()), you'll need to include c.h. But a.cpp is read only once where the header file is read n times with large n for classes that are used very often in large projects.

Forward declaration also allows for circular dependencies.
Example:

class B;

class A {
 B* m_ptrB;
}

class B {
 A* m_ptrA;
}

Just remember - you can't use any information about size & methods if you use forward declarations. This is also the case with 2 classes including each other (one class does not need the forward reference though). I personally think circular references are bad style and you should avoid them if possible.

For additional information: C++ FAQ

Thank you for the comment about the circular dependencies, I simply forgot them.

猫腻 2024-09-13 13:28:33

首先,声明该类,然后定义该类。

声明:它只是告诉编译器:好的,这里有一些东西(方法,类等),可以通过给定的名称使用。它只是将给定名称绑定到某些东西。

定义:它告诉编译器:好的,这是方法、类等实际执行的操作(以及如何执行)。如果定义了某些内容,则会导致编译器实际为其分配空间。

您可以查看此处

First, the class is declared, then it is defined.

Declaration: It just tells the compiler: Ok, here's something (method, class, etc.), that can be used by the given name. It just binds the given name to something.

Definition: It tells the compiler: Ok, here's what (and how) the methods, classes, etc. actually do their stuff. If something is defined, then the compiler is caused to actually allocate space for it.

You might have a look at here.

八巷 2024-09-13 13:28:33

第一行是所谓的前向声明。它将类的名称带入当前名称空间,而不实际定义它。

The first line is what's called a forward declaration. It brings the name of the class into the current namespace without actually defining it.

明媚殇 2024-09-13 13:28:33

嗯,问题不是很清楚。
但是,提供的代码声明了一个类 test 并在下面定义了它,省略了实际的成员 (...)。

Ehm, the question is not very clear.
However, the code supplied declares a class test and defines it below, omitting the actual members (...).

平安喜乐 2024-09-13 13:28:33

简单的答案是,当您使用第一种形式时,您可以保存对类的指针或引用,而不需要完整的实现。当两个类紧密交互并且它们的实现或定义难以分离时,这非常有用。

The simple answer is that when you use the first form, you can then hold pointers or references to a class without needing the full implementation. This can be very useful for when two classes tightly interact and their implementations or definitions are hard to separate.

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