14 Introduction to inheritance nteresting systems are seldom born into an empty world. Almost always,new software expands on previous developments;the best way to create it is by imitation,refinement and combination.Traditional design methods largely ignored this aspect of system development.In object technology it is an essential concern. The techniques studied so far are not enough.Classes do provide a good modular decomposition technique and possess many of the qualities expected of reusable components:they are homogeneous,coherent modules;you may clearly separate their interface from their implementation according to the principle of information hiding, genericity gives them some flexibility;and you may specify their semantics precisely thanks to assertions.But more is needed to achieve the full goals of reusability and extendibility. For reusability,any comprehensive approach must face the problem of repetition and variation,analyzed in an earlier chapter.To avoid rewriting the same code over and over again,wasting time,introducing inconsistencies and risking errors,we need techniques to capture the striking commonalities that exist within groups of similar structures-all text editors,all tables,all file handlers-while accounting for the many differences that characterize individual cases. For extendibility,the type system described so far has the advantage of guaranteeing type consistency at compile time,but prohibits combination of elements of diverse forms even in legitimate cases.For example,we cannot yet define an array containing geometrical objects of different but compatible types such as POINT and SEGMENT. Progress in either reusability or extendibility demands that we take advantage of the strong conceptual relations that hold between classes:a class may be an extension, specialization or combination of others.We need support from the method and the language to record and use these relations.Inheritance provides this support. A central and fascinating component of object technology,inheritance will require several chapters.In the present one we discover the fundamental concepts.The next three chapters will describe more advanced consequences:multiple inheritance,renaming, subcontracting,influence on the type system.Chapter 24 complements these technical presentations by providing the methodological perspective:how to use inheritance,and avoid misusing it
14 Introduction to inheritance Interesting systems are seldom born into an empty world. Almost always, new software expands on previous developments; the best way to create it is by imitation, refinement and combination. Traditional design methods largely ignored this aspect of system development. In object technology it is an essential concern. The techniques studied so far are not enough. Classes do provide a good modular decomposition technique and possess many of the qualities expected of reusable components: they are homogeneous, coherent modules; you may clearly separate their interface from their implementation according to the principle of information hiding; genericity gives them some flexibility; and you may specify their semantics precisely thanks to assertions. But more is needed to achieve the full goals of reusability and extendibility. For reusability, any comprehensive approach must face the problem of repetition and variation, analyzed in an earlier chapter. To avoid rewriting the same code over and over again, wasting time, introducing inconsistencies and risking errors, we need techniques to capture the striking commonalities that exist within groups of similar structures — all text editors, all tables, all file handlers — while accounting for the many differences that characterize individual cases. For extendibility, the type system described so far has the advantage of guaranteeing type consistency at compile time, but prohibits combination of elements of diverse forms even in legitimate cases. For example, we cannot yet define an array containing geometrical objects of different but compatible types such as POINT and SEGMENT. Progress in either reusability or extendibility demands that we take advantage of the strong conceptual relations that hold between classes: a class may be an extension, specialization or combination of others. We need support from the method and the language to record and use these relations. Inheritance provides this support. A central and fascinating component of object technology, inheritance will require several chapters. In the present one we discover the fundamental concepts. The next three chapters will describe more advanced consequences: multiple inheritance, renaming, subcontracting, influence on the type system. Chapter 24 complements these technical presentations by providing the methodological perspective: how to use inheritance, and avoid misusing it
460 INTRODUCTION TO INHERITANCE $14.1 14.1 POLYGONS AND RECTANGLES To master the basic concepts we will use a simple example.The example is sketched rather than complete,but it shows the essential ideas well. Polygons Assume we want to build a graphics library.Classes in this library will describe geometrical abstractions:points,segments,vectors,circles,ellipses,general polygons, triangles,rectangles,squares and so on. Consider first the class describing general polygons.Operations will include computation of the perimeter,translation,rotation.The class may look like this: indexing description:"Polygons with an arbitrary number of vertices" class POLYGON creation feature--Access count:INTEGER --Number of vertices perimeter:REAL is --Length of perimeter do...end feature--Transformation display is --Display polygon on screen. do...end rotate (center:POINT:angle:REAL)is --Rotate by angle around center. do ..See next... end translate (a,b:REAL)is -Move by a horizontally,b vertically. do...end ..Other feature declarations .. feature (NONE--Implementation vertices:LINKED LIST [POINT] --Successive points making up polygon invariant same count as implementation:count vertices.count at least three:count>=3 --A polygon has at least three vertices (see exercise 14.2) end The attribute vertices yields the list ofvertices;the choice ofa linked list is only one See also exercise possible implementation.(An array might be better.) E24.4,page869
460 INTRODUCTION TO INHERITANCE §14.1 14.1 POLYGONS AND RECTANGLES To master the basic concepts we will use a simple example. The example is sketched rather than complete, but it shows the essential ideas well. Polygons Assume we want to build a graphics library. Classes in this library will describe geometrical abstractions: points, segments, vectors, circles, ellipses, general polygons, triangles, rectangles, squares and so on. Consider first the class describing general polygons. Operations will include computation of the perimeter, translation, rotation. The class may look like this: indexing description: "Polygons with an arbitrary number of vertices" class POLYGON creation … feature -- Access count: INTEGER -- Number of vertices perimeter: REAL is -- Length of perimeter do … end feature -- Transformation display is -- Display polygon on screen. do … end rotate (center: POINT; angle: REAL) is -- Rotate by angle around center. do … See next … end translate (a, b: REAL) is -- Move by a horizontally, b vertically. do … end … Other feature declarations … feature {NONE} -- Implementation vertices: LINKED_LIST [POINT] -- Successive points making up polygon invariant same_count_as_implementation: count = vertices ● count at_least_three: count >= 3 -- A polygon has at least three vertices (see exercise 14.2) end The attribute vertices yields the list of vertices; the choice of a linked list is only one possible implementation. (An array might be better.) See also exercise E24.4, page 869
$14.1 POLYGONS AND RECTANGLES 461 Here is a possible implementation for a typical procedure,rotate.The procedure performs a rotation by a certain angle around a certain rotation center.To rotate a polygon, it suffices to rotate every vertex in turn: rotate (center:POINT;angle:REAL)is --Rotate around center by angle. do from vertices.start until vertices.after loop vertices.item.rotate (center,angle) vertices.forth end end The text of class To understand this procedure,note that feature item from LINKED LIST yields the POINT appeared on value of the currently active list element(where the cursor is).Since vertices is of type page 176. LINKED LIST [POINT],vertices.item denotes a point,to which we may apply procedure rotate defined for class POINT in an earlier chapter.It is valid-and common-to give the same name,here rotate,to features of different classes,as the target of any feature always has a clearly defined type.(This is the -O form of overloading.) Another routine,more important for our immediate purposes,is the function to compute the perimeter of a polygon.Since our polygons have no special properties,the only way to compute their perimeter is to loop through their vertices and sum the edge lengths.Here is an implementation of perimeter: perimeter:REAL is --Sum of edge lengths local this,previous:POINT do from vertices.start,this vertices.item check not vertices.after end--A consequence ofat least three until vertices.is last this (is last) loop previous :this previous vertices.forth first this :vertices.item Result:Result this.distance (previous) start) end ResultResult this.distance (vertices.first) end
§14.1 POLYGONS AND RECTANGLES 461 Here is a possible implementation for a typical procedure, rotate. The procedure performs a rotation by a certain angle around a certain rotation center. To rotate a polygon, it suffices to rotate every vertex in turn: rotate (center: POINT; angle: REAL) is -- Rotate around center by angle. do from vertices ● start until vertices ● after loop vertices ● item ● rotate (center, angle) vertices ● forth end end To understand this procedure, note that feature item from LINKED_LIST yields the value of the currently active list element (where the cursor is). Since vertices is of type LINKED_LIST [POINT], vertices ● item denotes a point, to which we may apply procedure rotate defined for class POINT in an earlier chapter. It is valid — and common — to give the same name, here rotate, to features of different classes, as the target of any feature always has a clearly defined type. (This is the O-O form of overloading.) Another routine, more important for our immediate purposes, is the function to compute the perimeter of a polygon. Since our polygons have no special properties, the only way to compute their perimeter is to loop through their vertices and sum the edge lengths. Here is an implementation of perimeter: perimeter: REAL is -- Sum of edge lengths local this, previous: POINT do from vertices ● start; this := vertices ● item check not vertices ● after end -- A consequence of at_least_three until vertices ● is_last loop previous := this vertices ● forth this := vertices ● item Result := Result + this ● distance (previous) end Result := Result + this ● distance (vertices ● first) end The text of class POINT appeared on page 176. this previous (start) (is_last) first
462 INTRODUCTION TO INHERITANCE $14.1 The loop simply adds the successive distances between adjacent vertices.Function The list interface will distance was defined in class POINT.Result,representing the value to be returned by the be discussed in function,is automatically initialized to 0 on routine entry.From class LINKED L/ST we “ACTIVE DATA use features first to get the first element,start to move the cursor to that first element, STRUCTURES” forth to advance it to the next,item to get the value of the element at cursor position,is 23.4,page774. last to know whether the current element is the last one,afier to know if the cursor is past the last element.As recalled by the check instruction the invariant clause at least_three will guarantee that the loop starts and terminates properly:since it starts in a not afier state,vertices.item is defined,and applying forth one or more time is correct and will eventually yield a state satisfying is_last,the loop's exit condition. Rectangles Now assume we need a new class representing rectangles.We could start from scratch. But rectangles are a special kind of polygon and many of the features are the same:a rectangle will probably be translated,rotated or displayed in the same way as a general polygon.Rectangles,on the other hand,also have special features (such as a diagonal), special properties(the number of vertices is four,the angles are right angles),and special versions of some operations (to compute the perimeter of a rectangle,we can do better than the above general poly gon algorithm). We can take advantage of this mix of commonality and specificity by defining class RECTANGLE as an heir to class POLYGON.This makes all the features of POLYGON -called a parent of RECTANGLE-by default applicable to the heir class as well.It suffices to give RECTANGLE an inheritance clause: elass RECTANGLE inherit POLYGON feature ..Features specific to rectangles... end The feature clause of the heir class does not repeat the features of the parent:they are automatically available because of the inheritance clause.It will only list features that are specific to the heir.These may be new features,such as diagonal;but they may also be redefinitions of inherited features. The second possibility is useful for a feature that was already meaningful for the parent but requires a different form in the heir.Consider perimeter.It has a better implementation for rectangles:no need to compute four vertex-to-vertex distances;the result is simply twice the sum of the two side lengths.An heir that redefines a feature for the parent must announce it in the inheritance clause through a redefine subclause: elass RECTANGLE inherit POLYGON redefine perimeter end feature end
462 INTRODUCTION TO INHERITANCE §14.1 The loop simply adds the successive distances between adjacent vertices. Function distance was defined in class POINT. Result, representing the value to be returned by the function, is automatically initialized to 0 on routine entry. From class LINKED_LIST we use features first to get the first element, start to move the cursor to that first element, forth to advance it to the next, item to get the value of the element at cursor position, is_ last to know whether the current element is the last one, after to know if the cursor is past the last element. As recalled by the check instruction the invariant clause at_least_three will guarantee that the loop starts and terminates properly: since it starts in a not after state, vertices ● item is defined, and applying forth one or more time is correct and will eventually yield a state satisfying is_last, the loop’s exit condition. Rectangles Now assume we need a new class representing rectangles. We could start from scratch. But rectangles are a special kind of polygon and many of the features are the same: a rectangle will probably be translated, rotated or displayed in the same way as a general polygon. Rectangles, on the other hand, also have special features (such as a diagonal), special properties (the number of vertices is four, the angles are right angles), and special versions of some operations (to compute the perimeter of a rectangle, we can do better than the above general polygon algorithm). We can take advantage of this mix of commonality and specificity by defining class RECTANGLE as an heir to class POLYGON. This makes all the features of POLYGON — called a parent of RECTANGLE — by default applicable to the heir class as well. It suffices to give RECTANGLE an inheritance clause: class RECTANGLE inherit POLYGON feature … Features specific to rectangles … end The feature clause of the heir class does not repeat the features of the parent: they are automatically available because of the inheritance clause. It will only list features that are specific to the heir. These may be new features, such as diagonal; but they may also be redefinitions of inherited features. The second possibility is useful for a feature that was already meaningful for the parent but requires a different form in the heir. Consider perimeter. It has a better implementation for rectangles: no need to compute four vertex-to-vertex distances; the result is simply twice the sum of the two side lengths. An heir that redefines a feature for the parent must announce it in the inheritance clause through a redefine subclause: class RECTANGLE inherit POLYGON redefine perimeter end feature … end The list interface will be discussed in “ACTIVE DATA STRUCTURES”, 23.4, page 774
$14.1 POLYGONS AND RECTANGLES 463 This allows the feature clause of RECTANGLE to contain a new version of perimeter,which will supersede the POLYGON version for rectangles.If the redefine subclause were not present,a new declaration of perimeter among the features of RECTANGLE would be an error:since RECTANGLE already has a perimeter feature inherited from POLYGON,this would amount to declaring a feature twice. The RECTANGLE class looks like the following: indexing description:"Rectangles,viewed as a special case of general polygons" class RECTANGLE inherit POLYGON redefine perimeter end creation make feature --Initialization make (center:POINT;s1,s2,angle:REAL)is --Set up rectangle centered at center,with side lengths --s/and s2 and orientation angle. do ..end feature--Access sidel,side2:REAL --The two side lengths diagonal:REAL --Length of the diagonal perimeter:REAL is --Sum of edge lengths --(Redefinition of the POLYGON version) do Result :2 (sidel side2) end side? sidel invariant four sides:count =4 For a list,i th (i) first side:(vertices.i th(1)).distance (vertices.i th(2))=sidel gives the element at second side:(vertices.i th (2)).distance (vertices.i th(3))=side2 position i (the i-th element,hence the third side:(vertices.i th (3)).distance (vertices.i th (4))=sidel name of the query). fourth side:(vertices.i th (4)).distance (vertices.i th(1)=side2 end Because RECTANGLE is an heir of POLYGON,all features of the parent class are still applicable to the new class:vertices,rotate,translate,perimeter (in redefined form) and any others.They do not need to be repeated in the new class. This process is transitive:any class that inherits from RECTANGLE,say SOUARE, also has the POLYGON features
§14.1 POLYGONS AND RECTANGLES 463 This allows the feature clause of RECTANGLE to contain a new version of perimeter, which will supersede the POLYGON version for rectangles. If the redefine subclause were not present, a new declaration of perimeter among the features of RECTANGLE would be an error: since RECTANGLE already has a perimeter feature inherited from POLYGON, this would amount to declaring a feature twice. The RECTANGLE class looks like the following: indexing description: "Rectangles, viewed as a special case of general polygons" class RECTANGLE inherit POLYGON redefine perimeter end creation make feature -- Initialization make (center: POINT; s1, s2, angle: REAL) is -- Set up rectangle centered at center, with side lengths -- s1 and s2 and orientation angle. do … end feature -- Access side1, side2: REAL -- The two side lengths diagonal: REAL -- Length of the diagonal perimeter: REAL is -- Sum of edge lengths -- (Redefinition of the POLYGON version) do Result := 2 ✳ (side1 + side2) end invariant four_sides: count = 4 first_side: (vertices ● i_th (1)) ● distance (vertices ● i_th (2)) = side1 second_side: (vertices ● i_th (2)) ● distance (vertices ● i_th (3)) = side2 third_side: (vertices ● i_th (3)) ● distance (vertices ● i_th (4)) = side1 fourth_side: (vertices ● i_th (4)) ● distance (vertices ● i_th (1)) = side2 end Because RECTANGLE is an heir of POLYGON, all features of the parent class are still applicable to the new class: vertices, rotate, translate, perimeter (in redefined form) and any others. They do not need to be repeated in the new class. This process is transitive: any class that inherits from RECTANGLE, say SQUARE, also has the POLYGON features. 1 2 4 3 side1 side2 For a list, i_th (i) gives the element at position i (the i-th element, hence the name of the query)
464 INTRODUCTION TO INHERITANCE $14.1 Basic conventions and terminology The following terms will be useful in addition to"heir'”and“parent'”. Inheritance terminology A descendant ofa class C is any class that inherits directly or indirectly from C,including C itself.(Formally:either C or,recursively,a descendant of an heir of C.) A proper descendant of C is a descendant other than C itself. An ancestor of C is a class 4 such that C is a descendant of 4.A proper ancestor of C is a class 4 such that C is a proper descendant of A. In the literature you will also encounter the terms“subclass”and“superclass”,but we will stay away from them because they are ambiguous;sometimes"subclass"means heir (immediate descendant),sometimes it is used in the more general sense of proper descendant,and it is not always clear which.In addition,we will see that the "subset" connotation of this word is not always justified. Associated terminology applies to the features of a class:a feature is either inherited (coming from a proper ancestors)or immediate (introduced in the class itself). In graphical representations of object-oriented software structures,where classes are represented by ellipses("bubbles"),inheritance links will appear as single arrows.This distinguishes them from links for the other basic inter-class relation,client,which as you will recall uses a double arrow.(For further distinction this book uses black for client and color for inheritance. perimeter POLYGON An inheritance link diagonal Inherits from perimeter+ RECTANGLE A redefined feature is marked,a convention from the Business Object Notation (B.O.N.). The arrow points upward,from the heir to the parent;the convention,easy to remember,is that it represents the relation "inherits from".In some of the literature you will find the reverse practice;although in general such choices of graphical convention are partly a matter of taste,in this case one convention appears definitely better than the other in the sense that one suggests the proper relationship and the other may lead to confusion.An arrow is not just an arbitrary pictogram but indicates a unidirectional link, between the two ends of the arrow.Here:
464 INTRODUCTION TO INHERITANCE §14.1 Basic conventions and terminology The following terms will be useful in addition to “heir” and “parent”. In the literature you will also encounter the terms “subclass” and “superclass”, but we will stay away from them because they are ambiguous; sometimes “subclass” means heir (immediate descendant), sometimes it is used in the more general sense of proper descendant, and it is not always clear which. In addition, we will see that the “subset” connotation of this word is not always justified. Associated terminology applies to the features of a class: a feature is either inherited (coming from a proper ancestors) or immediate (introduced in the class itself). In graphical representations of object-oriented software structures, where classes are represented by ellipses (“bubbles”), inheritance links will appear as single arrows. This distinguishes them from links for the other basic inter-class relation, client, which as you will recall uses a double arrow. (For further distinction this book uses black for client and color for inheritance.) A redefined feature is marked ++, a convention from the Business Object Notation (B.O.N.). The arrow points upward, from the heir to the parent; the convention, easy to remember, is that it represents the relation “inherits from”. In some of the literature you will find the reverse practice; although in general such choices of graphical convention are partly a matter of taste, in this case one convention appears definitely better than the other — in the sense that one suggests the proper relationship and the other may lead to confusion. An arrow is not just an arbitrary pictogram but indicates a unidirectional link, between the two ends of the arrow. Here: Inheritance terminology A descendant of a class C is any class that inherits directly or indirectly from C, including C itself. (Formally: either C or, recursively, a descendant of an heir of C.) A proper descendant of C is a descendant other than C itself. An ancestor of C is a class A such that C is a descendant of A. A proper ancestor of C is a class A such that C is a proper descendant of A. An inheritance link POLYGON RECTANGLE perimeter diagonal perimeter++ Inherits from
$14.1 POLYGONS AND RECTANGLES 465 Any instance ofthe heir may be viewed (as we shall see in more detail)as an instance of the parent,but not conversely. The text of the heir will always mention the parent(as in the inherit clause above), but not conversely;it is in fact an important property of the method,resulting among others from the Open-Closed principle,that a class does not"know"the list of its heirs and other proper descendants. Mathematically,the direction of the relationship is reflected in algebraic models for inheritance,which use a morphism (a generalization of the notion of function)from the heir's model to the parent's model-not the other way around.One more reason for drawing the arrow from the heir to the parent. Although with complex systems we cannot have an absolute rule for class placement in inheritance diagrams,we should try whenever possible to position a class above its heirs. Invariant inheritance You will have noticed the invariant of class RECTANGLE,which expresses that the number of sides is four and that the successive edge lengths are sidel,side2,side/and side2. Class POLYGON also had an invariant,which still applies to its heir: Invariant inheritance rule The invariant property ofa class is the boolean and ofthe assertions appearing in its invariant clause and of the invariant properties of its parents if any. Because the parents may themselves have parents,this rule is recursive:in the end the full invariant of a class is obtained by anding the invariant clauses of all its ancestors. The rule reflects one of the basic characteristics of inheritance:to say that B inherits from A is to state that one may view any instance of B also as an instance of4(more on this property later).As a result,any consistency constraint applying to instances of4,as expressed by the invariant,also applies to instances of B. In the example,the second clause (at least three)invariant of POLYGON stated that the number of sides must be at least three;this is subsumed by the four sides subclause in RECTANGLE's invariant clause,which requires it to be exactly four. You may wonder what would happen if the heir's clause,instead of making the parent's redundant as here (since count=4 implies count >=3),were incompatible with it,as with an heir of POLYGON that would introduce the invariant clause count=2.The result is simply an inconsistent invariant,not different from what you get if you include,in the invariant of a single class,two separate subclauses that read count>=3 and count=2. Inheritance and creation Although it was not shown,a creation procedure for POLYGON might be of the form
§14.1 POLYGONS AND RECTANGLES 465 • Any instance of the heir may be viewed (as we shall see in more detail) as an instance of the parent, but not conversely. • The text of the heir will always mention the parent (as in the inherit clause above), but not conversely; it is in fact an important property of the method, resulting among others from the Open-Closed principle, that a class does not “know” the list of its heirs and other proper descendants. Mathematically, the direction of the relationship is reflected in algebraic models for inheritance, which use a morphism (a generalization of the notion of function) from the heir’s model to the parent’s model — not the other way around. One more reason for drawing the arrow from the heir to the parent. Although with complex systems we cannot have an absolute rule for class placement in inheritance diagrams, we should try whenever possible to position a class above its heirs. Invariant inheritance You will have noticed the invariant of class RECTANGLE, which expresses that the number of sides is four and that the successive edge lengths are side1, side2, side1 and side2. Class POLYGON also had an invariant, which still applies to its heir: Because the parents may themselves have parents, this rule is recursive: in the end the full invariant of a class is obtained by anding the invariant clauses of all its ancestors. The rule reflects one of the basic characteristics of inheritance: to say that B inherits from A is to state that one may view any instance of B also as an instance of A (more on this property later). As a result, any consistency constraint applying to instances of A, as expressed by the invariant, also applies to instances of B. In the example, the second clause (at_least_three) invariant of POLYGON stated that the number of sides must be at least three; this is subsumed by the four_sides subclause in RECTANGLE’s invariant clause, which requires it to be exactly four. You may wonder what would happen if the heir’s clause, instead of making the parent’s redundant as here (since count = 4 implies count >= 3), were incompatible with it, as with an heir of POLYGON that would introduce the invariant clause count = 2. The result is simply an inconsistent invariant, not different from what you get if you include, in the invariant of a single class, two separate subclauses that read count >= 3 and count = 2. Inheritance and creation Although it was not shown, a creation procedure for POLYGON might be of the form Invariant inheritance rule The invariant property of a class is the boolean and of the assertions appearing in its invariant clause and of the invariant properties of its parents if any
466 INTRODUCTION TO INHERITANCE $14.I make polygon (vl:LINKED LIST [POINT])is --Set up with vertices taken from vl. require vl.count>=3 do 。。 Initialize polygon representation from the items of v/... ensure --vertices and v/have the same items (can be expressed formally) end This procedure takes a list of points,containing at least three elements,and uses it to set up the polygon The procedure has been given a special name make polygon to avoid any name conflict See“FEATURE when RECTANGLE inherits it and introduces its own creation procedure make.This is RENAMING”,I5.2. not the recommended style;in the next chapter we will learn how to give the standard page 535. name make to the creation procedure in POLYGON,and use renaming in the inheritance clause of RECTANGLE to remove any name clash. The creation procedure of class RECTANGLE,shown earlier,took four arguments: a point to serve as center,the two side lengths and an orientation.Note that feature vertices is still applicable to rectangles;as a consequence,the creation procedure of RECTANGLE should set up the vertices list with the appropriate point values (the four corners,to be computed from the center,side lengths and orientation given as arguments). The creation procedure for general polygons is awkward for rectangles,since only lists of four elements satisfying the invariant of class RECTANGLE would be acceptable Conversely,the creation procedure for rectangles is not appropriate for arbitrary polygons. This is a common case:a parent's creation procedure is not necessarily right as creation procedure for the heir.The precise reason is easy to spot;it follows from the observation that a creation procedure's formal role is to establish the class invariant.The parent's creation procedure was required to establish the parent's invariant;but,as we have seen, the heir's invariant may be stronger (and usually is);we cannot then expect that the original procedure will guarantee the new invariant. In the case of an heir adding new attributes,the creation procedures might need to initialize these attributes and so require extra arguments.Hence the general rule: Creation Inheritance rule An inherited feature's creation status in the parent class (that is to say, whether or not it is a creation procedure)has no bearing on its creation status in the heir. An inherited creation procedure is still available to the heir as a normal feature of the class (although,as we shall see,the heir may prefer to make it secret);but it does not by default retain its status as a creation procedure.Only the procedures listed in the heir's own creation clause have that status
466 INTRODUCTION TO INHERITANCE §14.1 make_polygon (vl: LINKED_LIST [POINT]) is -- Set up with vertices taken from vl. require vl ● count >= 3 do … Initialize polygon representation from the items of vl … ensure -- vertices and vl have the same items (can be expressed formally) end This procedure takes a list of points, containing at least three elements, and uses it to set up the polygon. The procedure has been given a special name make_polygon to avoid any name conflict when RECTANGLE inherits it and introduces its own creation procedure make. This is not the recommended style; in the next chapter we will learn how to give the standard name make to the creation procedure in POLYGON, and use renaming in the inheritance clause of RECTANGLE to remove any name clash. The creation procedure of class RECTANGLE, shown earlier, took four arguments: a point to serve as center, the two side lengths and an orientation. Note that feature vertices is still applicable to rectangles; as a consequence, the creation procedure of RECTANGLE should set up the vertices list with the appropriate point values (the four corners, to be computed from the center, side lengths and orientation given as arguments). The creation procedure for general polygons is awkward for rectangles, since only lists of four elements satisfying the invariant of class RECTANGLE would be acceptable. Conversely, the creation procedure for rectangles is not appropriate for arbitrary polygons. This is a common case: a parent’s creation procedure is not necessarily right as creation procedure for the heir. The precise reason is easy to spot; it follows from the observation that a creation procedure’s formal role is to establish the class invariant. The parent’s creation procedure was required to establish the parent’s invariant; but, as we have seen, the heir’s invariant may be stronger (and usually is); we cannot then expect that the original procedure will guarantee the new invariant. In the case of an heir adding new attributes, the creation procedures might need to initialize these attributes and so require extra arguments. Hence the general rule: An inherited creation procedure is still available to the heir as a normal feature of the class (although, as we shall see, the heir may prefer to make it secret); but it does not by default retain its status as a creation procedure. Only the procedures listed in the heir’s own creation clause have that status. Creation Inheritance rule An inherited feature’s creation status in the parent class (that is to say, whether or not it is a creation procedure) has no bearing on its creation status in the heir. See “FEATURE RENAMING”, 15.2, page 535
$14.2 POLYMORPHISM 467 In some cases,of course,a parent's creation procedure may still be applicable as a creation procedure;then you will simply list it in the creation clause: class B inherit A creation make feature 小小 where make is inherited-without modification-from 4,which also listed it in its own creation clause. An example hierarchy For the rest of the discussion it will be useful to consider the POLYGON-RECTANGLE example in the context of a more general inheritance hierarchy of geometrical figure types, such as the one shown on the next page Figures have been classified into open and closed variants.Along with polygons,an example of closed figure is the ellipse,a special case of the ellipse is the circle. Various features appear next to the applicable classes.The symbol+,as noted, means "redefined";the symbols and will be explained later. In the original example,for simplicity,RECTANGLE was directly an heir of POLYGON.Since the sketched classification of polygons is based on the number of vertices,it seems preferable to introduce an intermediate class OUADRANGLE,at the same level as TR/ANGLE,PENTAGON and similar classes.Feature diagonal can be moved up to the level of OUADRANGLE. Note the presence of SOUARE,an heir to RECTANGLE,characterized by the invariant side/side2.Similarly,an ellipse has two focuses (or foci),which for a circle are the same point,giving CIRCLE an invariant property of the form equal (focusl =focus2). 14.2 POLYMORPHISM Inheritance hierarchies will give us considerable flexibility for the manipulation of objects,while retaining the safety of static typing.The supporting techniques, polymorphism and dynamic binding,address some of the fundamental issues of software architecture discussed in part B of this book.Let us begin with polymorphism. Polymorphic attachment "Polymorphism"means the ability to take several forms.In object-oriented development what may take several forms is a variable entity or data structure element,which will have the ability,at run time,to become attached to objects of different types,all controlled by the static declaration
§14.2 POLYMORPHISM 467 In some cases, of course, a parent’s creation procedure may still be applicable as a creation procedure; then you will simply list it in the creation clause: class B inherit A creation make feature … where make is inherited — without modification — from A, which also listed it in its own creation clause. An example hierarchy For the rest of the discussion it will be useful to consider the POLYGON-RECTANGLE example in the context of a more general inheritance hierarchy of geometrical figure types, such as the one shown on the next page. Figures have been classified into open and closed variants. Along with polygons, an example of closed figure is the ellipse; a special case of the ellipse is the circle. Various features appear next to the applicable classes. The symbol ++, as noted, means “redefined”; the symbols + and * will be explained later. In the original example, for simplicity, RECTANGLE was directly an heir of POLYGON. Since the sketched classification of polygons is based on the number of vertices, it seems preferable to introduce an intermediate class QUADRANGLE, at the same level as TRIANGLE, PENTAGON and similar classes. Feature diagonal can be moved up to the level of QUADRANGLE. Note the presence of SQUARE, an heir to RECTANGLE, characterized by the invariant side1 = side2. Similarly, an ellipse has two focuses (or foci), which for a circle are the same point, giving CIRCLE an invariant property of the form equal (focus1 = focus2). 14.2 POLYMORPHISM Inheritance hierarchies will give us considerable flexibility for the manipulation of objects, while retaining the safety of static typing. The supporting techniques, polymorphism and dynamic binding, address some of the fundamental issues of software architecture discussed in part B of this book. Let us begin with polymorphism. Polymorphic attachment “Polymorphism” means the ability to take several forms. In object-oriented development what may take several forms is a variable entity or data structure element, which will have the ability, at run time, to become attached to objects of different types, all controlled by the static declaration
468 INTRODUCTION TO INHERITANCE $14.2 Figure type extent* display* FIGURE hierarchy barycenter* rotate* OPEN CLOSED FIGURE perimeter* FIGURE SEGMENT POLYLINE perimeter POLYGON ELLIPSE perimeter+ TRIANGLE diagonal QUADRANGLE CIRCLE perimeter+ perimeter+ RECTANGLE side1.side2 perimeter+ SQUARE
468 INTRODUCTION TO INHERITANCE §14.2 OPEN_ FIGURE SEGMENT POLYLINE POLYGON ELLIPSE QUADRANGLE CIRCLE TRIANGLE display* rotate* extent* … barycenter* … perimeter* perimeter+ diagonal SQUARE perimeter++ perimeter++ perimeter+ CLOSED_ FIGURE FIGURE perimeter RECTANGLE ++ side1, side2 ∗ ∗ ∗ Figure type hierarchy