Pros and Cons of Using Nested C++ Classes and Enumerations

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

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.

Using nested Classes in C# and C++ - Why and When?

Hmm this might call for a very suggestive answer and therefore many will disagree with my answer. I am one of those people who believe that there is no real need for nested classes and I am tended to agree with your statement:

My 'gut instinct' in this regard is that doing so is simply due to extremely poor methodology

Cases where people feel the need to design nested classes is where functionality that is tightly coupled to the behavior designed in the outer class. E.g. event handling can be designed in an inner class, or the Threading behavior can find its way to inner classes.

I rather refactor specific behavior out of the 'outer' class so that I end up with two smaller classes that both have clear responsibilities.

To me the main drawback of designing inner classes is that they tend to clutter functionality which is hard(er) to use with principals as TDD (test driven development).

If you are not relying on test driven principals, I think it will not harm you a lot. It is (like so many things) a matter of taste, not a matter of right or wrong. I learned that the topic can lead to long and exhausting discussion. Quite similar to whether you should use static helper classes that tend to do more than just 'be a helper' and are getting more and more state over time.

The discussions can become a lot more concrete if you ever run into a real life example. Until then it will be mostly people's "gut feeling".

C++ - What's the point of nested classes?

I'm studying a little of C++ and now I'm fighting against it's similitudes with Java.

First of all be aware that C++ nested classes are similar to what in Java you call static nested classes. There isn't anything in C++ syntax to reproduce Java nested classes.

I discover that private attributes of "container" class are not visible by inner class...

C++ 98

In C++ inner classes aren't different to normal classes, they're not class members then they can't access container class' private members (unlike other languages like Java or C#).

C++ 03

Nested classes are class members but restrictions on what they can access still applies (see also section Weird things at the end of this answer). It has been considered a standard defect (see DR45) then some compilers earlier implemented C++0x access rule earlier even when compiling for C++03 (notably GCC, thanks to Jonathan Wakely to spot this out).

C++ 11

This rule changed in C++ 11, now nested classes can access private member of container class. From §11.7:

A nested class is a member and as such has the same access rights as any other member.

Of course you still need an instance to access non static members.



...so why I should use them?

They're then an implementation detail to group related classes and they have same issues about their usage that you may have in other languages (clarity for newbies, primary). Their greatest benefit IMO is encapsulation, if for example you have this:

class stream {
virtual void write(const std::string text) = 0;
};

class channel {
public:
virtual stream* get_stream() = 0;

// Other methods...
};

class tcp_channel : public channel {
public:
virtual stream* get_stream() {
return new tcp_stream(this);
}

private:
class tcp_stream : public stream { /* implementation */ };
};

They're also helpful in some circumstances to substitute nested namespaces:

class protocol {
public:
virtual void create_connection() = 0;

class tcp : public protocol { /* implementation */ };
class shared_memory : public protocol { /* implementation */ };
class named_pipes: public protocol { /* implementation */ };
};

auto media = protocol::tcp();

Or to hide implementation details:

class file_system_entry {
public:
class file : public file_system_entry { };
class directory : public file_system_entry { };

std::time_t get_last_modified() { ... }

void remove() { ... }
virtual void copy_to(std::string path) = 0;

private:
class local_handle {
// Implementation details
} _handle;
};

There are many others usage patterns (see also Why would one use nested classes in C++? for a much better discussion), just remember not everyone will correctly understand (and use!) them. See also Pros and cons of using nested C++ classes and enumerations?

Also, is there a way to make visible those attributes?

Before C++ 11 you can't (of course unless you declare them as friends but see next paragraph), if you need this feature just use a C++ 11 compiler (that supports this feature). GCC does (from long time ago) and also MSVC does, I don't know about other compilers.

Nested Friends

Is there any difference between C++ 11 access rules and friend classes? In general they're almost equivalent (automatic access is just less verbose):

class container {
public:
class nested;
friend class nested;

class nested { };
};

Compared to:

class container {
public:
class nested { };
};

However with forward declaration you have some side effects. Also remember that from accessibility point of view they're equivalent (access, like friendship, is not inherited nor transitive). These examples don't compile:

class external : public container::nested {
public:
// No: only class declared inside "container"
// has access to private members, we do not inherit that
void foo(container obj) { /* access a private member of obj*/ }
};

// No, "container" has not access to "nested" private members,
// visibility isn't reciprocal
void container::foo(container::nested obj) {
// Access some private member of obj
}

// No, we don't have anything to do with container,
// visibility isn't transitive
void friendOfNested(container obj) {
// Access some private member of obj
}

Are then completely equivalent? No, because private members of container's friends are accessible in nested if it's a nested class in C++ 11 but they're not if nested is a friend of container. Given this outlined structure:

class container;

class another {
friend class container;
};

class container {
public:
class nested { };
};

nested can access another's private members:

void container::nested::foo(another obj) {
obj.somePrivateMember = 0;
}

It works because nested is a member of container then transitive restriction of friendship doesn't apply. Before C++ 11, declaring nested as friend of container, that code won't compile because friendship isn't transitive.

Weird things

We'd assume we can always declare a nested class as friend of its container? Actually standard said (SO/IEC 14822:2003(E), 11.8):

A friend of a class is a function or class that is not a member of the class...

Then we shouldn't be able to declare nested as friend of container: in C++ 03 nested classes are class members (but standard explicitly said they have no access to container privates and also they can't be friends of container class). It seems there was no hope, fortunately most compilers allowed us to do so (regardless to what standard said).

What is the pros and cons between Enum and enum-based class implementation in Java?

In Java, Enum types act as a class that is declared with their unique name. It is pretty much like the any other class that is designed to create constant values. Recently, I also came across to an info that before the declaration of Enums in Java, an enum like class was created. Just like the article that was suggested on this question, it seems that previous to JVM 1.5, class based enums were widely used.

You can check this source: http://javarevisited.blogspot.com/2011/08/enum-in-java-example-tutorial.html

I think it is a very good explanation on Java Enums and Why they are created. The article claims 3 advantages for Enum:

1)Type Safety.

2)Unless the class was worked thoroughly, the Enum class was prone to printing problems. When coder wanted a string result to be returned, an primitive value was returned. To my experience, with some additions to the class, this is avoided. But question is, is it convenient for the coder.

3)Again, access was based on an instance of the class. Thus, coder cannot access to the Enum option directly. Coder must use the class name.

As a result: for convenience and code readability issues, Enums are a good choice. Plus, Enum Structure is similar to an individual classes that are nested within a carrier class. If coder wants to enhance the Enum Design and create their own style, they can turn back to the old manually coded class based system.

Alternative to nested class

class B
{
friend class A;
private:
B(int x1, int y1, int x2, int y2);
...
}

Why is enum class preferred over plain enum?

C++ has two kinds of enum:

  1. enum classes
  2. Plain enums

Here are a couple of examples on how to declare them:

 enum class Color { red, green, blue }; // enum class
enum Animal { dog, cat, bird, human }; // plain enum

What is the difference between the two?

  • enum classes - enumerator names are local to the enum and their values do not implicitly convert to other types (like another enum or int)

  • Plain enums - where enumerator names are in the same scope as the enum and their
    values implicitly convert to integers and other types

Example:

enum Color { red, green, blue };                    // plain enum 
enum Card { red_card, green_card, yellow_card }; // another plain enum
enum class Animal { dog, deer, cat, bird, human }; // enum class
enum class Mammal { kangaroo, deer, human }; // another enum class

void fun() {

// examples of bad use of plain enums:
Color color = Color::red;
Card card = Card::green_card;

int num = color; // no problem

if (color == Card::red_card) // no problem (bad)
cout << "bad" << endl;

if (card == Color::green) // no problem (bad)
cout << "bad" << endl;

// examples of good use of enum classes (safe)
Animal a = Animal::deer;
Mammal m = Mammal::deer;

int num2 = a; // error
if (m == a) // error (good)
cout << "bad" << endl;

if (a == Mammal::deer) // error (good)
cout << "bad" << endl;

}

Conclusion:

enum classes should be preferred because they cause fewer surprises that could potentially lead to bugs.

Class.Class vs Namespace.Class for top level general use class libraries?

I would say #1. Because when you bundle up lots of classes into one static class you do the same thing as a namespace is meant for. Which is why I would say it is best to let namespaces do that for you.

In that case you can also get rid of having to write "NP" in front of everything by adding using in case you want. I think you should either nest your namespaces so that they wont collide or use more describing namespace names than IO.

Most often the best practice is what Microsoft does and I have never seen them do #2

Is there a way to predeclare nested classes in C++?

In short, the answer is no.

But you should have looked first for a similar question...

EDIT: a possible workaround might be wrapping both classes in another class, and forward delcaring the nested classes inside the wrapper.

class Wrapper
{
public:

// Forward declarations
class FirstNested;
class SecondNested;

// First class
class First
{
public:
SecondNested* sested;
};

// Second class
class Second
{
public:
FirstNested* fested;
};
};

This way you'll have to implement Wrapper::A and Wrapper::B while still isolating them from whatever namespace you're imlpementing.



Related Topics



Leave a reply



Submit