Reputation: 1746
I know similar questions have been answered before but I have searched stackoverflow (et al) and haven't found a clear idea on what to do with a small class that is instantiated and used only once in the program. Is it really important to still have the declaration and implementation in separate files?
Take the following example:
// 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();
};
Everything I have read insists that declaration and implementation be in separate files but it seems absurd to split up such a simple class into .h file and .cpp file. It is very rarely ever changed and instantiated only once.
I have some other classes, a little bigger and also used only once that I currently have in 2 files. Assuming a class is only instantiated once in the program, my questions are:
I know there are very similar questions already existent here but I haven't read any that gave a clear answer to the above.
Upvotes: 5
Views: 2049
Reputation: 11730
Here's another consideration: compilation performance.
Notice that your all-in-one declaration + definition file makes use of GetTickCount64
. This file needs to include Windows.h - a rather huge beast (albeit indirectly in your case, by way of your presets.h, no doubt), because GetTickCount64 is declared in Windows.h. (This is especially relevant if your timer return type (u64) does not rely on windows-platform-specific types).
If you separated your declaration from your definition, then only the definition (.cpp file) would need to include Windows.h. And the declaration (.h) would not need it.
This means that any .cpp file that includes your Timer.h file would not be forced to include Windows.h. This keeps compilation time and memory requirements down for all the consumers of Timer.h and ultimately results in a faster compile. There may be many consumers of the .h file (many other .cpp files in your project that need to include your Timer.h file) But only one .cpp will need to be compiled to produce the definition of the Timer class (your Timer.cpp), and that's the only one that actually needs to include the Windows.h header for that function.
As your application grows in size, you will hopefully create more and more platform-independent modules that rely on simple abstractions such as your Timer class rather than raw Win32/Win64 API calls such as GetTickCount64. The bulk of your application can just be the business logic of your application without relying on including the heavyweight platform-specific headers for large APIs such as the Win32 API.
Chapter 2
The next part of this effort would be to separate out the private part of the class from the public part of the interface to further isolate code and keep headers small. In your particular example, you don't have anything special in your class declaration to isolate, but in many cases, the class may require a private member variable with a type that the public interface doesn't care about. There's no need to burden consumers of your Timer.h header file with a definition of all the types of things that you might need to put in your private variables; only types that are part of your public API.
Upvotes: 1
Reputation: 238301
- Is it reasonable to put declaration and implementation of a small class in a single file?
Yes, it is reasonable to put declaration and implementation of a small class in a single file.
If not, why not?
Because if the function definitions are modified, then all translation units which depend on the class definition need to be recompiled - or rather, all translation units which include the definition need to be recompiled. This includes all the ones that do depend on the class as they must include the definition, but also those which include the definition gratuitously.
- How large does a class need to be before it's better to separate into 2 files?
There is no hard limit. It depends on many variables, and is heavily influenced by personal preference.
Some people put all member function definitions in one translation unit per each class, because that's the way they know how things are done, or because they have a coding standard that must be followed.
Others swear that they cannot live without optimisation possibilities allowed by defining all functions inline in headers so that there is just one translation unit for the entire program. This also has the effect of reducing compilation time from scratch, but also causing the entire project to rebuild upon any change.
But there is no need to dogmatically follow either of these paths, and neither is necessarily optimal - both have drawbacks and advantages. So, a good choice is probably somewhere between these paths. But as I said above, the choice depends on many variables, so it's probably better to use a quick heuristic rather than full analysis. Here are a few, that you can follow if you find the reasoning suitable:
Assuming a class is only instantiated once in the program
The number of instantiations is mostly irrelevant to the choice - other than inlining the constructor is probably not important for performance in this case.
P.S.
While it is quite portable, #pragma once
is non-standard. I'm not saying you should get rid of it; this is just something to be aware of.
GetTickCount64
is system specific and non-portable. C++ has a standard clock API in the <chrono>
header.
Upvotes: 7
Reputation: 556
Otherwise, the way you created the class in the .h file is also okay, I often create enums in a separate header file. If the one can declare a class and provide inline member functions, thus, to define the class in the same time, why not to do this? It reduces the number of files, amount of code, makes it briefer.
Important note: I would provide a comment that explains why I declared and defined a class in a header file. Other developers would be able to understand my motivation.
Upvotes: 2