More C++ Idioms/Inner Class
From Wikibooks, the open-content textbooks collection
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.
[edit] Also Known As
[edit] Motivation
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.
[edit] Solution and Sample Code
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.
[edit] Known Uses
[edit] Related Idioms
[edit] References
Thinking in C++ Vol 2 - Practical Programming --- by Bruce Eckel.