Regarding classes that only contain static members, I've seen multiple people claiming that it is a bad pattern and that it's never the best solution to a problem.
The accepted and top-voted answer on Are utility classes with nothing but static members an anti-pattern in C++? advocates using namespaces instead and concludes by stating
the most obvious answer to me is: Because we don't need OO to achieve this.
This is strange to me for several reasons. It seems like they are talking about classes only containing static member functions, and not classes containing a mix of static data and static functions. Classes with only static member functions can indeed be replaced with global functions inside a namespace, but how would you replace a class with containing both static functions and static data?
struct Foo
{
static void add5()
{
s_x += 5;
}
static const int& getX()
{
return s_x;
}
private:
static int s_x;
};
int Foo::s_x{ 0 };
With functions and a global variable inside a namespace? How would you make sure s_x
can't be accessed directly and modified by outside code?
The other thing that confuses me is that I feel like classes with only static members are a fairly common occurrence in books on C++ and in libraries.
SFML's sf::Mouse
has only static members.
Game Programming Patterns uses classes with only static members several times, even referring to it with the term "static class" in the Singleton chapter. And the Service Locator chapter is inherently a class with only static members.
So how should one think? Are classes with only static members bad design / bad practice? Or do they have their place in some contexts?
The top answer of the other question still holds: you do not need classes to encapsulate static functions and static variables. This can be done with namespaces and -- with a little discipline -- using the scope of compilation units.
In your example, you do not need to expose the existence of a private static data member if you're using namespaces:
Declare in a header:
namespace Foo {
void add5();
const int& getX();
}
Then implement in a cpp:
namespace Foo
{
static int s_x{0}; // static globals are not visible outside the compilation unit
void add5()
{
s_x += 5;
}
const int& getX()
{
return s_x;
}
};
Be careful: static globals are not exactly the same thing than static members, but in the code above, it's the same effect as it's private. For public data members, you'd just remove the keyword static
.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With