何时将一个小类分成头文件和cpp文件?

pob*_*oby 3 c++ class

我知道之前已经回答了类似的问题但是我已经搜索了stackoverflow(等)并且没有找到关于如何处理实例化并在程序中仅使用一次的小类的明确想法.在单独的文件中保留声明和实现是否真的很重要?

请看以下示例:

// timer.hpp

#pragma once
#include "presets.h" // includes #defines for u64 -> uint64_t, etc

class Timer {
    public:
        Timer() {}
        Timer(u64 elt) : elt_(elt) {}

        void startTiming() { if (NOT running_){ running_ = true;  sTime_ = GetTickCount64(); }};
        void stopTiming() { if (running_)     { running_ = false; eTime_ = GetTickCount64(); elt_ += (eTime_ - sTime_); sTime_ = eTime_; }}

        u64 getElapsed() { if (NOT running_) return elt_; eTime_ = GetTickCount64(); return elt_ + eTime_ - sTime_; }
    private:
        bool running_ = true;
        u64 elt_ = 0, eTime_ = 0, sTime_ = GetTickCount64();
};
Run Code Online (Sandbox Code Playgroud)

我读过的所有内容都坚持声明和实现是在单独的文件中,但将这样一个简单的类拆分为.h文件和.cpp文件似乎很荒谬.它很少被改变并且只被实例化一次.

我有一些其他类,更大一点,也只使用我目前在2个文件中的一次.假设一个类只在程序中实例化一次,我的问题是:

  1. 将声明和实现小类放在单个文件中是否合理?如果没有,为什么不呢?
  2. 一个类需要多大才能最好分成2个文件?

我知道这里已经存在非常类似的问题,但我没有看到任何对上述内容给出明确答案的问题.

eer*_*ika 5

  1. 将声明和实现小类放在单个文件中是否合理?

是的,将一个小类的声明和实现放在一个文件中是合理的.

如果没有,为什么不呢?

因为如果修改了函数定义,则需要重新编译依赖于类定义的所有转换单元 - 或者更确切地说,需要重新编译包含该定义的所有转换单元.这包括所有依赖于类的,因为它们必须包含定义,但也包括无偿定义的定义.

  1. 一个类需要多大才能最好分成2个文件?

没有硬性限制.它取决于许多变量,并且受到个人偏好的严重影响.

有些人将每个类的所有成员函数定义放在一个翻译单元中,因为这是他们知道事情是如何完成的,或者因为他们有必须遵循的编码标准.

其他人发誓,如果没有通过在标题中内联定义所有函数所允许的优化可能性,它们就无法生存,因此整个程序只有一个翻译单元.这还具有从头开始减少编译时间的效果,但也会导致整个项目在任何更改时重建.

但是没有必要教条地遵循这些路径中的任何一条,并且两者都不一定是最优的 - 两者都有缺点和优点.因此,一个好的选择可能介于这些路径之间.但正如我上面所说,选择取决于许多变量,因此使用快速启发式而非完整分析可能更好.以下是一些,如果您找到合适的推理,您可以遵循:

  • 如果函数定义为空,那么它是内联定义的一个非常好的候选者.
  • 如果函数或类是模板,则必须内联定义 - 您没有选项(除非您可以限制可能的模板实例的数量).
  • 如果函数的定义依赖于定义,则该类的定义不依赖于该定义.如果您定义内联函数,则会导致依赖项传播.在这种情况下,不定义内联函数是一个非常好的主意.
  • 如果您习惯于修改函数的定义而非极少,并且定义在许多翻译单元中使用,那么不定义内联函数可能是个好主意,否则您可能会发现自己重新编译大多数项目一次又一次.如果项目很小并且因此可以快速编译,那么这种启发式方法无关紧要.此外,使用类的地方数量通常很难跟踪,因此假设最差的情况通常更简单.
  • 如果您对程序进行概要分析并找到每秒钟调用一百万次的特定函数,那么它就是内联定义的一个很好的候选者,可以利用内联扩展优化.请注意,即使在单独的翻译单元中定义了函数,使用链接时优化也可以允许内联扩展.
  • 如果函数编译速度慢,那么最好不要内联定义它.现在,知道哪些函数编译起来很慢并不容易理解,所以你需要一套启发式算法.以下是一些,如果您找到合适的推理,您可以遵循:
    • 较长的函数定义通常比较短的函数定义慢.
    • 实例化模板的函数有时编译起来很慢.

假设一个类只在程序中实例化一次

实例化的数量与选择无关 - 除了内联构造函数在这种情况下对性能可能不重要.


PS

虽然很便携,但#pragma once非标准.我不是说你应该摆脱它; 这只是需要注意的事情.

GetTickCount64是系统特定的和不可移植的.C++在<chrono>标头中有一个标准时钟API .