More C++ Idioms/Inner Class

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

Inner Class[edit]

Intent[edit]

  • 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.

#include <iostream>
class Base1  /// Provided by Moon
    {
 public:
  virtual int open() = 0;
  /* virtual */ ~Base1() {}  // No polymorphic deletion allowed
};
 
class Base2  /// Provided by Jupitor
    {
 public:
  virtual int open() = 0;
  /* virtual */ ~Base2() {}  // No polymorphic deletion allowed
};
 
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) {}
    int open() override { 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) {}
    int open() override { return parent_->base2_open(); }
 
   private:
    Derived* parent_;
  } base2_obj;  // Note member object here
 
  int base1_open() { return 111; }  /// implement
  int base2_open() { return 222; }  /// implement
 
 public:
 
  Derived() : base1_obj(this), base2_obj(this) {}
 
  operator Base1&() { return base1_obj; }  /// convert to Base1&
  operator Base2&() { return base2_obj; }  /// convert to Base2&
};                                         /// class Derived
 
int base1_open(Base1& b1) { return b1.open(); }
 
int base2_open(Base2& b2) { return b2.open(); }
 
int main(void) {
  Derived d;
  std::cout << base1_open(d) << std::endl;  // Like upcasting in inheritance.
  std::cout << base2_open(d) << std::endl;  // 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.