Question

Once and for all I want to clearify this somewhat subjective and argumentative area of programming.

Multiple inheritnace

In my current working enviornment I have C++ developers and C# developers which come from totaly different worlds and thus have different opinions on programming layout.

Now being a C# and Java developer myself I've never come to the state where I actually needed to use Multiple inheritance, but C++ developers around me tend to through out comments like "That would be a perfect way to use Multiple inheritance"

Of course I tend to dissagree.

My question

In what scenario would multiple inheritance be a better or easier way to solve a problem than use of Interfaces and just simple inheritance?

And can you always solve the multiple inheritance benefits by using ie member variables instead?

Was it helpful?

Solution

Except that you seem to be proposing to use multiple inheritance.

Inheritance has different uses. Public inheritance specifies an IS-A relationship, and inheritance with any access modifiers can provide behavior to the child class, which can then be overridden. In C# and Java (which I'm more familiar with), interfaces provide the IS-A interface without behavior. (In C++, you can do an interface by defining a class with no data members and all functions pure virtual.)

So, if you provide an interface, and put in a member variable to provide behavior, you're doing full C++-style inheritance. You're just breaking it up into components and taking more trouble to do it. Describing this as solving the multiple inheritance problem is disingenuous, since doing that with two interfaces and two member variables is multiple inheritance. It gets even more awkward if you're going to modify the behavior in a polymorphic fashion, since either you need parallel inheritance hierarchies or a more complicated dispatch to the member variable.

There are problems with C++ multiple inheritance, true, but there are also uses that don't present problems. The first good use I saw was "mix-ins": small classes to add certain behaviors. There's plenty of interfaces to these in Java, but you're expected to handle the behavior by yourself.

If you're interested in learning more about multiple inheritance, I'd suggest trying a language, like Common Lisp, where multiple inheritance is routinely used and nobody has problems with it.

OTHER TIPS

Multiple inheritance is a nice to have feature. Those, who used to write code with MI, naturally attack the problem from the different angle. However, what is "easier" for one programmer, might be "harder" for another.
For C++ specific info about MI see Herb Sutter's article:

Combining Modules/Libraries

Many classes are designed to be base classes; that is, to use them you are intended to inherit from them. The natural consequence: What if you want to write a class that extends two libraries, and you are required to inherit from a class in each? Because you usually don't have the option of changing the library code (if you purchased the library from a third-party vendor, or it is a module produced by another project team inside your company), MI is necessary.

Ease of (Polymorphic) Use

There are examples where allowing MI greatly simplifies using the same object polymorphically in different ways. One good example is found in C++PL3 14.2.2 which demonstrates an MI-based design for exception classes, where a most-derived exception class may have a polymorphic IS-A relationship with multiple direct base classes.

Have a look at this SO topic: Should C# include multiple inheritance?

Having used two languages extensively where one has (Python) multiple inheritance and one doesn't (C#) I can honestly say that I have never used or had the need for MI.

I tend to prefer interfaces + composition in most cases over both normal inheritance and/or multiple inheritance. Sure there are some cases where you really need inheritance, especially in C# - but MI? Never.

Edit: It would be easier to answer if you could show an example where your C++ programmers advocated MI and you didn't.

Edit: Thinking about it a bit more I realized that the difference between a statically typed language like C# or C++ and a duck-typed language like Python might be a good reason I never had to use MI in Python, just due to it's dynamic nature. But still, I have not had the need for it in C# ever.

I haven't used multiple inheritance a lot, but sometimes, it comes handy because it just performs well and reduces the maintenance costs. C++ FAQ Lite answers have some good scenerios.

#include <afx.h>      
#include <afxtempl.h>
#include "StdAfx.h"  

class Employee
{
    char name[30];
public:
    Employee() {}
    Employee( const char* nm )
    {
        strcpy( name, nm ) ;
    }
    char* getName() const;
    virtual double computePay() const = 0;
    virtual ~Employee() 
    {
    }
};

class WageEmployee : public virtual Employee
{
    double wage;
    double hours;
public:
    WageEmployee( const char* nm );
    void setWage(  double wg  ){wage  = wg; }
    void setHours( double hrs ){hours = hrs;}

    double computePay() const       /* Implicitly virtual */
    {
        return wage * hours;
    }
};

class SalesPerson : public WageEmployee
{
      double commission; 
      double salesMade;
public:
      SalesPerson( const char* nm );
      void setCommission( double comm )
      {
          commission = comm;
      }
      void setSales( double sales )
      {
          salesMade = sales;
      }

      double computePay() const     /* Implicitly virtual */
      {
          return WageEmployee::computePay() + commission * salesMade;
      }
};

class Manager : public virtual Employee
{
    double weeklySalary; 
public:
    Manager( const char* nm );

    void setSalary( double salary ){weeklySalary = salary; }

    double computePay() const           /* Implicitly virtual */
    {
        return weeklySalary;
    }
};

class SalesManager : public SalesPerson, public Manager
{
public:
    SalesManager::SalesManager( const char* nm )
                :Employee(nm),Manager(nm),SalesPerson(nm)
    {
    }

    double computePay() const       /* Implicitly virtual */
    {
        return Manager::computePay() + SalesPerson::computePay();
    }
};

typedef CTypedPtrList < CPtrList, Employee* > CEmployeeList;

class EmployeeList
{
    CEmployeeList List;
public:
    EmployeeList() {}
    CEmployeeList& GetElements() { return List; }

    void Add( Employee* newEmp )
    {
        List.AddTail( newEmp ) ;        
    }

    virtual ~EmployeeList() 
    {
        POSITION pos = List.GetHeadPosition() ;
        while ( pos != NULL ) 
        {
            delete List.GetNext(pos) ;
        }
        List.RemoveAll() ;
    }
};


WageEmployee::WageEmployee( const char* nm )
            :Employee( nm )
{
    wage  = 0.0;
    hours = 0.0;
}

SalesPerson::SalesPerson( const char* nm )
           :WageEmployee( nm )
{
    commission = 0.0;
    salesMade  = 0.0;
}

Manager::Manager( const char* nm )
       :Employee( nm )
{
    weeklySalary = 0.0;
}

void main( int argc, char *argv[] )
{
    int ans = 0 ;

EmployeeList  myDept;
WageEmployee* wagePtr;
SalesPerson*  salePtr;
Manager*      mgrPtr;
SalesManager* smPtr;

wagePtr = new WageEmployee("Alan Wage");
salePtr = new SalesPerson("Brian Sale");
mgrPtr  = new Manager("Clive Manager");
smPtr   = new SalesManager("David SaleManager");

wagePtr->setWage( 10.0 );
wagePtr->setHours( 35.0 );

salePtr->setWage( 5.0 );
salePtr->setHours( 35.0 );
salePtr->setCommission( 0.05 );
salePtr->setSales( 100.0 );

mgrPtr->setSalary( 600.0 ) ;

smPtr->setSalary( 670.0 ) ;
smPtr->setCommission( 0.01 );
smPtr->setSales( 100.0 );


myDept.Add( wagePtr );
myDept.Add( salePtr );
myDept.Add( mgrPtr );
myDept.Add( smPtr );

double payroll = 0.0 ;
Employee* person ;
POSITION pos = myDept.GetElements().GetHeadPosition() ;
while ( pos != NULL )
{
    person = (Employee* )myDept.GetElements().GetNext(pos) ;
    payroll += person->computePay();
}

ExitProcess( ans ) ;
}

Above is Visual C++ with a multiple inheritance.

using System;
using System.IO;
using System.Collections;
using System.Collections.Generic;

namespace ConsolePoly
{
   interface Employee
   {
       string Name { get; set; }
       double computePay();
   }

class WageEmployee : Employee 
{
    private string iName = "";
    virtual public string Name { get { return iName; } set { iName = value; } }

    public double wage { get; set; }
    public double hours { get; set; }

    public WageEmployee(string nm)
    {
        Name = nm;
        wage = 0.0;
        hours = 0.0;
    }

    virtual public double computePay() { return wage * hours; }     /* Implicitly virtual c++ */
}

class SalesPerson : WageEmployee
{
    public double commission { get; set; }
    public double salesMade { get; set; }

    public SalesPerson(string nm)
        : base(nm)
    {
        commission = 0.0;
        salesMade = 0.0;
    }

    override public double computePay()
    {
        return base.computePay() + commission * salesMade;
    }   /* Implicitly virtual c++ */
}

class Manager : Employee
{
    private string iName = "";
    virtual public string Name { get { return iName; } set { iName = value; } }
    public double weeklySalary { get; set; }

    public Manager(string nm)
    {
        Name = nm;
        weeklySalary = 0.0;
    }
    public Manager()
    {
        weeklySalary = 0.0;
    }

    public double computePay() { return weeklySalary; }     /* Implicitly virtual c++ */
}

class SalesManager : Manager, /*SalesPerson,*/ Employee 
{            
    public SalesManager(string nm)
    {
        Name = nm;
        //SalesPerson(nm);
        //commission = 0.01;
        //salesMade = 100.0;
    }

    public double computePay() { return base.computePay();/*Manager.computePay()+SalesPerson.computePay();*/ }       
}

class EmployeeList
{
    private List<Employee> list = new List<Employee>();
    public List<Employee> GetElements() { return list; }
    public void Add(Employee newEmp) { list.Add(newEmp);}
    public EmployeeList() {}
}


class poly
{
    public poly()
    {

    }

    public virtual void generate()
    {
        EmployeeList  myDept = new EmployeeList();

        WageEmployee wagePtr = new WageEmployee("Alan Wage");
        SalesPerson salePtr = new SalesPerson("Brian Sale");
        Manager mgrPtr  = new Manager("Clive Manager");
        SalesManager salemanPtr = new SalesManager("David SaleMan");

        wagePtr.wage=10.0;
        wagePtr.hours=35; 

        salePtr.wage= 5.0 ;
        salePtr.hours= 35.0 ;
        salePtr.commission= 0.05 ;
        salePtr.salesMade= 100.0 ;

        mgrPtr.weeklySalary=600.0;
        salemanPtr.weeklySalary = 670;

        myDept.Add( wagePtr );
        myDept.Add( salePtr );
        myDept.Add( mgrPtr );
        myDept.Add( salemanPtr );

        double payroll = 0.0 ;

        List<Employee> list = myDept.GetElements();

        foreach (Employee person in list)
        {
            Console.WriteLine("personName( \"{0}\" )\tcomputePay( \"{1}\" )", person.Name, person.computePay());
            payroll += person.computePay();
        }
        Console.WriteLine("computePay( \"{0}\" )\n", payroll.ToString() );

    }

    static void Main(string[] args)
    {
        try
        {
            new poly().generate(); //new poly(args[0], args[1]).generate();  
        }
        catch (IndexOutOfRangeException ioe)
        {
            System.Console.Error.WriteLine(ioe);
        }
    }
}

}

But in C# SalesManager's multiple inheritance is not language supported.

Personally I am happy to lose multiple inheritance.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top