Article Discussion
Multiple Inheritance and Interfaces
Summary: Scott Meyers, C++ expert and author of numerous books including Effective C++, talks with Bill Venners about multiple inheritance and interfaces.
15 posts.
The ability to add new comments in this discussion is temporarily disabled.
Most recent reply: October 4, 2005 2:04 AM by Lee
    Bill
     
    Posts: 409 / Nickname: bv / Registered: January 17, 2002 4:28 PM
    Multiple Inheritance and Interfaces
    December 15, 2002 7:22 PM      
    Artima.com has published Part I of an interview with Scott Meyers in which he discusses how his view of multiple inheritance has changed with time, describes the C++ community's take on Java's interface, and points out a schism of focus between the C++ and other prominent development communities.---xj40dkcfea73---Artima.com has published Part I of an interview with Scott Meyers in which he discusses how his view of multiple inheritance has changed with time, describes the C++ community's take on Java's interface, and points out a schism of focus between the C++ and other prominent development communities.

    http://www.artima.com/intv/abcs.html

    Here's an excerpt:

    I happen to think one of the contributions of Java was getting rid of some of the baggage that comes with multiple inheritance in C++. I'm guessing, since I'm not a Java guy, that the creators of Java looked at the multiple inheritance model of C++. They said, "This has some good things, but it has some baggage too. So we're going to try to find a way to have the good stuff and throw away the baggage." That's essentially what an interface is. It is an abstract base class that doesn't have any of the things that tend to give rise to trouble in C++, because it doesn't have any data. I think that's an interesting idea. So I think interfaces are an interesting idea.

    What do you think of Scott's comments? In particular, what do you think of Scott's take on multiple inheritance and interface classes in C++? Also, do you think the C++ community erred in focusing on exceptions, templates, and the STL instead of building large libraries like the Java community?
    • Andre
       
      Posts: 1 / Nickname: andrem / Registered: December 15, 2002 4:46 PM
      Re: Multiple Inheritance and Interfaces
      December 15, 2002 9:55 PM      
      Clemens Szyperski in his book "Component Software" (p. 96) succinctly summarized the problem as consisting of:
      1. Implementation Inheritance (subclassing)
      2. Interface Inheritance (subtyping)

      Interface Inheritance obviously avoids the whitebox "diamond problem" issues with Implementation Inheritance, but still shares general inheritance issues of name clashes between superclasses that contain an identical method name.

      I find this formal distinction highly useful and precise. Java actually *does* have multiple inheritance - rather than being implementation inheritance it is interface inheritance. C++ does not have a clear distinction between interface and inheritance.
    • Jason
       
      Posts: 1 / Nickname: jasonc / Registered: December 16, 2002 2:48 AM
      Re: Multiple Inheritance and Interfaces
      December 16, 2002 8:10 AM      
      I think that there maybe more to the apparent lack of interest in interfaces in the C++ community than Scott describes.

      In C++, the style of interface programming used in Java (and C#) is generally less used (less useful?). Templates are typcally used instead.

      As I understand it, interfaces are a formal statement of 'capability' or of conformance to a particular design idiom. For example, in C# the IComparable interface (Comparable in Java, I think) is used to specify that a class can be ordered.

      In C++ you would be unlikely to write code using this approach. Instead you would typically use a templated method that relies either on a class's < operator for 'natural' ordering or on some functor object to provide custom ordering. (The std::sort algorithm provides an obvious example).
    • Vincent
       
      Posts: 40 / Nickname: vincent / Registered: November 13, 2002 7:25 AM
      Re: Multiple Inheritance and Interfaces
      December 18, 2002 8:47 AM      
      Looks like another good interview with one of programming's 'movers and shakers' but please, make sure you spell out all the abbreviations the first time that you use them. Here in the UK, an ISA is a common financial instrument. I had to look up its programming context to properly follow the interview.

      Vince.
      • Matt
         
        Posts: 62 / Nickname: matt / Registered: February 6, 2002 7:27 AM
        Re: Multiple Inheritance and Interfaces
        December 18, 2002 2:17 PM      
        Actually, I must admit I was a little confused when I first saw ISA as I perused (yes, perused) the interview (I was thinking of the PC bus architecture). In this context, it wasn't even an acronym, it conveying the "is-a" concept.

        I think Scott hit on a fascinating point at the end of this interview. I wonder to what extent the libraries are more important than the language. Microsoft seems to think (ostensibly) that they are in their promotion of .Net, where they are trying (again, ostensibly) to sell the idea of language agnosticism.
      • Bill
         
        Posts: 409 / Nickname: bv / Registered: January 17, 2002 4:28 PM
        Re: Multiple Inheritance and Interfaces
        December 18, 2002 11:05 PM      
        > Looks like another good interview with one of
        > programming's 'movers and shakers' but please, make
        > sure you spell out all the abbreviations the first time
        > that you use them. Here in the UK, an ISA is a common
        > financial instrument. I had to look up its programming
        > context to properly follow the interview.
        >
        Sorry Vince. I do try to spell out the abreviations the first time I use them, but I missed ISA. I mean I missed ISA (short for "is a"). I'll fix that tonight when I get a direct connection to the internet. The real problem is that I ran out of time last week and my editor didn't get a chance to fix my mistakes. I keep thinking I'm going to get ahead of schedule, but somehow it never happens. Either it's a law of the universe, or at least a law of my personality.

        Nevertheless, please do post or email me if something is confusing in an article. One nice thing about publishing on the web is that mistakes can be corrected, confusing text can be clarified.
    • Arnold
       
      Posts: 6 / Nickname: arnoldd / Registered: December 2, 2002 8:25 AM
      Interfaces vs. ABC
      January 6, 2003 4:12 PM      
      There is a seldom-mentioned difference between data-less, abstract base classes (ABC in C++ or Java) and Java interfaces.

      If I inherit an ABC my decendents or I must implement its methods. Not so if I inherit an interface. Implementations may be supplied by my ancestors as well as my decendents.

      Given this, I find it useful to think of adding and interface to a class as "tagging" or "describing" rather than "inheritance", "specialisation" or "extension".

      The flavour is brought out when you consider that in Java one can non-intrusively tag an existing implementation, C, with an new interface, I, by creating a class that extends C and implements I. No delegation required.
    • Arnold
       
      Posts: 6 / Nickname: arnoldd / Registered: December 2, 2002 8:25 AM
      Interfaces vs. ABC
      January 6, 2003 4:22 PM      
      There is a seldom-mentioned difference between data-less, abstract base classes (ABC in C++ or Java) and Java interfaces.

      If I inherit an ABC my decendents or I must implement its methods. Not so if I inherit an interface. Implementations may be supplied by my ancestors as well as my decendents.

      Given this, I find it useful to think of adding and interface to a class as "tagging" or "describing" rather than "inheritance", "specialisation" or "extension".

      You could say this is just part of Java'a solution to the diamond-shaped inheritance problem. But the real flavour is brought out when you consider that in Java one can non-intrusively tag an existing implementation, C, with an new interface, I, by creating a class that extends C and implements I. No delegation required.
      • Chris
         
        Posts: 1 / Nickname: chrism / Registered: January 6, 2003 8:30 PM
        Re: Interfaces vs. ABC
        January 7, 2003 1:41 AM      
        In Eiffel, when you implement an inherited method, you can also rename it. If two ancestor classes or interfaces have methods which happen to have the same name, they can still be implemented by different methods of the child class.

        One great result is that you can implement the same listener interface several times, with different methods for different event sources. This seems like a cleaner solution than anonymous subclasses.

        It relies on a different dispatch mechanism. In Java, the method table is an attribute of an object. This is possible because the method table of an ancestor class is always a prefix of the method table of the inheriting class. That is why the dispatch method is different, and less efficient, for a call to an interface reference.

        It is more correct to understand the method table as an attribute of a reference. Casting a reference to a new type means making a new reference to the same object but with a different method table. Then the name of a method only need exist at compile time.

        C# copied Java in this - it's derivative nature is shown best by the fact that it inherits all of Java's weaknesses.
        • Bill
           
          Posts: 409 / Nickname: bv / Registered: January 17, 2002 4:28 PM
          Re: Interfaces vs. ABC
          January 11, 2003 1:24 AM      
          > In Eiffel, when you implement an inherited method, you can
          > also rename it. If two ancestor classes or interfaces have
          > methods which happen to have the same name, they can still
          > be implemented by different methods of the child class.
          >
          I had heard this about Eiffel.

          > One great result is that you can implement the same
          > listener interface several times, with different methods
          > for different event sources. This seems like a cleaner
          > solution than anonymous subclasses.
          >
          I'm not sure it would be easier to understand to understand a class that implemented the same interface several times and changed the names of the methods. Seems like you'd always have to do an extra step of figuring out what the name change has been.

          > It relies on a different dispatch mechanism. In Java, the
          > method table is an attribute of an object. This is
          > possible because the method table of an ancestor class is
          > always a prefix of the method table of the inheriting
          > class. That is why the dispatch method is different, and
          > less efficient, for a call to an interface reference.
          >
          I'd say the method table is an attribute of the class, not the object.

          > It is more correct to understand the method table as an
          > attribute of a reference. Casting a reference to a new
          > type means making a new reference to the same object but
          > with a different method table. Then the name of a method
          > only need exist at compile time.
          >
          Can you clarify what you mean by this?

          > C# copied Java in this - it's derivative nature is shown
          > best by the fact that it inherits all of Java's
          > weaknesses.

          Not that this is much of a weakness, but Ken Arnold always complains that Java's Cloneable interface is mispelled. It should be Clonable. I was rather amused to discover that the corresponding interface in C# is ICloneable. A Jini guy I mentioned this to said it gives one the impression that someone copied Jimmy's homework, including the mistakes.
    • Rick
       
      Posts: 1 / Nickname: rickw / Registered: September 8, 2003 1:40 PM
      Re: Multiple Inheritance and Interfaces
      September 8, 2003 6:01 PM      
      I've found small utility classes useful with multiple inheritance in C++. An example of an untility class I'll inherite from even if a class already has a base is my compare helper class:



      template<class DERIVED, class COMPARED = DERIVED>
      struct CompareHelper
      {
      bool operator ==(const COMPARED &d2) const
      {
      return (static_cast<const DERIVED *>(this)->Compare(d2))==0;
      }
      bool operator >=(const COMPARED &d2) const
      {
      return (static_cast<const DERIVED *>(this)->Compare(d2))>=0;
      }
      bool operator <=(const COMPARED &d2) const
      {
      return (static_cast<const DERIVED *>(this)->Compare(d2))<=0;
      }
      bool operator !=(const COMPARED &d2) const
      {
      return !((*this) == d2);
      }
      bool operator <(const COMPARED &d2) const
      {
      return !((*this) >= d2);
      }
      bool operator >(const COMPARED &d2) const
      {
      return !((*this) <= d2);
      }
      };


      I'll then inherite from this class for each type I want to overload the standard compare operators for.



      class my_class
      // get compare operators for my class
      : public CompareHelper<my_class>
      // get compare operators for long type
      , public CompareHelper<my_class, long>
      {
      //<<Define privte here...>>
      public:
      //<<Define rest of public here...>>

      int Compare(const my_class &rhs) const;
      int Compare(long rhs) const;
      };

      int main()
      {
      my_class c1;
      my_class c2;
      long l = 9;

      if(c1 > c2)
      {
      //Put greater then code here...
      }

      if(c1 == l)
      {
      //Put equal to code here...
      }

      return 0;

      }


      Note: the compare helper class is not an ABC. This is to avoid the overhead of the virtual call to Compare().
    • Joseph
       
      Posts: 2 / Nickname: jcoffland / Registered: October 1, 2003 7:39 AM
      Re: Multiple Inheritance and Interfaces
      October 1, 2003 0:11 PM      
      There is one problem I run into repeatedly in trying to use the Java
      interface paradigm in C++.

      A C++ class with only pure virtual member functions and no data
      doesn't behave at all like a Java interface in at least one important
      aspect.

      Perhaps an example will explain it best. First I create a C++ style
      "interface" class A. Then I create an implementation of A called
      AImpl.

      class A {
      public:
      void function1() = 0;
      void function2() = 0;
      };

      class AImpl : public A {
      public:
      void function1() {// Do something}
      void function2() {// Do something}
      };


      Now I would like to add some functionality to A with a new "interface"
      B. I also naturally want to reuse the code I wrote in AImpl. In Java
      this is no problem. I just make B extend A then create a new class
      BImpl which extends AImpl and implements B. Java doesn't care that
      there is an A in the inheritance tree above both B and AImpl. C++
      does.

      If I make BImpl inherit from both B and AImpl then I have two copies
      of A instead of one. A has no data so there is not a big storage
      cost, but it is now ambiguous which version of A I am calling through
      B as implemented by BImpl.


      class B : public A {
      public:
      void function3() = 0;
      };

      // In Java this would be 'extend AImpl implement B'
      class BImpl : public AImpl, public B {
      public:
      void function3() {// Do something}
      };


      Wouldn't it be wonderful if the C++ compiler would realize that one
      version of A is still pure virtual and not implemented and the other
      version is the implementation? Java does this automatically.


      int main(int argc, char *argv[]) {
      B *b = new BImpl();

      b->function1(); // This is ambiguous.
      b->function2(); // This is ambiguous.
      b->function3(); // This is of course not!

      return 0;
      }


      Of course I can just map my BImpl functions down to AImpl but this is
      a lot of extra typing and if I where to change A I would have to
      update BImpl aswell! We then miss the whole point of inheritance.


      // An example of mapping BImpl up to AImpl
      class BImpl : public AImpl, public B {
      public:
      void function1() {AImpl::function1();}
      void function2() {AImpl::function2();}
      void function3() {// Do something}
      };


      With out this feature is seems that C++ will never be able to fully
      reap the benefits of Java interfaces. Maybe one day the standards
      committee will be able to wade through all the bureaucracy and add
      a 'interface' keyword to C++.

      Joseph Coffland
    • Joseph
       
      Posts: 2 / Nickname: jcoffland / Registered: October 1, 2003 7:39 AM
      Re: Multiple Inheritance and Interfaces
      October 1, 2003 0:48 PM      
      Funny how things work. Minutes after I posted the message above I found a solution to my problem. If you use virtual inheritance whenever inheriting from a C++ style "interface" you no longer have the problem! There is a good explanation of how to use virtual inheritance here: http://www.parashift.com/c++-faq-lite/multiple-inheritance.html#faq-25.9

      Joseph Coffland
      • Kris
         
        Posts: 1 / Nickname: kdekeyser / Registered: January 15, 2004 10:18 PM
        Re: Multiple Inheritance and Interfaces
        January 16, 2004 3:30 AM      
        Yep, indeed. That is the proper solution and a good case to show why multiple inheritance may be needed.
        It occurs to me that- strange enough - in order to implement Java's Interface mechanism in C++, we have to use virtual multiple inheritance.
        A problem which I am facing is to port a utility library which uses this scheme extensively to a build environment that does not allow to use virtual inheritance. I'm now down to the "reimplement and delegate" option :-(((
        Are there any other design solutions to solve the A-AImpl-B-BImpl diamond in C++ without virtual inheritance and without the reimplement-in-BImpl-and-delegate-to-AImpl solution?
        • Rastislav
           
          Posts: 1 / Nickname: galia / Registered: March 9, 2005 11:46 PM
          Re: Multiple Inheritance and Interfaces
          March 10, 2005 4:56 AM      
          I would like to stress the importance of using dynamic_cast to navigate between interfaces of the same object.

          Having declarations

          //////////
          struct IA
          {
          virtual void fnc1() = 0;
          };

          strcut IB
          {
          virtual void fnc2() = 0;
          };

          class Impl : public IA, public IB
          {
          void fnc1() { std::cout << "Impl::fnc1()" << std::endl; }
          void fnc2() { std::cout << "Impl::fnc2()" << std::endl; }
          };

          Impl obj;
          IA* ia = &obj;
          ////////

          one should not use

          IB *ib = (IB*)ia;

          or

          IB* ib = static_cast<IB*>(ia)

          since without an aid from RTTI interface 'ia' is not able to determine the layout of the object 'obj'. Correct usage is

          IB* ib = dynamic_cast<IB*>(ia);
          • Lee
             
            Posts: 3 / Nickname: lpowell / Registered: October 3, 2005 8:06 PM
            Re: Multiple Inheritance and Interfaces
            October 4, 2005 2:04 AM      
            In my view, the need to use dynamic_cast (and the RTTI overhead it requires) with MI class hierarchies makes widespread use of inherited C++ interface classes undesirable. It's simpler and more efficient to use interface containment in an object (by declaring an explicit pointer to each interface class). Yes, you then have to use new and delete on each pointer, but that's what your constructors and destructors are there for...