When I was going through the project on which I am working, I came across a cpp file, which has only functions and static variables.I was wondering why they have not put everything into a class! Whenever the inside functions have to be called, the cpp file is included.
Is this a good design? what are the pros and cons of these type of design?
for ex.
//independent.cpp
#include "someclass.h"
static int var1;
static someclass object("hello");
static bool var2;
void foo(const char* dir, const char* filename){
...
}
somefile.cpp
#include "independent.cpp"
class sample{
public:
void caller(){
foo("c:", "file.txt");
}
}
3
What are the pros and cons of these type of design?
Pros: easy to write, easy to read, easy to call.
Cons: naming conflicts, risk of global variables, difficult to override.
I was wondering why they have not put everything into a class!
If your functions don’t need a context (e.g. utility functions), you’re going to have difficulties finding a meaningful place for them in a class. As much as classes are a very useful way to organise code and instances, there are scenarios where they’re not worth the hassle.
You could also argue it’s not much of an effort to put it in a class. That’s a valid point, but the author(s) didn’t see any added value to it.
Is this a good design?
I 100% agree with Emilio Garavaglia’s take on that: Whether it is a good or a bad design depends on the context. It’s not wrong to do it this way, but it may be infeasible in the scope of some projects.
They simply follow a singleton-object paradigm different from the C++ class offered one:
static variables in CPP file are invisible outside, while private member of a class have to be declared in the class (that must be given in an header).
If you want to make those variables just unreachable, the private
access is good, but if you want to make them secret, they cannot be “members” of a class whose size must be known.
And if they have to exist just once, a class must be a singleton (that is a static hidden variable accessed by a global function) that’s not that different in making the variable itself global in a very limited context.
Its is just the good-old C-based OOP implementation you can find in Win32, or in GTK+.
If it is a good or bad design is more a matter of context than idiom.
One of the driving reasons why to not implement a set of utility functions as a class is th fact that when it comes to having a class with no state which only provides functions, then there’s very little sense in instantiating that class as all of the instances are identical. There’s no meaning in defining such a data type because data types are contracts about what the data/state represents. When there is no state or data, there’s nothing to represent.
Many times it is not that straightforward though. For the sake of example (this is something you’d perhaps want in an actual self-contained class instead), consider a situation where you have a get_time_delta()
function and want to return time spent since the last invocation of the get_time_delta()
function — a common situation when calculating for example how long it takes to run a render_scene()
function in a game. You’d need to store the time for the first invocation and the time for the second invocation and subtract the first from the second — but without state this is impossible. One way to do this would be to implement a class and hold this state as private member variables, but if this is a generic utility class, that timing data which is relevant for get_time_delta()
only gets exposed to other utility functions too. This is bad because minimizing the scope of the variables is desired. One good way to go about this is to have the internal timing data local to the get_time_delta()
function by specifying it with static
storage-class specifiers.
As it stands, in the aforementioned example we do not need state for the class. So why do we need a class to begin with? Say we have an API like this:
unsigned int delta_time = Util::get_time_delta();
It would be unreasonable to need to instantiate Util
as it holds no state. So either we declare get_time_delta()
as static
functions of the class or we declare get_time_delta()
inside a namespace Util
.
This all said, “the C++ way”(whatever it means, don’t read to it too much) is to define utility functions within a namespace instead of as static
member functions of an utility class.
In other languages, namely in C# and Java, there’s a pattern called utility pattern which simulates namespaces — placing utility functions behind a “namespace” by declaring them as static member functions of a class. In C++ this is not needed at all because of built-in namespaces and free-standing functions.
My guess is that it is used to make a bunch of “single purpose executables”.
(Disclaimer: my C++ knowledge is not as good as the other answerers – my answer is just a guess.)
Observe that
-
This approach allows multiple reusable classes, “someclass.h”, etc, to be included. So, one could deduce that the family of classes named “someclass.h” do indeed follow good C++ OOP practices.
-
However, if one includes more than one “independent.cpp” into a build, it is likely to run into name conflicts. The actual name conflicts could be two “static” variables with the same name (“var1”) across two such source files (*), or could be linking errors.
- (*) Unless they are made
extern
. Remember these lines are being included into a singlecpp
file.
- (*) Unless they are made
-
So, one could deduce that in an actual build, only one such “independent.cpp” file could ever be linked per executable produced in the build. If there are multiple files like this, only one of these could be linked at a time.
(Details.)
Suppose there were two files, “IndependentOne.cpp” and “IndependentTwo.cpp”. Note that these file extensions wouldn’t matter, if they were being included verbatim into another cpp
file.
Suppose each “IndependentOne.cpp” and “IndependentTwo.cpp” contains a definition for “var1”:
// IndependentOne.cpp
#include "someClassOne.h"
static someClassOne var1;
// IndependentTwo.cpp
#include "someClassTwo.h"
static someClassTwo var1;
// SomeMainFile.cpp
#include "IndependentOne.cpp"
#include "IndependentTwo.cpp" // ---- compiler error here
int main(int argc, char** argv)
{ ... }
Then var1
is multiple-defined. To resolve it, one has to manually copy-and-paste the two files together, into “IndependentOneAndTwo.cpp”, and rename the static variables.
When is it appropriate?
- Whenever you need to “call a C++ function from the OS command line”,
- You want one executable file per C++ function called
- No data passed between calls; or the data is always passed via the file system
What the heck is this philosophy?
-
It sounds like Unix-ish – Do one thing and do it well; chain your programs with pipes
-
It would have been more believable, if it was not betrayed by the hard-coded filename
"file.txt"
If it is not meant to be for real use (hard-coded filenames, etc) then what is it used for?
- Throwaway “command line wrappers” for C++ functions.
- It allows you to call exactly one C++ function;
- It reads from and writes to exactly one file or directory, whose path is hard-coded.
What are some alternative designs?
- If your goal is throwaway command-line wrapper, this is fine.
- As long as these files are excluded from the production build.
- If your goal is production use command-line application,
- Implement or use a decent command-line parsing utility, or integrate a small scripting engine with your C++ classes which removes the “call once and exit” limitation.
- If your goal is software testing (white-box / unit-testing),
- Use a unit testing framework.