411 REFERENCE · Wikibooks
More C++ Idioms/Inner Class
Reference material by Wikibooks contributors. This retains its source identity and is not 411 news reporting.
Inner Class
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
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.
Solution and Sample Code
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) {}
Derived(Derived const&) : base1_obj(this), base2_obj(this) {}
Derived(Derived&&) : base1_obj(this), base2_obj(this) {}
Derived& operator=(Derived const&) { return *this; }
Derived& operator=(Derived&&) { return *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
Related Idioms
Interface Class
Capability Query
References
Thinking in C++ Vol 2 - Practical Programming --- by Bruce Eckel.
ja:More C++ Idioms/内部クラス(Inner Class)