15 Multiple inheritance lappicimrantxteshraworkefed in the preceding chapter.In study ing the basics of the mechanism we have encountered the notion that a class may need more than one parent.Known as multiple inheritance (to distinguish it from the more restrictive case of single inheritance),this possibility is necessary to build robust object-oriented architectures by combining different abstractions. Multiple inheritance,in its basic form,is a straightforward application of the principles of inheritance already seen;you just allow a class to include an arbitrary number of parents.More detailed probing brings up two interesting issues: The need for feature renaming,which in fact has useful applications in single inheritance too. The case of repeated inheritance,in which the ancestor relation links two classes in more than one way. 15.1 EXAMPLES OF MULTIPLE INHERITANCE The first task is to form a good idea of when multiple inheritance is useful.Let us study a few typical examples from many different backgrounds,a few will be shown in some detail,others only sketched. This review is all the more necessary that in spite of the elegance,necessity and fundamental simplicity of multiple inheritance,obvious to anyone who cares to study the concepts,this facility has sometimes been presented (often,as one later finds out,based solely on experience with languages or environments that cannot deal with it)as complex, mysterious,error-prone-as the object-oriented method's own"goto".Although it has no basis in either fact or theory,this view has been promoted widely enough to require that we take the time to review a host of cases in which multiple inheritance is indispensable. As it will turn out,the problem is not to think of valuable examples,but to stop the flow of examples that will start pouring in once we open the tap
15 Multiple inheritance Full application of inheritance requires an important extension to the framework defined in the preceding chapter. In studying the basics of the mechanism we have encountered the notion that a class may need more than one parent. Known as multiple inheritance (to distinguish it from the more restrictive case of single inheritance), this possibility is necessary to build robust object-oriented architectures by combining different abstractions. Multiple inheritance, in its basic form, is a straightforward application of the principles of inheritance already seen; you just allow a class to include an arbitrary number of parents. More detailed probing brings up two interesting issues: • The need for feature renaming, which in fact has useful applications in single inheritance too. • The case of repeated inheritance, in which the ancestor relation links two classes in more than one way. 15.1 EXAMPLES OF MULTIPLE INHERITANCE The first task is to form a good idea of when multiple inheritance is useful. Let us study a few typical examples from many different backgrounds; a few will be shown in some detail, others only sketched. This review is all the more necessary that in spite of the elegance, necessity and fundamental simplicity of multiple inheritance, obvious to anyone who cares to study the concepts, this facility has sometimes been presented (often, as one later finds out, based solely on experience with languages or environments that cannot deal with it) as complex, mysterious, error-prone — as the object-oriented method’s own “goto”. Although it has no basis in either fact or theory, this view has been promoted widely enough to require that we take the time to review a host of cases in which multiple inheritance is indispensable. As it will turn out, the problem is not to think of valuable examples, but to stop the flow of examples that will start pouring in once we open the tap
520 MULTIPLE INHERITANCE $15.1 What not to use as an introductory example To dispel a frequent confusion,we must first consider an example whose use(with some variants)by many introductory papers,books and lectures may account for some of the common mistrust of multiple inheritance.Not that there is anything fundamentally wrong with the example;it is simply inadequate for an introductory presentation,since it is not typical of simple,straightforward uses of multiple inheritance. The standard form of this example involves classes TEACHER and STUDENT,part of the model for some university system;you will be invited to note that some students are also teachers,prompting a new class TEACHING ASS/STAN7 that inherits from both TEACHER and STUDENT. A case of TEACHER STUDENT multiple inheritance... TEACHING ASSISTANT Is this example an improper use of inheritance?Not necessarily.But as an introduction to multiple inheritance it is about as bad as they can get.The problem is that TEACHER and STUDENT are not separate abstractions but variations on a common theme:person,or more accurately UNIVERSITY PERSON.So if we draw the full picture we see a case of not just multiple but repeated inheritance-the scheme,studied later in this chapter,in which a class is a proper descendant ofanother through two paths or more: UNIVERSITY ..that is a case PERSON of repeated inheritance TEACHER STUDENT TEACHING ASSISTANT Repeated inheritance is a special case;as will be noted when we get to it,using this Fordetails see facility requires good experience with the more elementary forms of inheritance,single and “REPEATED NHERITANCE” multiple.So it is not a matter for beginners,ifonly because it seems to create conflicts(what 15.4page543. about a feature name or subscribe to health plan which TEACHING ASSISTANT inherits
520 MULTIPLE INHERITANCE §15.1 What not to use as an introductory example To dispel a frequent confusion, we must first consider an example whose use (with some variants) by many introductory papers, books and lectures may account for some of the common mistrust of multiple inheritance. Not that there is anything fundamentally wrong with the example; it is simply inadequate for an introductory presentation, since it is not typical of simple, straightforward uses of multiple inheritance. The standard form of this example involves classes TEACHER and STUDENT, part of the model for some university system; you will be invited to note that some students are also teachers, prompting a new class TEACHING_ASSISTANT that inherits from both TEACHER and STUDENT. Is this example an improper use of inheritance? Not necessarily. But as an introduction to multiple inheritance it is about as bad as they can get. The problem is that TEACHER and STUDENT are not separate abstractions but variations on a common theme: person, or more accurately UNIVERSITY_PERSON. So if we draw the full picture we see a case of not just multiple but repeated inheritance — the scheme, studied later in this chapter, in which a class is a proper descendant of another through two paths or more: Repeated inheritance is a special case; as will be noted when we get to it, using this facility requires good experience with the more elementary forms of inheritance, single and multiple. So it is not a matter for beginners, if only because it seems to create conflicts (what about a feature name or subscribe_to_health_plan which TEACHING_ASSISTANT inherits A case of multiple inheritance… TEACHING_ ASSISTANT TEACHER STUDENT … that is a case of repeated inheritance TEACHING_ ASSISTANT UNIVERSITY_ PERSON TEACHER STUDENT For details see “REPEATED INHERITANCE”, 15.4, page 543
$15.1 EXAMPLES OF MULTIPLE INHERITANCE 521 from both of its parents,even though they are really in each case a single feature coming from the common ancestor UN/VERSITY PERSON?).With a well-reasoned approach we will be able to remove these conflicts simply.But it is a serious mistake to begin with such exceptional and seemingly tricky cases as if they were typical of multiple inheritance The truly common cases do not raise any such problem.Instead of dealing with variants of a single abstraction,they combine distinct abstractions.This is the form that you will need most often in building inheritance structures,and the one that introductory discussions should describe.The following examples belong to that pattern. Can an airplane be an asset? Our first proper example belongs to system modeling more than to software construction in the strict sense.But it is typical of situations that require multiple inheritance. Assume a class 4/RPLANE describing the abstraction suggested by its name. Queries may include passenger count,altitude,position,speed;commands may include take off,land,set speed. In a different domain,we may have a class ASSET describing the accounting notion of an asset-something which a company owns,although it may still be paying installments on it,and which it can depreciate or resell.Features may include purchase price, resale value,depreciate,resell,pay installment. You must have guessed where we are heading:companies may own company planes.For the pilot,a company plane is just a plane with its usual features:it takes off, lands,has a certain speed,flies somewhere.From the viewpoint of the accountant (the one who grumbles that the money would have been better kept in the bank or spent on more productive ventures)it is an asset,with a purchase value(too high),an estimated resale value (too low),and the need to pay interest on the loan each month. To model the notion of company plane we can resort to multiple inheritance: Company PLANE ASSET planes COMPANY PLANE class COMPANY PLANE inherit PLANE ASSET feature ..Any feature that is specific to company planes (rather than applying to all planes or all assets)... end
§15.1 EXAMPLES OF MULTIPLE INHERITANCE 521 from both of its parents, even though they are really in each case a single feature coming from the common ancestor UNIVERSITY_PERSON?). With a well-reasoned approach we will be able to remove these conflicts simply. But it is a serious mistake to begin with such exceptional and seemingly tricky cases as if they were typical of multiple inheritance. The truly common cases do not raise any such problem. Instead of dealing with variants of a single abstraction, they combine distinct abstractions. This is the form that you will need most often in building inheritance structures, and the one that introductory discussions should describe. The following examples belong to that pattern. Can an airplane be an asset? Our first proper example belongs to system modeling more than to software construction in the strict sense. But it is typical of situations that require multiple inheritance. Assume a class AIRPLANE describing the abstraction suggested by its name. Queries may include passenger_count, altitude, position, speed; commands may include take_off, land, set_speed. In a different domain, we may have a class ASSET describing the accounting notion of an asset — something which a company owns, although it may still be paying installments on it, and which it can depreciate or resell. Features may include purchase_price, resale_value, depreciate, resell, pay_installment. You must have guessed where we are heading: companies may own company planes. For the pilot, a company plane is just a plane with its usual features: it takes off, lands, has a certain speed, flies somewhere. From the viewpoint of the accountant (the one who grumbles that the money would have been better kept in the bank or spent on more productive ventures) it is an asset, with a purchase value (too high), an estimated resale value (too low), and the need to pay interest on the loan each month. To model the notion of company plane we can resort to multiple inheritance: class COMPANY_PLANE inherit PLANE ASSET feature … Any feature that is specific to company planes (rather than applying to all planes or all assets) … end Company planes COMPANY_ PLANE PLANE ASSET
522 MULTIPLE INHERITANCE $15.1 To specify multiple parents in the inherit clause,just list them one after the other. (As usual,you can use semicolons as optional separators.)The order in which you list parents is not significant. Cases similar to COMPANY PLANE abound in system modeling.Here are a few: Wristwatches (a special case of the notion of watch,itself specializing the general notion of clock-there are a few inheritance links here)provide commands such as setting the time,and queries such as the current time and date.Electronic calculators provide arithmetic features.There also exist some (quite handy)watch-calculators, elegantly modeled through multiple inheritance. Boats;trucks;AMPHIBIOUS VEHICLE.A variant is:boats;planes;HYDROPLANE (There is a hint of repeated inheritance here,as with TEACHING ASS/STANT,since both parents may themselves be descendants of some /EHICLE class.) You eat in a restaurant;you travel in a train car.To make your trip more enjoyable, the railway company may let you eat in an instance of EATING CAR.A variant of this example is SLEEPING CAR. On an instance of SOFA BED you may not only read but also sleep. .A MOBILE HOME is a VEHICLE and a HOUSE. And so on.Multiple inheritance is the natural tool to help model the endless combinations that astute people never tire of concocting. For a software engineer the preceding examples may at first appear academic,since we get paid not to model the world but to build systems.In many practical applications, however,you will encounter similar combinations of abstractions.A detailed example, from ISE's own graphical development environment appears later in this chapter. Numeric and comparable values The next example is much more directly useful to the daily practice of object-oriented software construction.It is essential to the buildup of the Kemel library. Some ofthe Kernel library's classes-that is to say,classes describing abstractions of potential use to all applications-require arithmetic features:operations such as infix "+"infix "-"infix"+",prefix "-"as well as special values ero (identity element for "+")and one (identity element for "*")Kernel library classes that use these features include INTEGER,REAL and DOUBLE;but many non-predefined classes may need them too,for example a class MATRIY describing matrices of some application-specific kind. It is appropriate to capture the corresponding abstraction through a deferred class NUMERIC,itself a part of the Kernel library: deferred class NUMER/C feature ..infix "+"infix "-"infix ""prefix ""zero,one .. end
522 MULTIPLE INHERITANCE §15.1 To specify multiple parents in the inherit clause, just list them one after the other. (As usual, you can use semicolons as optional separators.) The order in which you list parents is not significant. Cases similar to COMPANY_PLANE abound in system modeling. Here are a few: • Wristwatches (a special case of the notion of watch, itself specializing the general notion of clock — there are a few inheritance links here) provide commands such as setting the time, and queries such as the current time and date. Electronic calculators provide arithmetic features. There also exist some (quite handy) watch-calculators, elegantly modeled through multiple inheritance. • Boats; trucks; AMPHIBIOUS_VEHICLE. A variant is: boats; planes; HYDROPLANE. (There is a hint of repeated inheritance here, as with TEACHING_ASSISTANT, since both parents may themselves be descendants of some VEHICLE class.) • You eat in a restaurant; you travel in a train car. To make your trip more enjoyable, the railway company may let you eat in an instance of EATING_CAR. A variant of this example is SLEEPING_CAR. • On an instance of SOFA_BED you may not only read but also sleep. • A MOBILE_HOME is a VEHICLE and a HOUSE. And so on. Multiple inheritance is the natural tool to help model the endless combinations that astute people never tire of concocting. For a software engineer the preceding examples may at first appear academic, since we get paid not to model the world but to build systems. In many practical applications, however, you will encounter similar combinations of abstractions. A detailed example, from ISE’s own graphical development environment appears later in this chapter. Numeric and comparable values The next example is much more directly useful to the daily practice of object-oriented software construction. It is essential to the buildup of the Kernel library. Some of the Kernel library’s classes — that is to say, classes describing abstractions of potential use to all applications — require arithmetic features: operations such as infix "+", infix "–", infix "∗", prefix "–" as well as special values zero (identity element for "+") and one (identity element for "∗"). Kernel library classes that use these features include INTEGER, REAL and DOUBLE; but many non-predefined classes may need them too, for example a class MATRIX describing matrices of some application-specific kind. It is appropriate to capture the corresponding abstraction through a deferred class NUMERIC, itself a part of the Kernel library: deferred class NUMERIC feature … infix "+", infix "–", infix "∗", prefix "–", zero, one … end
$15.1 EXAMPLES OF MULTIPLE INHERITANCE 523 Mathematically,NUMER/C has a precise specification:its instances represent members of a ring(a set equipped with two operations,both of which separately give it the structure of a group,one commutative,with distributivity between the two operations). Some classes also need an order relation,with features for comparing arbitrary elements:infix "<"infix"<=",infix">",infix ">="Again this is useful not only to some Kernel library classes,such as STR/NG whose instances are comparable through lexical ordering,but also to many application classes;for example you may write a class TENNIS CHAMP/ON which takes into account the ranking of professional tennis players, with a feature "<such that tc/<tc2 tells us whether tc2 is ranked ahead of tc/.So it is appropriate to capture the corresponding abstraction through a deferred class COMPARABLE,itself a part of the Kernel library: deferred class COMPARABLE feature ..infix "<"infix "<="infix">",infix ">=".. end Technically the COMPAR4BLE has a precise mathematical model:its instances represent members exact model is that of a set ordered by a total order relation. ofa"preorder” Notall descendants ofCOMPARABLE should be descendants of NUMER/C:in class STRING,we need the order features for lexicographical ordering but not the arithmetic features.Conversely,not all descendants of NUMER/C should be descendants of COMPARABLE:the set of real matrices has addition,multiplication,zero and one,giving it a ring structure,but no total order relation.So it is appropriate that COMPARABLE and NUMER/C,representing completely different abstractions,should remain distinct classes, neither of them a descendant of the other. Objects of certain types,however,are both comparable and numeric.(In mathematical terms.the structures modeled by their generating classes are totally ordered rings.)Example classes include REAL and INTEGER:integers and real numbers can be compared for "<="as well as added and multiplied.These classes should be defined through multiple inheritance,as in(see the figure on the next page): expanded class REAL inherit NUMERIC COMPARABLE feature end Types of objects that need to be both comparable and numeric are sufficiently common to suggest a class COMPARABLE NUMER/C,still deferred,covering the merged abstraction by multiply inheriting from COMPARABLE and NUMER/C.So far this solution has not been adopted for the library because it does not bring any obvious ad vantage and seems to open the way to endless combinations:why not COMPARABLE HASHABLE,HASHA BLE ADDABLE SUBTRACTABLE?Basing such deferred classes on well-accepted mathematical abstractions,such as ring or totally ordered set,seems to yield the right level of granularity.Related issues in the methodology of inheritance are discussed in detail in chapter 16
§15.1 EXAMPLES OF MULTIPLE INHERITANCE 523 Mathematically, NUMERIC has a precise specification: its instances represent members of a ring (a set equipped with two operations, both of which separately give it the structure of a group, one commutative, with distributivity between the two operations). Some classes also need an order relation, with features for comparing arbitrary elements: infix "<", infix "<=", infix ">", infix ">=". Again this is useful not only to some Kernel library classes, such as STRING whose instances are comparable through lexical ordering, but also to many application classes; for example you may write a class TENNIS_CHAMPION which takes into account the ranking of professional tennis players, with a feature "<" such that tc1 < tc2 tells us whether tc2 is ranked ahead of tc1. So it is appropriate to capture the corresponding abstraction through a deferred class COMPARABLE, itself a part of the Kernel library: deferred class COMPARABLE feature … infix "<", infix "<=", infix ">", infix ">=" … end COMPARABLE has a precise mathematical model: its instances represent members of a set ordered by a total order relation. Not all descendants of COMPARABLE should be descendants of NUMERIC: in class STRING, we need the order features for lexicographical ordering but not the arithmetic features. Conversely, not all descendants of NUMERIC should be descendants of COMPARABLE: the set of real matrices has addition, multiplication, zero and one, giving it a ring structure, but no total order relation. So it is appropriate that COMPARABLE and NUMERIC, representing completely different abstractions, should remain distinct classes, neither of them a descendant of the other. Objects of certain types, however, are both comparable and numeric. (In mathematical terms. the structures modeled by their generating classes are totally ordered rings.) Example classes include REAL and INTEGER: integers and real numbers can be compared for "<=" as well as added and multiplied. These classes should be defined through multiple inheritance, as in (see the figure on the next page): expanded class REAL inherit NUMERIC COMPARABLE feature … end Types of objects that need to be both comparable and numeric are sufficiently common to suggest a class COMPARABLE_NUMERIC, still deferred, covering the merged abstraction by multiply inheriting from COMPARABLE and NUMERIC. So far this solution has not been adopted for the library because it does not bring any obvious advantage and seems to open the way to endless combinations: why not COMPARABLE_ HASHABLE, HASHABLE_ADDABLE_SUBTRACTABLE? Basing such deferred classes on well-accepted mathematical abstractions, such as ring or totally ordered set, seems to yield the right level of granularity. Related issues in the methodology of inheritance are discussed in detail in chapter 16. Technically the exact model is that of a “preorder