Hiding 'static' class variables

1.9k views Asked by At

So I recently found some source code which used a particular technique(idiom?) I hadn't seen before; to put it simply; instead of using a static variable for the class in question, it used a local variable inside the classes source file.

myclass.h

class myclass {
    //static int myint;

public:
    myclass();
    ~myclass();
    int count();
};

myclass.cpp

#include "myclass.h"

int myint = 0;

myclass::myclass() {
    myint++;
}
myclass::~myclass() {
    myint--;
}

int myclass::count() {
    return myint;
}

main.cpp

#include "myclass.h"
#include <iostream>

int main() {
    myclass aclass;
    myclass theclass;

    std::cout << theclass.count(); //outputs 2
    return 0;
}

My question is, why would someone take this approach over using a static variable?

My take on it is that, since ideally the variable would only be known to the myclass class (private static), and inheritance is not of importance at all (in this case), this could stop others knowing about this variable. But that is the only advantage I can see; not sure if that would warrant it.

The same question goes for (static / non - static) member functions that are private; when inheritance is not important.

EDIT: After reading around, I'm going to make a stab that it is because some people still use C programming style...

3

There are 3 answers

4
James McNellis On BEST ANSWER

It doesn't really matter whether you use a static member variable or a global variable or a locally declared static variable; the only important thing is that the object has to have static storage duration. Beyond that, the choice is mostly based on personal preference or coding style guidelines.

Unfortunately, this code is basically wrong. While myint is "hidden" and only directly accessible from within myclass.cpp, it still has external linkage. This means that it is accessible from other translation units (by using extern int myint in those other translation units) and its definition can conflict with other definitions of myint in other translation units.

To correct this, it should either be declared static (giving it internal linkage) or, preferably, it should be declared in an unnamed namespace,

namespace {
    int myint;
}

(an object in an unnamed namespace may still have external linkage, but it is uniquely named so it cannot be used by its name from outside of the translation unit in which it is compiled.)

0
6502 On

In your example the variable is not static and is technically visible outside the compilation unit if properly declared. If this is not intentional it can be a source of problems if another compilation unit uses the same trick on a variable with the same name (to fix this see James McNellis answer).

Assuming a properly declared static (e.g. using the unnamed namespace approach) this technique can be better than a class static because it hides completely the variable from class users. This means that if you need to add or modify that variable the clients don't even need to be recompiled (you just need to recompile the implementation .cpp file and then to relink the program). This can be a big difference if your class is used everywhere in a big project (compile just one file instead of recompiling the whole world because of a change in an internal detail).

Also if the static variable is not an int but something more complex (e.g. a templated class instance) then putting the variable in the class as a static requires to expose much more data to clients, introducing not needed dependencies.

Sometimes this unwanted dependency problem is considered so important that you can find implementation of the "compiler firewall" idiom. This hiding is sort of a partial and light version of it.

1
justin On

My question is, why would someone take this approach over using a static variable?

it makes sense if you have something to hide -- an int is not worth usually hiding, but a large library is. an author may also prefer to hide implementation details from clients in some cases.

regarding static functions -- i'll typically hide them if they are just free helpers, and really don't belong in, or are required to be a part of the class interface.

generally, i'll put it in the class interface simply for organizational purposes.