我个人使用c++的风格总是把类声明放在包含文件中,定义放在。cpp文件中,这很像Loki对c++头文件的回答,代码分离。不可否认,我喜欢这种风格的部分原因可能与我花了这么多年来编写Modula-2和Ada有关,这两者都有类似的规范文件和主体文件方案。

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

我不像以前那么灵活了,所以在我看到更多的人和他在一起之前,我并不急于加入他的行列。那么这个习语到底有多普遍呢?

只是给答案一些结构:现在的方式™,非常常见,有点常见,不常见,还是疯狂?


当前回答

正如图马斯所说,你的头球应该是最小的。为了完整,我将展开一点。

我个人在我的c++项目中使用4种类型的文件:

Public: Forwarding header: in case of templates etc, this file get the forwarding declarations that will appear in the header. Header: this file includes the forwarding header, if any, and declare everything that I wish to be public (and defines the classes...) Private: Private header: this file is a header reserved for implementation, it includes the header and declares the helper functions / structures (for Pimpl for example or predicates). Skip if unnecessary. Source file: it includes the private header (or header if no private header) and defines everything (non-template...)

此外,我还附带了另一条规则:不要定义可以转发声明的内容。当然,我在那里是合理的(到处使用皮impl是相当麻烦的)。

这意味着我更喜欢在头文件中使用前向声明,而不是使用#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

这里的救星是大多数时候forward头是无用的:只有在typedef或模板的情况下才需要,实现头也是;)

其他回答

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

我发现把所有东西都放在头文件中的有用的事情是:

不需要写和同步头文件和源文件。 结构很简单,没有循环依赖迫使编码器做出“更好”的结构。 便携,易于嵌入到新项目中。

我同意编译时间的问题,但我认为我们应该注意到:

源文件的改变很可能会改变头文件,从而导致整个项目重新编译。 编译速度比以前快多了。而如果你的项目建设时间长、频率高,这可能说明你的项目设计存在缺陷。将任务分离到不同的项目和模块中可以避免这个问题。

最后,我只是想支持你的同事,只是在我个人看来。

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

将代码放在头文件中的一个原因是,当使用其他cpp文件中实例化的模板时,关键字inline通常需要它才能正常工作。

正如图马斯所说,你的头球应该是最小的。为了完整,我将展开一点。

我个人在我的c++项目中使用4种类型的文件:

Public: Forwarding header: in case of templates etc, this file get the forwarding declarations that will appear in the header. Header: this file includes the forwarding header, if any, and declare everything that I wish to be public (and defines the classes...) Private: Private header: this file is a header reserved for implementation, it includes the header and declares the helper functions / structures (for Pimpl for example or predicates). Skip if unnecessary. Source file: it includes the private header (or header if no private header) and defines everything (non-template...)

此外,我还附带了另一条规则:不要定义可以转发声明的内容。当然,我在那里是合理的(到处使用皮impl是相当麻烦的)。

这意味着我更喜欢在头文件中使用前向声明,而不是使用#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

这里的救星是大多数时候forward头是无用的:只有在typedef或模板的情况下才需要,实现头也是;)

我把所有实现都放在类定义之外。我想把doxygen注释从类定义中删除。

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

// class-declaration

// inline-method-declarations

我不喜欢将方法的代码与类混合在一起,因为我发现快速查找东西很痛苦。

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

在类中执行方法是有效的…但从可读性的角度来看,我不喜欢它。将方法放在头文件中确实意味着,如果可能的话,它们将被内联。