//
// Include files
//

// x.h: sample header
// version 1

#include <iostream>
#include <ostream>
#include <list>

// none of A, B, C, D, E are templates
// Only A and C have virtual functions

#include "a.h"      // class A
#include "b.h"      // class B
#include "c.h"      // class C
#include "d.h"      // class D
#include "e.h"      // class E

class X : public A, private B
{
public:
        X( const C&);
    B   f(int, char*);
    C   f(int, C);
    C&  g(B);
    E   h(E);
    virtual std::ostream& print(std::ostream&) const;
private:
    std::list<C>    clist_;
    D               d_;
};

inline std::ostream& operator<<( std::ostream& os, const X& x)
{
    return x.print(os);
}


-- Remove <iostream> People automatically include <iostream>, even if
   input functions never used.

-- Replace <ostream> with <iosfwd> Parameters and return types only need
   to be forward declared. Because ostream is basic_ostream<char> template,
   it is not enough to declare.

-- Replace "e.h" with forward declaration of class E.

-- Leave "a.h" and "b.h": we need a full declaration of the base classes
   in case of inheritance. The compiler must know the size of bases,
   whether functions are virtual or not.

-- Leave "c.h" and "d.h": list<C> and D are private data members of X.


// x.h: sample header
// version 2

#include <iosfwd>
#include <list>

// none of A, B, C, D, E are templates
// Only A and C have virtual functions

#include "a.h"      // class A
#include "b.h"      // class B
#include "c.h"      // class C
#include "d.h"      // class D

class E;

class X : public A, private B
{
public:
        X( const C&);
    B   f(int, char*);
    C   f(int, C);
    C&  g(B);
    E   h(E);
    virtual std::ostream& print(std::ostream&) const;
private:
    std::list<C>    clist_;
    D               d_;
};

inline std::ostream& operator<<( std::ostream& os, const X& x)
{
    return x.print(os);
}



//
// Pimpl
//

// file x.h
class X
{
    // public and protected members
private:
    // pointer to forward declared class
    class XImpl *pimpl_;  // opaque pointer
};

// file x.cpp
struct XImpl   // not neccessary to declare as "class"
{
    // private members; fully hidden
    // can be changed at without
    // recompiling clients
};



Advantages:

-- Types mentioned only in a class's implementation need no longer be defined
   for client code, wich eliminate extra #includes and improve compile speed.

-- A class's implementation can be changed - private members can be added
   or removed - without replacing client code.

Costs:

-- Each construction/destruction must allocate/deallocate memory.

-- Each access of a hidden member can require at least one extra indirection.
   Sometimes from the hidden part we must access members in visible part:
   that we need another extra indirection.


// x.h: sample header
// version 3

#include <iosfwd>
#include "a.h"      // class A
#include "b.h"      // class B

class C;
class E;

class X : public A, private B
{
public:
        X( const C&);
    B   f(int, char*);
    C   f(int, C);
    C&  g(B);
    E   h(E);
    virtual std::ostream& print(std::ostream&) const;
private:
    // opaque pointer to forward-declared class   
    class XImpl *pimpl_;
};

inline std::ostream& operator<<( std::ostream& os, const X& x)
{
    return x.print(os);
}


// file x.cpp

#include "x.h"
#include "c.h"      // class C
#include "d.h"      // class D

struct XImpl
{
    std::list<C>    clist_;
    D               d_;
};



//
// Removing inheritance
//

// x.h: sample header
// version 4

#include <iosfwd>
#include "a.h"      // class A

class C;
class E;

class X : public A
{
public:
        X( const C&);
    B   f(int, char*);
    C   f(int, C);
    C&  g(B);
    E   h(E);
    virtual std::ostream& print(std::ostream&) const;
private:
    // opaque pointer to forward-declared class   
    class XImpl *pimpl_;
};

inline std::ostream& operator<<( std::ostream& os, const X& x)
{
    return x.print(os);
}

// file x.cpp

#include "x.h"
#include "b.h"      // class B
#include "c.h"      // class C
#include "d.h"      // class D

struct XImpl
{
    B               b_;
    std::list<C>    clist_;
    D               d_;
};