我必须重构旧代码。它的一个问题是它超过了无用的“包括”。在同一个项目中,我看到了以下语法:
#include <AnyClass> //A system header
#include "AnotherAnyClass" //A application header
class AnotherClass;
class Class : public OneMoreClass
{
public:
explicit Class();
~Class();
private:
AnotherClass *m_anotherClass;
}
我想知道:
答案 0 :(得分:7)
声明一个这样的类:
class AnotherClass;
称为Forward Declaration。它允许编译器知道类的存在,在不需要知道类的详细信息的情况下,例如在您发布的场景中。
通常,如果您不打算使用该类的实例,那么您只需处理指针而不调用其上的任何方法,您不需要知道除类名之外的任何内容。这可以加速大型项目的编译。
答案 1 :(得分:5)
要理解差异,您必须首先理解编译器为什么需要include。
编译器必须知道您声明的每个类的大小。因此,它必须知道您添加到类中的每个成员的大小。对于非指针非内置成员,编译器必须查看该成员类的定义,该成员类通常位于必须包含的标头中。在指针的情况下,编译器不必查看整个定义,因为无论其类型如何,指针在给定平台上总是具有相同的大小(通常为32或64位)。因此,当成员是指针时,编译器只需要知道名称,这可以通过前向声明来完成,即
class AnotherClass;
现在,使用哪一个?
保持简短:尽可能使用前向声明,包括必要时。
如果您的标题可以使用转发声明完成,那么您将减少整个编译时间,因为您包含的每个标题都必须在包含它的每个翻译单元中进行处理。
一种常见的方案是在标题中转发声明,并在关联的.cpp
中包含相应的类。
答案 2 :(得分:5)
这是两件不同的事情:
#include <AnyClass>
这是标题(或任何类型的文本)文件的常规包含。它等同于在您键入包含指令的位置粘贴AnyClass
文件的内容(这就是为什么包含保护和/或编译器编译指示通常用于防止同一文件中的多个包含)。
此语法:
class AnotherClass;
是forward declaration,它通知编译器AnotherClass
类的存在。它在许多场景中都很有用,例如假设你有两个类,每个类需要一个指向另一个的指针:
class ClassB {
ClassA* pointer_to_classA;
};
class ClassA {
ClassB* pointer_to_classB;
};
以上代码将生成错误:“错误:未知类型名称'ClassA'”,因为您使用了ClassA
类型而编译器不知道它是什么(还)。编译器的解析器在解析类声明的开头时只知道ClassA
的存在。
要完成上述工作,您需要一个前瞻声明:
class ClassA; // A ClassA type exists
class ClassB {
ClassA* pointer_to_classA;
};
class ClassA {
ClassB* pointer_to_classB;
};