📄 chapter 9 designing classes.htm
字号:
<P><PRE> type
A is class
. . .
end class;
B is class
extends A;
. . .
end class;
</PRE>It is important to remember that a hierarchy such as the one above refers
only to instances of class B and and the symbolic representation of any instance
of B. It does not try to represent all classes that inherit from B.
<P>
<H3>9.2.1 Single Inheritance</H3><!-------------------------------------------------------------------------------->As
far as implementation is concerned, classes are in many ways similar to records.
In fact, neglecting certain details, a class in memory looks exactly like a
record. Consider a class like the one shown in listing {CLASSX} <PRE> type
X is class
a: int;
b: char;
c: real;
end class;
<B>listing {CLASSX}.</B>
</PRE>The compiler would lay out such a class in memory in a manner similar to
figure {CLSXMEM}.
<MENU><IMG src="Chapter 9 Designing Classes.files/CLSXMEM.gif">
<P><FONT face=arial size=-1><B>Figure {CLSXMEM}</B> A representation of the
way the members of a class are organized in memory. An integer takes four
bytes, a character one, and a real number takes eight.</FONT></P></MENU>The
elements are stored contiguously in the order that they appear. This would be
the same as for a record.
<P>Single inheritance refers to the types of hierarchies where each class within
a hierarchy directly derives from no more than one superclass. In other words, A
is subclassed by B, which is subclassed by C, which in turn is subclassed by D,
and so on. Multiple inheritance refers to that type of inheritance where any
class within a hierarchy derives from from more than one superclasses. See
figure {SIMI}.
<MENU><IMG src="Chapter 9 Designing Classes.files/SIMI.gif">
<P><FONT face=arial size=-1><B>Figure {SIMI}</B> An example of the difference
between single and multiple inheritance. In multiple inheritance, the
hierarchy may have one or more branches.</FONT></P></MENU>The preferred method
of implementing single inheritance is for the compiler to append the members of
the deriving class onto the end of the base class. Suppose class Y derives from
class X in figure {CLASSX}. <PRE> type
Y is class
extends X;
p, q: int;
end class;
<B>listing {CLASSY}.</B>
</PRE>The compiler would lay out each instance of Y like figure {CLSYMEM}.
<MENU><IMG src="Chapter 9 Designing Classes.files/CLSYMEM.gif">
<P><FONT face=arial size=-1><B>Figure {CLSYMEM}</B> An instance of class Y in
memory.</FONT></P></MENU>Single inheritance is easily implemented. In fact, some
languages stop here due to the complexities of implementing further features.
Most notable of these is Java.
<P>Inheritance immediately introduces one troublesome complexity: suppose class
A inherits from class B, and both classes have an integer X. If we have an
instance of A called a, which x do we get when we say a.X?
<P>This question is solved in two ways, both of which are strictly defined for
SAL. The first is to make use of a special operator that works on classes,
called the scope resolution operator. It is a double colon, ::. To answer the
question posed, we can get at the X belonging to class A by saying a.A::X. We
can likewise get to the X belonging to class B by saying a.B::X.
<P>The second solution is to rely on the order that members and methods shadow
eachother. In SAL, the deriving class shadows the derived class. So when we say
a.X, we implicitly mean a.A::X.
<P>
<H3>9.2.2 Multiple Inheritance</H3><!-------------------------------------------------------------------------------->When
explaining single inheritance, we presented an implementation where the members
of the subclass are appended to those of the superclass. This will not work in
the case of multiple inheritance. When explaining multiple inheritance
implementations, it is easier to think of a superclass being <I>included</I> in
the subclass. Suppose we have a hierarchy where class C inherits directly from
classes A and B. <PRE> type
A is class // A B
i, j: int; // \ /
end class; // \ /
// C
B is class
m, n: int;
end class
C is class
extends A, B;
p, q: int;
end class;
var
c: C;
<B>Listing {CLASSC}.</B> Declaration for class A.
</PRE>An instance of class C will include the contents of classes A and B. In
some languages this order is not defined. In SAL it is. Base classes are
included in the same order that they are listed in the declaration for the
deriving class.
<MENU><IMG src="Chapter 9 Designing Classes.files/CLSCMEM.gif">
<P><FONT face=arial size=-1><B>Figure {CLSCMEM}</B> The contents of classes A
and B are laid out consecutively at the beginning of each instance of class
C.</FONT></P></MENU>Again the issue of shadowing comes in to play, this time
with a new twist. Suppose all three classes A, B, and C had a member integer
called X. If we have an instance of class C, how do we know which class's X we
are dealing with?
<P>Again, the question is solved in the same two ways as before. With scope
resolution we can say c.A::X, and that will give us the member X of class A. We
can say c.C::X, and that will give us the member X of class C. We can also
explicitly designate the path to the variable that we want. c.C::A::X will give
us the same thing as c.A::X.
<P>The second method is to rely on the order of shadowing. This order is
strictly definde in SAL, though in some languages it is not. In SAL, the order
of shadowing closely follows the order that base classes are listed in the
declaration for any deriving class. In our example, for all instances of class
C, all conflicting members of class A will shadow all conflicting members of B,
since C derives first from A and then from B. Thus by default, if both A and B
have a member X, c.X will give us the member X of A. If class C then also had a
member X, c.X would implicitly give us the member X of class C.
<P>In multiple inheritance, and in some cases of single inheritance these two
sloutions make use of eachother. In all cases, the order of scoping determines
which members of which classes shadow the members of the other classes. Scope
designation works by providing a hint in the process. In multiple inheritance, a
superclass can appear more than once in a hierarchy. In all cases, a combination
of judicious use of scope resolution and reliance upon the order of shadowing in
all other cases will resolve ambiguities.
<P>
<H3>9.2.3 Shared Multiple Inheritance</H3><!-------------------------------------------------------------------------------->Shared
multiple inheritance refers to that type of inheritance that in C++ is called
virtual. In SAL we use the term shared instead of virtual, since the word
virtual is a little overused.
<P>Among some OOP programmers, shared (virtual) inheritance is possibly the
worst offense imaginable. Others agree that it is as necessary as a goto, in
other words, to be used sparingly, with caution, and only when absolutely
necessary. After an explanation of how this type of inheritance is implemented,
we will see why.
<P>A graph representing a multiple inheritance hierarchy with virtual
inheritance is shown in figure {MVI}
<MENU><IMG src="Chapter 9 Designing Classes.files/MVI.gif">
<P><FONT face=arial size=-1><B>Figure {MVI}</B> The difference between
multiple and shared multiple inheritance. a) B and C have their own instance
of A. b) B and C share a single instance of A.</FONT></P></MENU>In this scheme,
both B and C inherit from class A. The question arises, if two base classes in
their turn inherit from a common base class, do they each have their own copy,
or do they share a single copy?
<P>C++ allows both types of inheritance, and so does SAL. In many cases, this
question of whether or not a common base class is shared depends upon the design
of the language, itself. C++ and SAL both obted for the maximum flexability.
Other languages might shy away from shared-style multiple inheritance for the
simple fact that is is adds an extra layer of complexity on top of a concept
that is already a hairy and difficult matter.
<P>In SAL, subclasses must specify whether or not they intend to share a single
copy of each superclass individually. Classes may not declare themselves as
shared. Listing {UMI} shows an example of unique multiple inheritance, and
listing {SMI} demonstrates the same classes using shared inheritance.
<P><PRE> type
A is class
x, y: int; // A A
end class; // | |
// | |
B is class // B C
extends A; // \ /
// \ /
m, n: int // D
end class;
C is class
extends A;
p, q: int
end class;
D is class
extends B, C;
i, j: int
end class;
<B>Listing {UMI}.</B> Unique Multiple Inheritance
type
A is class
x, y: int;
end class; // A
// / \
B is class // / \
extends shared A; // B C
// \ /
m, n: int // \ /
end class; // D
C is class
extends shared A;
p, q: int
end class;
D is class
extends B, C;
i, j: int
end class;
<B>Listing {SMI}.</B> Shared Multiple Inheritance
</PRE>Member and method access rules have been strictly defined up to this
point. All rules for the default order of scoping and scope designation still
apply. The only new consideration is that there will be multiple paths to a
single member or method within a shared group. This can introduce ambiguities
that are not easily resolved without the use of these two utilities.
<P>
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -