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
static functions of the class or we declare
get_time_delta() inside a namespace
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.