Why would one use nested classes in C++?

Solution 1:

Nested classes are cool for hiding implementation details.

List:

class List
{
    public:
        List(): head(nullptr), tail(nullptr) {}
    private:
        class Node
        {
              public:
                  int   data;
                  Node* next;
                  Node* prev;
        };
    private:
        Node*     head;
        Node*     tail;
};

Here I don't want to expose Node as other people may decide to use the class and that would hinder me from updating my class as anything exposed is part of the public API and must be maintained forever. By making the class private, I not only hide the implementation I am also saying this is mine and I may change it at any time so you can not use it.

Look at std::list or std::map they all contain hidden classes (or do they?). The point is they may or may not, but because the implementation is private and hidden the builders of the STL were able to update the code without affecting how you used the code, or leaving a lot of old baggage laying around the STL because they need to maintain backwards compatibility with some fool who decided they wanted to use the Node class that was hidden inside list.

Solution 2:

Nested classes are just like regular classes, but:

  • they have additional access restriction (as all definitions inside a class definition do),
  • they don't pollute the given namespace, e.g. global namespace. If you feel that class B is so deeply connected to class A, but the objects of A and B are not necessarily related, then you might want the class B to be only accessible via scoping the A class (it would be referred to as A::Class).

Some examples:

Publicly nesting class to put it in a scope of relevant class


Assume you want to have a class SomeSpecificCollection which would aggregate objects of class Element. You can then either:

  1. declare two classes: SomeSpecificCollection and Element - bad, because the name "Element" is general enough in order to cause a possible name clash

  2. introduce a namespace someSpecificCollection and declare classes someSpecificCollection::Collection and someSpecificCollection::Element. No risk of name clash, but can it get any more verbose?

  3. declare two global classes SomeSpecificCollection and SomeSpecificCollectionElement - which has minor drawbacks, but is probably OK.

  4. declare global class SomeSpecificCollection and class Element as its nested class. Then:

    • you don't risk any name clashes as Element is not in the global namespace,
    • in implementation of SomeSpecificCollection you refer to just Element, and everywhere else as SomeSpecificCollection::Element - which looks +- the same as 3., but more clear
    • it gets plain simple that it's "an element of a specific collection", not "a specific element of a collection"
    • it is visible that SomeSpecificCollection is also a class.

In my opinion, the last variant is definitely the most intuitive and hence best design.

Let me stress - It's not a big difference from making two global classes with more verbose names. It just a tiny little detail, but imho it makes the code more clear.

Introducing another scope inside a class scope


This is especially useful for introducing typedefs or enums. I'll just post a code example here:

class Product {
public:
    enum ProductType {
        FANCY, AWESOME, USEFUL
    };
    enum ProductBoxType {
        BOX, BAG, CRATE
    };
    Product(ProductType t, ProductBoxType b, String name);

    // the rest of the class: fields, methods
};

One then will call:

Product p(Product::FANCY, Product::BOX);

But when looking at code completion proposals for Product::, one will often get all the possible enum values (BOX, FANCY, CRATE) listed and it's easy to make a mistake here (C++0x's strongly typed enums kind of solve that, but never mind).

But if you introduce additional scope for those enums using nested classes, things could look like:

class Product {
public:
    struct ProductType {
        enum Enum { FANCY, AWESOME, USEFUL };
    };
    struct ProductBoxType {
        enum Enum { BOX, BAG, CRATE };
    };
    Product(ProductType::Enum t, ProductBoxType::Enum b, String name);

    // the rest of the class: fields, methods
};

Then the call looks like:

Product p(Product::ProductType::FANCY, Product::ProductBoxType::BOX);

Then by typing Product::ProductType:: in an IDE, one will get only the enums from the desired scope suggested. This also reduces the risk of making a mistake.

Of course this may not be needed for small classes, but if one has a lot of enums, then it makes things easier for the client programmers.

In the same way, you could "organise" a big bunch of typedefs in a template, if you ever had the need to. It's a useful pattern sometimes.

The PIMPL idiom


The PIMPL (short for Pointer to IMPLementation) is an idiom useful to remove the implementation details of a class from the header. This reduces the need of recompiling classes depending on the class' header whenever the "implementation" part of the header changes.

It's usually implemented using a nested class:

X.h:

class X {
public:
    X();
    virtual ~X();
    void publicInterface();
    void publicInterface2();
private:
    struct Impl;
    std::unique_ptr<Impl> impl;
}

X.cpp:

#include "X.h"
#include <windows.h>

struct X::Impl {
    HWND hWnd; // this field is a part of the class, but no need to include windows.h in header
    // all private fields, methods go here

    void privateMethod(HWND wnd);
    void privateMethod();
};

X::X() : impl(new Impl()) {
    // ...
}

// and the rest of definitions go here

This is particularly useful if the full class definition needs the definition of types from some external library which has a heavy or just ugly header file (take WinAPI). If you use PIMPL, then you can enclose any WinAPI-specific functionality only in .cpp and never include it in .h.