Home > Blockchain >  C - Are classes with only static members bad practice/anti-pattern?
C - Are classes with only static members bad practice/anti-pattern?

Time:12-15

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?

CodePudding user response:

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.

CodePudding user response:

While in general I recommend namespaces too, there are cases where the class is clearly a better approach. For example, you can pass a class as a template parameter, and that can mean you can have policy classes implement an interface differently, and "plug it in". You can't do that with namespaces.

But if you're not intending to refer to the group of names in such a way, I'd discourage it as a general approach to organizing code.

  • Related