Use and misuse of C++ nested classes

| 2 Comments

I like nested classes in C++. They allow a nicely fine grained approach to naming. Where a class may need to be called CRegistryKeyIterator if declared at namespace level it can be called Iterator if nested inside the CRegistryKey class. The problem is I think I tend to overuse the feature...

I'm restructuring some code at present. This involves decoupling the IO Completion Port code for async IO from the socket server code in The Server Framework so that it can be used for file IO as well as network IO. The socket server had an IOPool class nested inside it. It probably shouldn't have been structured that way.

I guess it all comes down to how 'free standing' a concept is. The IOPool class isn't really dependant on the CSocketServer class in any way. The socket server uses the IOPool but other people may wish to use the IOPool without using the socket server... Whereas with the CRegistryKeyIterator it's less likely that you'd use the iterator without the key... I'd noticed a slight smell when using the IOPool how when I wanted to provide a derived IOPool class that provided debug information on IO pool events I had to include all of the socket server stuff. The derived IO pool didn't need to know or care about the socket server yet the nested nature of the classes required it to pull in the socket server header to get access to the IO pool.

Likewise the CIOBuffer has a nested Allocator class, some parts of the code just care about the allocator and never need to access the buffer class. They'd get by with a header that defined the Allocator and simply forward declared the buffer. Due to the nested nature of the class they can't do that and become dependant on the buffer and changes to it even though they shouldn't be.

As these concepts are moved from the socket tools library to the new library these knots are being untangled. I can't help thinking that they're the kind of knots that I'd never have tied if I'd been developing the code test first; they're the kind of things that make it hard to test the code because writing a mock object to replace one of the concepts is out of the question.

I still think nested classes are useful, but I think I should be more careful about when I use them...

2 Comments

Iterators are good examples of where nested classes are appropriate, I think, and so are nodes in a tree. A class called Node() isn't a very good idea even within your own namespace since the odds of having multiple tree classes (and therefore multiple node types) are fairly high, but a nested Node() class solves the problem nicely.

Typically, the data stored in a tree node is non-generic, that is application specific. I think you're right to say that its the dependencies that matter. That the IOPool nested class doesn't depend on the encapsulating class and could feasibly be used elsewhere are both good signs that you should consider other encapsulation options.

p.s. I know this post is four years old, but it was relevant to my interests. Thank you for your thoughts.

Agree, and I've no problem with you commenting on old posts :)

Leave a comment