Neat Nested Classes in C++
TL;DR Nested classes are awesome. But write the implementations outside.
A common pattern when writing C++ code for large projects is to declare classes within classes. This is desirable for a number of reasons:
- Doesn’t pollute the namespace.
- Has the usual class access restrictions.
For example consider an Object
class for a Game
. Object
is a very
generic name and there could be other Object
s in the global namespace or in
the namespace in which Game
exists. So we can declare Object
only within
the Game
namespace like so:
1
2
3
4
5
6
7
8
9
10
11
12
class Game {
int parameter1;
int parameter2;
// This class is only used by Game.
class Object {
int property1;
int property2;
};
std::vector<Object> objects;
};
But the problem with this approach usually is that it tends to make the code look very ugly because of all the class definitions inside the main class definition.
In this simply example, it’s clear what attributes belong to which class. But as you start adding methods and constructors and enums, it quickly becomes very ugly and hard to read and maintain.
A better solution instead is to declare the Object
class inside the
Game
class but write out the implementation the body of the class definition
elsewhere:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
class Game {
class Object;
int parameter1;
int parameter2;
std::vector<Object> objects;
};
// This class is only used by Game.
class Game::Object {
int property1;
int property2;
};
This way, the two implementations, even though related, are separately
implemented and are easier to read and maintain. The implementation of
Game::Object
can even be moved into its own separate file.
Alternatives
The solution above is much neater than the alternatives:
- Declare a new namespace and put both the classes in the new namespace. This solution is not as nice because it introduces an additional namespace which is unneeded.
- Write two classes
Game
andGameObject
in the same (global) namespace. This solution gets messy as the number of classes “nested” grows. Also pollutes the global namespace.