More C++ Idioms/Inner Class

From Wikibooks, open books for an open world
Jump to: navigation, search

Contents

[edit]

Inner Class

[edit] Intent

  • Implementing multiple interfaces without multiple inheritance and yet provide natural looking up-casting.
  • Provide multiple implementations of the same interface in a single abstraction.

Also Known As [edit]

Motivation [edit]

Signature of a virtual function in two independent interfaces provided by two independent class libraries may collide. It is a problem especially when a single class has to implement both the colliding functions in different ways depending upon the interface you consider. For example,

class Base1 /// Provided by Moon
{
  public:
      virtual int open (int) = 0;
      /* virtual */ ~Base1() {}  // No polymorphic deletion allowed
};
 
class Base2 /// Provided by Jupitor
{
  public:
      virtual int open (int) = 0;
      /* virtual */ ~Base2() {}  // No polymorphic deletion allowed
};
 
class Derived : public Base1, public Base2
{
  public:
    virtual int open (int i)
    {
      // Call from which base class?
      return 0;
    }
    /* virtual */ ~Derived () {}
};

The inner class idiom can help solve this problem.

Solution and Sample Code [edit]

Leaving the interface classes, Base1 and Base2 unchanged we can implement the Derived class as follows.

class Derived // Note no inheritance
{
  class Base1_Impl;
  friend class Base1_Impl;
  class Base1_Impl: public Base1 // Note public inheritance
  {
     public:
       Base1_Impl (Derived * p) : parent_ (p) {}
       virtual int open (int) 
       {
          return parent_->base1_open ();
       }
     private:
       Derived * parent_;
  } base1_obj;   // Note member object here.
 
  class Base2_Impl;
  friend class Base2_Impl;
  class Base2_Impl: public Base2 // Note public inheritance
  {
     public:
       Base2_Impl (Derived * p) : parent_ (p) {}
       virtual int open (int) 
       {
          return parent_->base2_open ();
       }
     private:
       Derived * parent_;
  } base2_obj; // Note member object here
 
  int base1_open () {}
  int base2_open () {}
 
  public:
 
    Derived () : base1_obj (this), base2_obj(this) {}
 
    operator Base1 & () { return base1_obj; }
    operator Base2 & () { return base2_obj; }
};
 
int base1_open (Base1 & b1)
{
  return b1.open (1);
}
 
int base2_open (Base2 & b2)
{
  return b2.open (2);
}
 
int main (void)
{
  Derived d;
  base1_open (d);  // Like upcasting in inheritance.
  base2_open (d);  // Like upcasting in inheritance.
}

Note the use of conversion operators in class Derived. (Derived class is really not a derived class!) The conversion operators allow conversion of Derived to Base1 even though they don't share inheritance relationship themselves! Use of member objects base1_obj and base2_obj eliminates the concern of object lifetime. Lifetime of member objects is same as that of the Derived object.

Known Uses [edit]

Related Idioms [edit]

References [edit]

Thinking in C++ Vol 2 - Practical Programming --- by Bruce Eckel.