Solution

I l @ ve RuBoard

graphics/bulb.gif
  class D : public B1, public B2   {   string DoName() { return "D";  }   };  

Demonstrate the best way you can find to "work around" not using multiple inheritance by writing an equivalent (or as near as possible) class D without using MI . How would you get the same effect and usability for D with as little change as possible to syntax in the calling code?

There are a few strategies, each with its weaknesses, but here's one that gets quite close.

 class D : public B1 { public:   class D2 : public B2   {   public:     void   Set ( D* d ) { d_ = d; }   private:     string DoName();     D* d_;   } d2_;   D()                 { d2_.Set( this ); }   D( const D& other ) : B1( other ), d2_( other.d2_ )                       { d2_.Set( this ); }   D& operator=( const D& other )                       {                         B1::operator=( other );                         d2_ = other.d2_;                         return *this;                       }   operator B2&()      { return d2_; }   B2& AsB2()          { return d2_; } private:   string DoName()     { return "D"; } }; string D::D2::DoName(){ return d_->DoName(); } 

Before reading on, take a moment to consider the code and think about the purpose of each class or function.

Drawbacks

The workaround does a pretty good job of implementing MI, automates most of MI's behavior, and allows all of MI's usability, as long as you rely on coding discipline to fill in the parts that are not completely automated. In particular, here are some drawbacks of this workaround that show which parts of the MI feature are not completely automated.

  • Providing operator B2&() arguably gives references special (inconsistent) treatment over pointers.

  • Calling code has to invoke D::AsB2() explicitly to use a D as a B2 (in the test harness, this means changing " B2* pb2 = &d; " to " B2* pb2 = &d . AsB2(); ").

  • A dynamic_cast from D* to B2* still doesn't work (it's possible to work around this if you're willing to use the preprocessor to redefine dynamic_cast calls, but that's an extreme solution).

Interestingly, you may have observed that the D object layout in memory is similar to what multiple inheritance would give. That's because we're trying to simulate MI, without all the syntactic sugar and convenience that built-in language support would provide.

You may not need MI often, but when you need it, you really need it. This Item is intended to demonstrate that having the required language support for this kind of useful feature is far better than trying to roll your own, even if you can duplicate the functionality exactly through a combination of other features and coding discipline.

I l @ ve RuBoard


More Exceptional C++
More Exceptional C++: 40 New Engineering Puzzles, Programming Problems, and Solutions
ISBN: 020170434X
EAN: 2147483647
Year: 2001
Pages: 118
Authors: Herb Sutter

flylib.com © 2008-2017.
If you may any questions please contact us: flylib@qtcs.net