C++ Declaration of class variables in header or .cpp?

Kefir picture Kefir · Feb 14, 2015 · Viewed 23.7k times · Source

So far, I've been using classes the following way:

GameEngine.h declares the class as follows

class GameEngine {
public:
    // Declaration of constructor and public methods

private:
    InputManager inputManager;
    int a, b, c;

    // Declaration of private methods
};

My GameEngine.cpp files then just implement the methods

#include "____.h"    
GameEngine::GameEngine() {

}

void GameEngine::run() {
    // stuff
}

However, I've recently read that variable declarations are not supposed to be in the header file. In the above example, that would be an inputManager and a, b, c.

Now, I've been searching for where to put the variable declarations, the closest answer I found was this: Variable declaration in a header file

However, I'm not sure if the use of extern would make sense here; I just declare private variables that will only be used in an instance of the class itself. Are my variable declarations in the header files fine? Or should I put them elsewhere? If I should put them in the cpp file, do they go directly under the #include?

Answer

ZaldronGG picture ZaldronGG · Feb 14, 2015

Don't confuse a type's members with variables. A class/struct definition is merely describing what constitutes a type, without actually declaring the existence of any variables, anything to be constructed on memory, anything addressable.

In the traditional sense, modern class design practices recommend you pretend they are "black boxes": stuff goes in, they can perform certain tasks, maybe output some other info. We do this with class methods all the time, briefly describing their signature on the .h/.hpp/.hxx file and hiding the implementation details in the .cpp/.cc/.cxx file.

While the same philosophy can be applied to members, the current state of C++, how translation units are compiled individually make this way harder to implement. There's certainly nothing "out of the box" that helps you here. The basic, fundamental problem is that for almost anything to use your class, it kind of needs to know the size in bytes, and this is something constrained by the member fields and the order of declaration. Even if they're private and nothing outside the scope of the type should be able to manipulate them, they still need to briefly know what they are.

If you actually want to hide this information to outsiders, certain idioms such as PImpl and inlined PImpl can help. But I'd recommend you don't go this way unless you're actually:

  1. Writing a library with a semi-stable ABI, even if you make tons of changes.
  2. Need to hide non-portable, platform-specific code.
  3. Need to reduce pre-processor times due to an abundance of includes.
  4. Need to reduce compile times directly impacted by this exposure of information.

What the guideline is actually talking about is to never declare global variables in headers. Any translation unit that takes advantage of your header, even if indirectly, will end up declaring its own global variable as per header instructions. Everything will compile just fine when examined individually, but the linker will complain that you have more than one definition for the same thing (which is a big no-no in C++)

If you need to reserve memory / construct something and bind it to a variable's name, always try to make that happen in the source file(s).