代码之家  ›  专栏  ›  技术社区  ›  T.E.D.

头文件中的C++代码

  •  170
  • T.E.D.  · 技术社区  · 17 年前

    我个人对C++的风格一直是将类声明放在include文件中,将定义放在 .cpp Loki's answer to C++ Header Files, Code Separation 诚然,我喜欢这种风格的部分原因可能与我花了多年时间编写Modula-2和Ada有关,这两者在规范和正文文件方面都有类似的方案。

    我有一位同事,他对C++的了解比我多得多,他坚持认为所有C++声明都应该尽可能在头文件中包含定义。他并不是说这是一种有效的替代风格,甚至是一种稍微好一点的风格,而是说这是每个人现在都在C++中使用的新的普遍接受的风格。

    ,非常常见,有点常见,不常见,还是疯狂?

    17 回复  |  直到 5 年前
        1
  •  239
  •   Community Mohan Dere    9 年前

    你的同事错了,常见的方法是,而且一直是,将代码放在.cpp文件(或你喜欢的任何扩展名)中,并在头文件中声明。

    最后,当所有代码都是头时,循环对象关系(有时是需要的)通常很烦人。

    编辑: 我一直在思考你的问题。有 他说的是真的。模板。许多较新的“现代”库,如boost,大量使用模板,并且通常是“仅限头部”的。但是,只有在处理模板时才应该这样做,因为这是处理模板时的唯一方法。

    编辑:

    如果你四处搜索,你会看到很多人试图在处理boost时找到一种减少编译时间的方法。例如: How to reduce compilation times with Boost Asio ,它看到了一个包含boost的1K文件的14s编译。14秒可能看起来并没有“爆炸”,但它肯定比典型的要长得多,在处理大型项目时可以很快加起来。仅头文件库确实以一种相当可衡量的方式影响编译时间。我们之所以容忍它,是因为助推非常有用。

    注:

    最后一点,当使用boost作为纯头代码的示例时,常常会遗漏一个巨大的细节。

        2
  •  181
  •   Yes - that Jake.    17 年前

    C++程序员达成一致的那一天

    目前,.h和.cpp文件之间的分隔大多是任意的,这是很久以前编译器优化的残余。在我看来,声明属于头文件,定义属于实现文件。但是,这只是习惯,不是宗教。

        3
  •  33
  •   Laserallan    17 年前

    头文件中的代码通常是一个坏主意,因为当您更改实际代码而不是声明时,它会强制重新编译包含头文件的所有文件。它还会减慢编译速度,因为您需要解析包含标头的每个文件中的代码。

    在头文件中包含代码的一个原因是,通常需要内联关键字才能正常工作,并且在使用其他cpp文件中实例化的模板时也需要内联关键字。

        4
  •  24
  •   JohnMcG    17 年前

        5
  •  14
  •   Nathan Moinvaziri Cloud    9 年前

    我认为你的同事很聪明,你也是对的。

    1. 无需写作;同步标头和源。

    2. 便携,易于嵌入到新项目中。

    1. 源文件的更改很可能会更改头文件,从而导致整个项目再次重新编译。

    2. 编译速度比以前快得多。如果你有一个项目需要长时间、高频率地构建,这可能表明你的项目设计有缺陷。将任务分解为不同的项目和模块可以避免这个问题。

        7
  •  7
  •   Matthieu M.    16 年前

    正如Tuomas所说,你的头球应该尽量小。为了完整,我将稍作扩展。

    我个人使用4种类型的文件 C++

    • 公众:
    • 转发标头:如果是模板等,此文件将获取将出现在标头中的转发声明。
    • 私人:

    此外,我还将此与另一条规则结合起来:不要定义你可以转发声明的内容。当然,我在这方面是讲道理的(到处使用Pimpl都很麻烦)。

    #include 只要我能逃脱惩罚,我就会在标题中添加指令。

    最后,我还使用了可见性规则:我尽可能地限制符号的范围,这样它们就不会污染外部范围。

    总而言之:

    // example_fwd.hpp
    // Here necessary to forward declare the template class,
    // you don't want people to declare them in case you wish to add
    // another template symbol (with a default) later on
    class MyClass;
    template <class T> class MyClassT;
    
    // example.hpp
    #include "project/example_fwd.hpp"
    
    // Those can't really be skipped
    #include <string>
    #include <vector>
    
    #include "project/pimpl.hpp"
    
    // Those can be forward declared easily
    #include "project/foo_fwd.hpp"
    
    namespace project { class Bar; }
    
    namespace project
    {
      class MyClass
      {
      public:
        struct Color // Limiting scope of enum
        {
          enum type { Red, Orange, Green };
        };
        typedef Color::type Color_t;
    
      public:
        MyClass(); // because of pimpl, I need to define the constructor
    
      private:
        struct Impl;
        pimpl<Impl> mImpl; // I won't describe pimpl here :p
      };
    
      template <class T> class MyClassT: public MyClass {};
    } // namespace project
    
    // example_impl.hpp (not visible to clients)
    #include "project/example.hpp"
    #include "project/bar.hpp"
    
    template <class T> void check(MyClass<T> const& c) { }
    
    // example.cpp
    #include "example_impl.hpp"
    
    // MyClass definition
    

    这里的救命稻草是,大多数时候,前向头球是无用的:只有在以下情况下才有必要 typedef template

        8
  •  6
  •   Anonymous    17 年前

    .ipp .hpp ),而 包含接口。

    正常代码

        9
  •  6
  •   EvilTeach    17 年前

        10
  •  5
  •   jww avp    10 年前

    我个人在头文件中这样做:

    // class-declaration
    
    // inline-method-declarations
    

    我不会将所有方法都放在头文件中。编译器(通常)不能内联虚拟方法,并且(可能)只内联没有循环的小方法(完全取决于编译器)。

        11
  •  4
  •   Virne    17 年前

    我认为将所有函数定义放在头文件中是绝对荒谬的。为什么?因为头文件用作类的PUBLIC接口。这是“黑匣子”的外部。

    当你需要查看一个类来参考如何使用它时,你应该查看头文件。头文件应该给出它可以做什么的列表(注释以描述如何使用每个函数的详细信息),并且它应该包括成员变量的列表。它不应该包括每个单独函数的实现方式,因为这是一堆不必要的信息,只会使头文件变得混乱。

        12
  •  4
  •   SeanRamey    8 年前

    如果这种新方式真的

    我们也使用 "opaque pointer"-pattern

    通过这些实践,我们可以比大多数同行更快地构建。是的。..更改代码或类成员不会导致巨大的重建。

        13
  •  2
  •   spoulson    17 年前

    依我之见,他只有在做模板和/或元编程时才有价值。前面已经提到了很多将头文件限制为仅声明的原因。他们就是这样。..标题。如果你想包含代码,你可以将其编译为库并链接起来。

        14
  •  2
  •   Jesus Fernandez    10 年前

    我把所有的实现都从类定义中去掉了。我想把doxygen注释从类定义中去掉。

        15
  •  1
  •   Ed James    17 年前

    这真的不取决于系统的复杂性和内部惯例吗?

    目前,我正在开发一个非常复杂的神经网络模拟器,我希望使用的公认风格是:



    classname.cpp中的可执行代码

    这将用户构建的模拟与开发人员构建的基类分开,在这种情况下效果最佳。

    然而,如果人们在图形应用程序或任何其他不为用户提供代码库的应用程序中这样做,我会感到惊讶。

        16
  •  0
  •   Abhishek Agarwal    13 年前

        17
  •  0
  •   Emile    9 年前

    我认为你的同事是对的,只要他不参与在头部编写可执行代码的过程。