Pros and cons of using nested C++ classes and enumerations?

23,631

Solution 1

Nested classes

There are several side effects to classes nested inside classes that I usually consider flaws (if not pure antipatterns).

Let's imagine the following code :

class A
{
   public :
      class B { /* etc. */ } ;

   // etc.
} ;

Or even:

class A
{
   public :
      class B ;

   // etc.
} ;

class A::B
{
   public :

   // etc.
} ;

So:

  • Privilegied Access: A::B has privilegied access to all members of A (methods, variables, symbols, etc.), which weakens encapsulation
  • A's scope is candidate for symbol lookup: code from inside B will see all symbols from A as possible candidates for a symbol lookup, which can confuse the code
  • forward-declaration: There is no way to forward-declare A::B without giving a full declaration of A
  • Extensibility: It is impossible to add another class A::C unless you are owner of A
  • Code verbosity: putting classes into classes only makes headers larger. You can still separate this into multiple declarations, but there's no way to use namespace-like aliases, imports or usings.

As a conclusion, unless exceptions (e.g. the nested class is an intimate part of the nesting class... And even then...), I see no point in nested classes in normal code, as the flaws outweights by magnitudes the perceived advantages.

Furthermore, it smells as a clumsy attempt to simulate namespacing without using C++ namespaces.

On the pro-side, you isolate this code, and if private, make it unusable but from the "outside" class...

Nested enums

Pros: Everything.

Con: Nothing.

The fact is enum items will pollute the global scope:

// collision
enum Value { empty = 7, undefined, defined } ;
enum Glass { empty = 42, half, full } ;

// empty is from Value or Glass?

Ony by putting each enum in a different namespace/class will enable you to avoid this collision:

namespace Value { enum type { empty = 7, undefined, defined } ; }
namespace Glass { enum type { empty = 42, half, full } ; }

// Value::type e = Value::empty ;
// Glass::type f = Glass::empty ;

Note that C++0x defined the class enum:

enum class Value { empty, undefined, defined } ;
enum class Glass { empty, half, full } ;

// Value e = Value::empty ;
// Glass f = Glass::empty ;

exactly for this kind of problems.

Solution 2

One con that can become a big deal for large projects is that it is impossible to make a forward declaration for nested classes or enums.

Solution 3

There are no pros and cons per se of using nested public C++ classes. There are only facts. Those facts are mandated by the C++ standard. Whether a fact about nested public C++ classes is a pro or a con depends on the particular problem that you are trying to solve. The example you have given does not allow a judgement about whether nested classes are appropriate or not.

One fact about nested classes is, that they have privileged access to all members of the class that they belong to. This is a con, if the nested classes does not need such access. But if the nested class does not need such access, then it should not have been declared as a nested class. There are situations, when a class A wants to grant privileged access to certain other classes B. There are three solutions to this problem

  1. Make B a friend of A
  2. Make B a nested class of A
  3. Make the methods and attributes, that B needs, public members of A.

In this situation, it's #3 that violates encapsulation, because A has control over his friends and over his nested classes, but not over classes that call his public methods or access his public attributes.

Another fact about nested classes is, that it is impossible to add another class A::C as a nested class of A unless you are owner of A. However, this is perfectly reasonable, because nested classes have privileged access. If it were possible to add A::C as a nested class of A, then A::C could trick A into granting access to privileged information; and that yould violate encapsulation. It's basically the same as with the friend declaration: the friend declaration does not grant you any special privileges, that your friend is hiding from others; it allows your friends to access information that you are hiding from your non-friends. In C++, calling someone a friend is an altruistic act, not an egoistic one. The same holds for allowing a class to be a nested class.

Som other facts about nested public classes:

  • A's scope is candidate for symbol lookup of B: If you don't want this, make B a friend of A instead of a nested class. However, there are cases where you want exactly this kind of symbol lookup.
  • A::B cannot be forward-declared: A and A::B are tightly coupled. Being able to use A::B without knowing A would only hide this fact.

To summarize this: if the tool does not fit your needs, don't blame the tool; blame yourself for using the tool; others might have different problems, for which the tool is perfect.

Solution 4

It seems like you should be using namespaces instead of classes to group like things that are related to each other in this way. One con that I could see in doing nested classes is you end up with a really large source file that could be hard to grok when you are searching for a section.

Solution 5

If you're never going to be using the dependent class for anything but working with the independent class's implementations, nested classes are fine, in my opinion.

It's when you want to be using the "internal" class as an object in its own right that things can start getting a little manky and you have to start writing extractor/inserter routines. Not a pretty situation.

Share:
23,631
Rob
Author by

Rob

C++, MFC, Win32, WTL, STL, Boost, HTML, CSS, JavaScript, Qt, Python, jQuery Mobile.

Updated on June 07, 2020

Comments

  • Rob
    Rob almost 4 years

    What are the pros and cons of using nested public C++ classes and enumerations? For example, suppose you have a class called printer, and this class also stores information on output trays, you could have:

    class printer
    {
    public:
        std::string name_;
    
        enum TYPE
        {
            TYPE_LOCAL,
            TYPE_NETWORK,
        };
    
        class output_tray
        {
            ...
        };
        ...
    };
    
    printer prn;
    printer::TYPE type;
    printer::output_tray tray;
    

    Alternatively:

    class printer
    {
    public:
        std::string name_;
        ...
    };
    
    enum PRINTER_TYPE
    {
        PRINTER_TYPE_LOCAL,
        PRINTER_TYPE_NETWORK,
    };
    
    class output_tray
    {
        ...
    };
    
    printer prn;
    PRINTER_TYPE type;
    output_tray tray;
    

    I can see the benefits of nesting private enums/classes, but when it comes to public ones, the office is split - it seems to be more of a style choice.

    So, which do you prefer and why?

  • paercebal
    paercebal over 15 years
    Note that using a namespace to nest a class enable the user to forward-declare this class: i.e.: <code>namespace Foo { class Bar ; }</code>. Anyway, +1 for the remark.
  • Martin York
    Martin York over 15 years
    Good example of a nested private class is the links in the list inside a std::list. There is no need for anybody to know about them use them or interact with them (or do they even really exist ;-)
  • xtofl
    xtofl over 15 years
    I do use a nested private class every now and then for the pImpl-pattern.
  • paercebal
    paercebal over 15 years
    The nested private class in the PImpl pattern means the user will see the implementation class, even if it is not accessible. Having a simple forward declaration will only declare the name, and nothing else. You'll be able to define fully the implementation elsewhere (hidden from the user)... ^_^ ..
  • Catskul
    Catskul over 14 years
    The forward declaration problem is more than just an inconvenience. You can get yourself stuck in a dependency loop that requires un-nesting of the problem area. The un-nesting could then create design inconsistency, or you would have to change your whole project to un-nested : / stackoverflow.com/questions/951234/…
  • paercebal
    paercebal over 14 years
    I completed the "nested classes" section after further investigation (prompted by a technical discussion with a friend). The results are the same (unless exception, nested classes are NOT Ok), but the reasons are better detailed.
  • Oswald
    Oswald over 10 years
    There's a confusion here. Nested class does not imply nested object. For an object b of type A::B, there might not be an object of type A, that b is a member of. If you want such a relation, you have to set one up yourself.
  • Marius Amado-Alves
    Marius Amado-Alves over 10 years
    You're right, there might not. But many times there is. This idiom is common
  • Marius Amado-Alves
    Marius Amado-Alves over 10 years
    You're right, there might not. But many times there is. This idiom is common: class A { int m; class B { int getM(); } B b; } where B objects are always components of a real A object. If C++ add a "parent" like she has "this" you could implement getM thus: int A::B::getM() { return parent->m; } (This is merely academic.)