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:

  1. Doesn’t pollute the namespace.
  2. 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 Objects 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:

  1. 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.
  2. Write two classes Game and GameObject in the same (global) namespace. This solution gets messy as the number of classes “nested” grows. Also pollutes the global namespace.