CSC/ECE 517 Fall 2012/ch1 1w23 as

From Expertiza_Wiki
Jump to navigation Jump to search

1w23: Multiple Inheritance and Mixins

Introduction

The purpose of this article is to give a brief introduction about multiple inheritance by taking a look at some of its issues and discuss techniques employed by different programming languages to handle such issues. In this relation, the article also compares solutions offered by different programming languages, especially Ruby mixins, by listing their advantages and disadvantages.

Multiple Inheritance

Multiple Inheritance is a technique of establishing hierarchical relationships within a set of classes, such that a single class can inherit  behaviors from multiple parent classes. Although it might seem useful to include methods from multiple classes, the major issue with multiple inheritance is the ambiguity in referencing the parent class methods,  when more than one parent classes share a method with the same name.This ambiguity is predominant in cases where the inheritance hierarchy is more than one level deep, where the class in the lowermost level inherits from two classes, that have overridden the same method from their parent in different ways.<ref>http://en.wikipedia.org/wiki/Multiple_inheritance#The_diamond_problem</ref>

A Real World Example

Let us consider an example of representing players of Cricket<ref> http://en.wikipedia.org/wiki/Cricket</ref> using classes and objects. The players of Cricket are instances of class Cricketer. Classes Bowler and Batsman inherit Cricketer’s state and behavior. All rounders inherit states and behaviors of Batsman, Bowler and subsequently the Cricketer through Batsman and Bowler classes. Let us explore the issues of multiple inheritance in reference to this context.

Class Diagram for the example.

Issues of Multiple Inheritance

1. Due to inheritance, the parent class’s objects get duplicated to child class. As a result, Allrounder Class duplicates Cricketer objects through each of Batsman and Bowler classes. When Allrounder accesses any of the Cricketer’s attributes, the compiler would be ambiguous about determining the correct path to use since two paths are available from Allrounder to Cricketer. This problem of multiple inheritance is called diamond problem. Compiler takes arbitrary decisions during such situations. <ref>http://www.artima.com/weblogs/viewpost.jsp?thread=246488</ref>

2.Objects of parent classes can be separately managed by using virtual tables as in C++. By explicitly specifying the virtual table pointer, the Allrounder class can access Batsman and Bowler classes unambiguously. However virtual tables occupy significant portion of memory thereby limiting their extensive usage.

3. The order by which a child class inherits parent classes also matters. If Allrounder inherits Batsman prior to Bowler, then Batsman precedes Bowler and common methods are accessed in this order of precedence. Hence if the Programmer is not aware of such precedences, debugging would be difficult.

Solutions

Programming languages provide different solutions to handle the issues of multiple inheritance. Here we consider the techniques offered by C++, Java, Ruby, Scala and Python.

Multiple Inheritance in C++

C++ supports multiple inheritance with the notion of virtual classes and virtual functions. In the example, the Cricketer class defines virtual functions with Batsman and Bowler classes virtually inheriting the features of Cricketer. The Allrounder class can now unambiguously access Cricketer class using virtual table pointers of Batsman and Bowler. The example written using C++ virtual functions is shown below.

-->

class Cricketer
{
  protected:
    char* country;
    char* player_type;
  public:
    virtual void statistics()
    {
        cout<<"Cricketer's statistics include number of matches, average, best performances etc."<<endl; }
    }    
};

class Batsman : virtual public Cricketer
{
  public:
    void statistics()
    {
      cout<<"Batsman's statistics include batting average, number of 100's & 50's, top score etc."<<endl;
    }
        // other methods to operate on Cricketer & Batsman specific attributes
};

class Bowler : virtual public Cricketer
{
  public:
    void statistics()
    {
      cout<<"Bowler's statistics include number of wickets, bowling average, economy etc."<<endl;
    }
      // other methods to operate on Cricketer & Bowler specific attributes
};

class Allrounder: public Batsman, public Bowler
{
  public:
    void statistics()
    {
      cout<<"Allrounder's statistics include batting average, bowling average etc."<<endl;
    }
    // other methods to operate on Cricketer, Batsman & Bowler specific attributes
};

int main()
{
  int i = 0;
  Cricketer *instances[3];
  Batsman bat;
  Bowler bowl;
  Allrounder all;
  instances[0] = &bat;
  instances[1] = &bowl;
  instances[2] = &all;
  while(i<3) 
    instances[i++]->statistics();      
  return 0;
}