Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/cplusplus/135.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C++ 在头文件中大量转发声明类有什么风险? 代码>的前向声明,而不包括类1>代码>头文件?< /p>_C++ - Fatal编程技术网

C++ 在头文件中大量转发声明类有什么风险? 代码>的前向声明,而不包括类1>代码>头文件?< /p>

C++ 在头文件中大量转发声明类有什么风险? 代码>的前向声明,而不包括类1>代码>头文件?< /p>,c++,C++,我只看到好处:头文件的大小会更小。在类的提供者控制之外的转发声明是有问题的!我正在开发一个代码库,其中使用了很多前向声明。虽然一开始情况很好,但远期声明的存在已成为一种遗产: 类不能从一个命名空间移动到另一个命名空间。如果没有转发声明,原始命名空间中的名称可以成为别名(typedef或使用别名) 类不能按原样转化为类模板的专门化,例如,在概括一个成功的类时很有用 用户不能向前声明类模板,因为只有类模板的第一个声明可以提供默认参数 假设转发声明是通过类提供者/实现者(例如,提供类似于的东西的实

我只看到好处:头文件的大小会更小。

在类的提供者控制之外的转发声明是有问题的!我正在开发一个代码库,其中使用了很多前向声明。虽然一开始情况很好,但远期声明的存在已成为一种遗产:

  • 类不能从一个命名空间移动到另一个命名空间。如果没有转发声明,原始命名空间中的名称可以成为别名(
    typedef
    使用别名
  • 类不能按原样转化为类模板的专门化,例如,在概括一个成功的类时很有用
  • 用户不能向前声明类模板,因为只有类模板的第一个声明可以提供默认参数
假设转发声明是通过类提供者/实现者(例如,提供类似于
的东西的实现者)控制下的报头提供的,这些问题是不相关的,因为存在可以更改声明的中心位置。但是,让用户决定声明实体会成为一种遗留问题,造成巨大的成本


上文概述的提供声明的做法似乎造成了一些混乱。我会尽力澄清的。在我看来,实现单元是一个组件(它基于John Lakos的组件表示法)。组件定义一个或多个密切相关的类和/或函数。组件的实现由多个文件组成:

  • 声明所有相关实体的头文件,该头文件还定义了使用组件时必须定义的实体,即定义了用户可访问的类、枚举等
  • 头文件仅声明组件提供的相关实体(多个相关组件可以共享一个这样的头文件;
    是跨多个组件共享的头文件的示例)
  • 一个实现文件,定义了仅在中由上述头声明的所有实体[用于ODR]
  • 至少一个包含测试驱动程序的文件,测试组件定义的所有实体
  • 在某些上下文中,只需要知道组件中名称的组件的用户将包括仅声明标头。在任何情况下,用户都不会在组件中提供名称声明:组件中名称的所有声明都由组件的提供者/实现者负责

    我只能看到它的优点:头文件的大小会更小

    这不是重点

    假设在头文件中有一个类声明,如

    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);
    };