Advertisement

Organising classes

Started by June 28, 2000 01:17 AM
0 comments, last by gimp 24 years, 5 months ago
For a while now I have used classes to hide implementation code from the calling class, unfortunitilu if the class has private data this is of a type that is specific to the implementation then the calling class needed to include that the header too. For example I have a Network class that hids a bunch of winsock code. Some of the class private data is the socket , sockaddr_in etc. Due to this the calling code need to have this included. Recently I''ve been thinking about going back to using file scope globals in the calsses CPP file for the classes ''internal stuff''. Is this a terribly bad practice? Gimp
Chris Brodie
In C++, there is something known as the Pimpl Idiom ("pipml" pronounced just like those ugly blobs commonly seen on the faces of teenagers). If I understand your purpose correctly, I think this is what you're looking for.

Let's say we have a class A with two private members, both instatiations of a couple other classes (B and C). The typical "a.h" header file (listing 1) must include both of the other header files ("b.h" and "c.h", and anything that includes "a.h" is now forced to include all three.

Listing 2 is the first good fix; change the private members to pointers, and move the include statements into the .cpp file. You have to do a little memory management, but you've reduced the header compilation dependencies. You replace the header includes with forward declarations, but it's still better than the first attempt.

Now, try something different. Separate out A's private data into a separate struct called AImpl, and make it a private struct of A. Declare a pointer in the "a.h" header, but define the struct only in the "a.cpp" file. Talk about privacy and hiding! (Listing 3)


                    // ---- LISTING 1 ----  //file a.h#include "b.h" #include "c.h"   class A {  B b;  C c;};  //file a.cpp#include "a.h"   A::A() { }      // ---- LISTING 2 ----  //file a.hclass B;class C;  class A {  B* pb;  C* pc;};  //file a.cpp#include "a.h" #include "b.h" #include "c.h"   A::A() : pb(new B), pc(new C) { }A::~A() { delete pb; delete pc; }      // ---- LISTING 3 ----  //file a.hclass A {  struct AImpl* pimpl;};  //file a.cpp#include "a.h" #include "b.h" #include "c.h"   struct A::AImpl {  //what was private in A is now put here  B b;  C c;};  A::A() : pimpl(new AImpl) { }A::~A() { delete pimpl; }                


Both listing 2 and 3 are better than listing 1 in terms of reducing compiler dependencies and therefore compile time. Listing 3 is really good at hiding private data and implementation details.

Both listing 2 and 3 come with a price: memory allocation/deallocation, and an extra pointer indirection. The latter is a very inexpensive operation and is usually worthwhile. The former can be pricey if objects are created and deleted regularly. Fortunately, this is typical memory management details and there are many solutions.

Check out Exceptional C++ by Herb Sutter; get the book, or check it online at http://www.peerdirect.com/Resources/ . It has a decent section on the Pimpl Idiom (item #28) including info on a "Fast Pimpl" idea. Your favorite search engine should also come up with some other good pages on this technique.


---- --- -- -
Blue programmer needs food badly. Blue programmer is about to die!

Edited by - mossmoss on June 28, 2000 1:17:36 PM

This topic is closed to new replies.

Advertisement