标题文件中大规模转发声明类别的风险是什么?

What are the risks to massively forward declaration classes in header files?

本文关键字:是什么 文件 大规模 转发 声明 标题      更新时间:2023-10-16

对于class1类的每个指针p1,是否应该通过使用class1的前向声明而不是包括class1标头文件来考虑任何风险?

我只能看到优势:标头文件的尺寸较小。

班级提供商控制之外的正向声明是有问题的!我正在使用使用大量前瞻性声明的代码库。虽然事情最初是很棒的,但前瞻性声明的存在变成了遗产:

  • 不能将类从一个名称空间移到另一个名称空间。没有前向声明,可以使原始名称空间中的名称成为别名(typedefusing alias)。
  • 课程不能像以前那样变成类模板的专业化,例如,在概括成功的类时很有用。
  • 类模板不能被用户转发,因为只有类模板的第一个声明才能提供默认参数。

假设前向声明是通过类提供商/实施者控制下的标头提供的(例如,提供类似于<iosfwd>的某些东西的实施者)与这些问题无关紧要,因为有一个可以更改声明的中心位置。但是,让用户决定声明实体成为造成巨大成本的遗产。


上面概述的宣言提供的方法似乎引起了一些混乱。我会尝试澄清。在我看来,实施单位是组件(基于约翰·拉科斯(John Lakos)的组件表示法)。组件定义一个或多个密切相关的类和/或功能。组件的实现由多个文件组成:

  1. 标题文件声明 所有相关实体,也定义了使用组件时必须定义的实体,即定义了用户访问类,枚举等。。
  2. 一个标题文件仅声明组件提供的相关实体(多个相关组件可以共享一个这样的标头文件; <iosfwd>是跨多个组件共享此类标头的示例。
  3. )。
  4. 定义所有实体(旨在被用ODR使用的)的实现文件,该文件仅由上面的标头声明。
  5. 至少有一个用测试驱动程序测试组件定义的所有实体的文件。

组件的用户在某些情况下只需要了解组件中的名称将包括仅声明的标题。在任何情况下,用户都不会在组件中提供名称的声明:组件中的所有名称声明都是组件的提供商/实施者的责任。

我只能看到优势:标头文件的尺寸较小。

这不完全是重点。

让我们假设您在标题文件中有类声明,例如

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时必定会重新编译所有因素)

#include "Baz.hpp"
class Foo {
public:
    void bar(const MyNamespace::Baz & x);
};

使用声明,第一版可能有助于编译代码更快。

特别是如果您有自己的标题和类声明,并且如果可能更改其中的任何一个,则只想在代码库中重新编译您的翻译单元,而不是每个包含您类型依赖性标头的源文件。/p>


请注意,正向声明只能与引用和指针一起使用。也无法使用对转发类型成员的删除代码的标题。