例如,在下面的示例中,通过在定义类之前声明类可以获得什么额外的好处?
class test; class test { ..... };
qq24tv8q1#
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是一个类,因为我在第一遍中看到了定义”。
0mkxixxg2#
如果要访问类的成员/方法,或者需要知道类的大小,编译器需要该类的定义。在其他情况下,前向声明就足够了。这可以节省编译时间。例如:
class A { B m_b; C* m_ptrC; };
对于这个类,你需要B的定义(需要大小)和C的声明(指针有固定大小)。你只需要包括B的头,而不是C的头。C的前向声明就足够了。答:
#ifndef A_H #define A_H #include <b.h> class C; class A { B m_b; C* m_ptrC; } #endif
c的前向声明(而不是包含c. h,这也是可能的)节省了每当你包含a. h时解析c. h的时间。在一个大的项目中,这可能会节省大量的编译时间。另一个好处是,在这种情况下,c. h中的变化不会触发a的重新编译。我不知道如果你包含c. h而不是前向声明它,编译器是否会识别出这一点。要了解更多信息,试着理解粉刺这个成语(只要谷歌一下,你会得到很多点击)。当然--在a.cpp中,如果你真的用指向c的指针做了一些事情(例如,m_ptrC-〉Add()),你需要包含c. h。但是a.cpp只读一次,头文件被读n次,对于大型项目中经常使用的类,n很大。正向声明也允许循环依赖。例如:
class B; class A { B* m_ptrB; } class B { A* m_ptrA; }
请记住-如果你使用前向声明,你不能使用任何关于size和方法的信息。这也是2个类互相包含的情况(一个类不需要前向引用)。我个人认为循环引用是不好的风格,如果可能的话,你应该避免它们。更多信息:C++常见问题解答谢谢你对循环依赖的评论,我只是忘记了它们。
r1wp621o3#
首先,类是 * 声明的 *,然后是 * 定义的 *。声明:它只是告诉编译器:好的,这里有一些东西(方法,类,等等),可以被给定的名字使用。它只是把给定的名字绑定到一些东西上。定义:它告诉编译器:好的,下面是方法、类等实际上做了什么(以及如何做)。如果定义了某个东西,那么编译器就会为它实际上分配空间。你可以看看here。
bmvo0sr54#
第一行是所谓的前向声明,它将类的名称带入当前命名空间,但实际上并没有定义它。
8zzbczxx5#
嗯,这个问题不是很清楚。但是,提供的代码声明了一个类test,并在下面定义了它,省略了实际的成员(...)。
test
mm5n2pyu6#
简单的答案是,当你使用第一种形式时,你可以保存指向类的指针或引用,而不需要完整的实现。当两个类紧密交互,它们的实现或定义很难分离时,这会非常有用。
6条答案
按热度按时间qq24tv8q1#
C++(和C一样)被设计成可由单遍编译器实现。在编译器需要在类被实际定义之前知道一个符号引用一个类的情况下,前向引用是必要的。典型的例子是当两个类需要包含指向彼此的指针时。
如果没有对B的前向引用,编译器就不能成功地解析A的定义,并且不能通过将B的定义放在A之前来解决这个问题。
在像C#这样需要两遍编译器的语言中,不需要前向引用
因为编译器的第一遍只是简单地拾取所有的符号定义,当编译器进行第二遍时,它可以说“我知道B是一个类,因为我在第一遍中看到了定义”。
0mkxixxg2#
如果要访问类的成员/方法,或者需要知道类的大小,编译器需要该类的定义。在其他情况下,前向声明就足够了。这可以节省编译时间。例如:
对于这个类,你需要B的定义(需要大小)和C的声明(指针有固定大小)。你只需要包括B的头,而不是C的头。C的前向声明就足够了。
答:
c的前向声明(而不是包含c. h,这也是可能的)节省了每当你包含a. h时解析c. h的时间。在一个大的项目中,这可能会节省大量的编译时间。另一个好处是,在这种情况下,c. h中的变化不会触发a的重新编译。我不知道如果你包含c. h而不是前向声明它,编译器是否会识别出这一点。
要了解更多信息,试着理解粉刺这个成语(只要谷歌一下,你会得到很多点击)。
当然--在a.cpp中,如果你真的用指向c的指针做了一些事情(例如,m_ptrC-〉Add()),你需要包含c. h。但是a.cpp只读一次,头文件被读n次,对于大型项目中经常使用的类,n很大。
正向声明也允许循环依赖。例如:
请记住-如果你使用前向声明,你不能使用任何关于size和方法的信息。这也是2个类互相包含的情况(一个类不需要前向引用)。我个人认为循环引用是不好的风格,如果可能的话,你应该避免它们。
更多信息:C++常见问题解答
谢谢你对循环依赖的评论,我只是忘记了它们。
r1wp621o3#
首先,类是 * 声明的 *,然后是 * 定义的 *。
声明:它只是告诉编译器:好的,这里有一些东西(方法,类,等等),可以被给定的名字使用。它只是把给定的名字绑定到一些东西上。
定义:它告诉编译器:好的,下面是方法、类等实际上做了什么(以及如何做)。如果定义了某个东西,那么编译器就会为它实际上分配空间。
你可以看看here。
bmvo0sr54#
第一行是所谓的前向声明,它将类的名称带入当前命名空间,但实际上并没有定义它。
8zzbczxx5#
嗯,这个问题不是很清楚。但是,提供的代码声明了一个类
test
,并在下面定义了它,省略了实际的成员(...)。mm5n2pyu6#
简单的答案是,当你使用第一种形式时,你可以保存指向类的指针或引用,而不需要完整的实现。当两个类紧密交互,它们的实现或定义很难分离时,这会非常有用。