5.3. A Few Words About Multiple Inheritance

So far, the inheritance hierarchies we looked at are known informally as "single inheritance" hierarchies because any particular class in the hierarchy may only have a single direct base class (immediate ancestor). In the hierarchy shown in Figure 5-8, for example, classes marked B, C, and I all have the single direct base class A; D, E, and F have the single direct base B; and G and H have the single direct base E.

Figure 5.8. A sample single inheritance hierarchy

If we for some reason find ourselves needing to meld together the characteristics of two different base classes to create a hybrid third class, multiple inheritance may seem to be the answer. While not permitted in C#, multiple (as opposed to single) inheritance allows any given class in a class hierarchy to have two or more classes as immediate ancestors.

For example, we have a Professor class representing people who teach classes and a Student class representing people who take classes. What might we do if we have a professor who wants to enroll in a class via the SRS? Or, a student—most likely a graduate student—who has been asked to teach an undergraduate-level course? In order to accurately represent either of these two people as objects, we would need to be able to combine the members of the Professor class with those of the Student class: a hybrid ProfessorStudent. This might be portrayed in our class hierarchy, as shown in Figure 5-9.

Figure 5.9. Multiple inheritance permits a derived class to have multiple immediate ancestors.

On the surface, this seems quite handy. However, there are many complications inherent with multiple inheritance; so many, in fact, that the C# language designers chose not to support multiple inheritance. Instead, they provided an alternative mechanism for handling the requirement of creating an object with a "split personality" (one that can behave like two or more different real-world entities). This mechanism involves the notion of interfaces and will be explored in detail in Chapter 7. Therefore, if you are primarily interested in object concepts only as they pertain to the C# language, you may wish to skip the rest of this section. If, on the other hand, you're curious as to why multiple inheritance is so tricky, then please read on.

Here's the problem with what we've done in the previous example. We learned that with inheritance a derived class automatically inherits the fields and methods of its base. What about when we have two or more direct base classes? If these base classes have no overlaps in terms of their field names or method signatures, we are fine. But what if the direct base classes in question

  • Have methods with the same signature, but with different code body implementations?

  • Have identical fields (name and type the same)?

  • Have fields with identical names, but with different types?

Let's explore these situations with a simple example.

First, say that we created a trivially simple Person class that declares one field and one method, GetDescription, as shown here:

public class Person
{
  private string name;

  //  public Name property syntax not shown.

  public virtual string GetDescription() {
    return name;
    // e.g., "John Doe"
  }
}

Later on, we decide to specialize Person by creating two derived classes—Professor and Student—which each add a few fields as well as overriding the GetDescription method to take advantage of their newly added fields, as follows:

public class Student : Person
{
  // We add two fields.
  string major;
  int id;  // a unique Student ID number

  // Override this method as inherited from Person.
  public override string GetDescription() {
    return Name + " [" + major + "; " + id + "]";
    // e.g., "Mary Smith [Math; 10273]"
  }
}

public class Professor : Person
{
  // We add two fields; note that one has the same name, but a
  // different data type, as a field of Student.
  string title;
  string id;  // a unique Employee ID number

  // Override this method as inherited from Person.
  public override string GetDescription() {
    return Name + " [" + title + "; " + id + "]";
    // e.g., "Harry Henderson [Chairman; A723]"
  }
}

Note that both derived classes happen to have added a field named id, but that in the case of the Student class, it's declared to be of type int; and in Professor, of type string. Also, note that both classes have overridden the GetDescription method differently, to take advantage of each class's own unique fields.

At some future point in the evolution of this system, we determine the need to represent a single object as both a Student and a Professor simultaneously, and so we create the hybrid class ProfessorStudent as a derived class of both Student and Professor. We don't particularly want to add any fields or methods; we just want to meld together the characteristics of both base classes, so we'd ideally like to declare ProfessorStudent as follows:

// * * * Important Note:  this is not permitted in C#!!! * * *
					class ProfessorStudent : Professor and Student
{
  // It's OK to leave a class body empty; the class itself is not
  // really 'empty', because it inherits the members of its
  // base classes.
}

But we encounter several roadblocks to doing so.

First, we have a field name clash. If we were to simple-mindedly inherit all the fields of both Professor and Student, we'll wind up with the items shown in Table 5-1.

Table 5.1. Multiple Inheritance Introduces Many Ambiguities with Respect to Derived Class Members
FieldNotes
string name;Inherited from Student, this in turn inherited it from Person.
string major;Inherited from Student.
int id;Inherited from Student; this conflicts with the string id field inherited from Professor (the compiler won't allow both to coexist).
string name;Inherited from Professor, which in turn inherited it from Person; a duplicate—the compiler won't allow this.
string title;Inherited from Professor.
string id;Inherited from Professor; this conflicts with the int id field inherited from Student (the compiler won't allow both to coexist).

Making a compiler intelligent enough to automatically resolve and eliminate true duplicates, such as the second copy of the name field wouldn't be too difficult a task, but what about int id vs. string id? There's no way for the compiler to know which one to eliminate; indeed, we really shouldn't eliminate either one because they represent different information items. Our only choice would be to go back to either the Student class or the Professor class (or both), and rename their respective id fields to be perhaps studentId and/or employeeId to make it clear that the fields represent different information items. Then ProfessorStudent could inherit both without any problems. If we don't have control over the source code for at least one of these base classes, however, we're in trouble.

Another problem we face is that the compiler will be confused as to which version of the GetDescription method we should inherit. Chances are that we'll want neither because neither one takes full advantage of the other class's fields; but even if we wanted to use one of the base class's versions of the method versus the other, we'd have to invent some way of informing the compiler which one we wanted to inherit, or else we'd be forced to override GetDescription in the ProfessorStudent class.

This is just a simple example, but it nonetheless illustrates why multiple inheritance can be so cumbersome to take advantage of in an OOPL.

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset