C++ 在头文件中大量转发声明类有什么风险? 代码>的前向声明,而不包括类1>代码>头文件?< /p>
我只看到好处:头文件的大小会更小。在类的提供者控制之外的转发声明是有问题的!我正在开发一个代码库,其中使用了很多前向声明。虽然一开始情况很好,但远期声明的存在已成为一种遗产:C++ 在头文件中大量转发声明类有什么风险? 代码>的前向声明,而不包括类1>代码>头文件?< /p>,c++,C++,我只看到好处:头文件的大小会更小。在类的提供者控制之外的转发声明是有问题的!我正在开发一个代码库,其中使用了很多前向声明。虽然一开始情况很好,但远期声明的存在已成为一种遗产: 类不能从一个命名空间移动到另一个命名空间。如果没有转发声明,原始命名空间中的名称可以成为别名(typedef或使用别名) 类不能按原样转化为类模板的专门化,例如,在概括一个成功的类时很有用 用户不能向前声明类模板,因为只有类模板的第一个声明可以提供默认参数 假设转发声明是通过类提供者/实现者(例如,提供类似于的东西的实
- 类不能从一个命名空间移动到另一个命名空间。如果没有转发声明,原始命名空间中的名称可以成为别名(
或typedef
)使用别名
- 类不能按原样转化为类模板的专门化,例如,在概括一个成功的类时很有用
- 用户不能向前声明类模板,因为只有类模板的第一个声明可以提供默认参数
的东西的实现者)控制下的报头提供的,这些问题是不相关的,因为存在可以更改声明的中心位置。但是,让用户决定声明实体会成为一种遗留问题,造成巨大的成本
上文概述的提供声明的做法似乎造成了一些混乱。我会尽力澄清的。在我看来,实现单元是一个组件(它基于John Lakos的组件表示法)。组件定义一个或多个密切相关的类和/或函数。组件的实现由多个文件组成:
是跨多个组件共享的头文件的示例)namespace MyNamespace {
class Baz;
}
class Foo {
public:
void bar(const MyNamespace::Baz & x);
};
在单独的翻译单元中定义为
#include "Baz.hpp"
void Foo::bar(const MyNamespace::Baz & x) {
// actually do something with Baz
}
相反,头文件中包含了所有内容(并且当Baz.hpp
将被更改时,所有依赖源都将被重新编译)
有了这个声明,第1个版本可能有助于加快代码的编译速度
特别是如果您有自己的头文件和类声明,并且其中任何一个可能会被更改,那么您只需要在代码库中重新编译翻译单元,而不是包括依赖类型的头文件的每个源文件
请注意,前向声明只能与引用和指针一起使用。也不能使用取消引用转发类型成员的头内联代码。编译器会告诉您。转发声明不能做那么多。缺点是,如果您决定重命名类,如果忘记更新转发声明,则不会出现任何编译器错误。一般来说,您在某些地方仍然会有一些错误,但原因不会那么明显。完整的类声明和转发声明是不可互换的:转发声明不允许您使用类的成员,只允许声明指向它的引用和指针。当这足以满足您的目的时,就没有风险了。@StavAlfi我没有否决投票,但有些否决票可能是因为他们认为您应该先研究向前声明。您能解释一下什么是“类的提供者”吗?@StavAlfi您想要编写类的人use@StavAlfi:类的提供者是实现该类的提供者。也就是说,转发声明必须是类实现的一部分,例如,通过具有包含一个类或一组类的转发声明的头。如果只有转发声明以更合乎逻辑的方式工作。在我可能需要转发声明的情况下,我只想说,“这里将有一个此名称的类型。”对我来说,无论该类型是通过类型别名还是其他方式。哈,这顶帽子非常适合你。我喜欢。
#include "Baz.hpp"
class Foo {
public:
void bar(const MyNamespace::Baz & x);
};