GotW #39

Home Blog Talks Books & Articles Training & Consulting

On the
blog
RSS feed November 4: Other Concurrency Sessions at PDC
November 3
: PDC'09: Tutorial & Panel
October 26: Hoare on Testing
October 23
: Deprecating export Considered for ISO C++0x

This is the original GotW problem and solution substantially as posted to Usenet. See the book More Exceptional C++ (Addison-Wesley, 2002) for the most current solution to this GotW issue. The solutions in the book have been revised and expanded since their initial appearance in GotW. The book versions also incorporate corrections, new material, and conformance to the final ANSI/ISO C++ standard.

Multiple Inheritance - Part III
Difficulty: 4 / 10

Overriding inherited virtual functions is easy -- as long as you're not trying to override a virtual function that has the same signature in two base classes. This can happen even when the base classes don't come from different vendors!

Problem

1. Consider the following two classes:

  class B1 {
  public:
    virtual int ReadBuf( const char* );
    // ...
  };

  class B2 {
  public:
    virtual int ReadBuf( const char* );
    // ...
  };

Both are clearly intended to be used as base classes but they are otherwise unrelated -- their ReadBuf functions are intended to do different things, and the classes come from different library vendors.

Demonstrate how to write a class D, publicly derived from both B1 and B2, which overrides both ReadBufs independently to do different things.

Solution

Demonstrate how to write a class D, publicly derived from both B1 and B2, which overrides both ReadBufs independently to do different things.

Here's the naive attempt that won't work:

  class D : public B1, public B2 {
  public:
    int ReadBuf( const char* );
        // overrides both B1::ReadBuf and B2::ReadBuf
  };

This overrides BOTH functions with the same implementation, whereas the point of the question was to override the two functions to do different things. You can't just "switch" behaviours inside this D::ReadBuf depending which way it gets called, either, because once you're inside D::ReadBuf there's no way of telling which base interface was used (if any).

Renaming Virtual Functions

If the two inherited functions had different signatures, there would be no problem: We would just override them independently as usual. The trick, then, is to somehow change the signature of at least one of the two inherited functions.

The way to change a base class function's signature is to create an intermediate class which derives from the base class, declares a new virtual function, and overrides the inherited version to call the new function:

  class D1 : public B1 {
  public:
    virtual int ReadBufB1( const char* p ) = 0;
    int ReadBuf( const char* p ) // override inherited
      { return ReadBufB1( p ); } // to call new func
  };

  class D2 : public B2 {
  public:
    virtual int ReadBufB2( const char* p ) = 0;
    int ReadBuf( const char* p ) // override inherited
      { return ReadBufB2( p ); } // to call new func
  };

D1 and D2 may also need to duplicate constructors of B1 and B2 so that D can invoke them, but that's it. D1 and D2 are abstract classes, so they do NOT need to duplicate any other B1/B2 functions or operators, such as assignment operators.

Now we can simply write:

  class D : public D1, public D2 {
  public:
    int ReadBufB1( const char* );
    int ReadBufB2( const char* );
  };

Derived classes only need to know that they must not further override ReadBuf itself.

Copyright 2009 Herb Sutter