📄 chapter 10 virtual methods.htm
字号:
<H3>10.2.2 Virtual Methods in Multiple Inheritance</H3><!-------------------------------------------------------------------------------->In
multiple inheritance, since base classes are laid out in parallel instead of
inline, the vtables and indexing proceeds in a slightly different manner. The
problem is twofold. Each base class has its own vtable pointer, and each base
class has started its virtual indexing at zero, To overcome this, we do two
things.
<P>First, the deriving class lays out the vtable in a manner that is similar to
the layout of its member data, and although there is only one vtable, each base
class points directly to its part in the vtable. The first base class is at the
start of the vtable, and the next comes after that, and so on. The deriving
class then shares the vtable pointer with the first base class it inherits
<P>The second thing that we do is have the base class begin its indexing by
adding together the count of all the virtual methods of all its base classes.
Consider listing {CLSVRST}. <PRE> type
S is class
a, b, c: int;
virtual proc foo;
begin
write "I am S::foo().\n";
end proc;
virtual proc bar;
begin
write "I am S::bar().\n";
end proc;
end class;
T is class
i, j, k: int;
virtual proc baz;
begin
write "I am T::baz().\n";
end proc;
virtual proc barf;
begin
write "I am T::barf().\n";
end proc;
end class;
R is class // S T
extends S, T; // \ /
// \ /
m, n, o: int; // R
proc foo;
begin
write "I am R::foo().\n";
end proc;
proc baz;
begin
write "I am S::baz().\n";
end proc;
virtual proc foobar;
begin
write "I am Q::foobar().\n";
end proc;
end class;
<B>Listing {CLSVRST}.</B> A listing for a simple virtual inheritance
hierarchy.
</PRE>Since classes <TT>S</TT> and <TT>T</TT> each have two virtual methods,
class <TT>R</TT> will begin its indexing at four. A full layout for class
<TT>R</TT> is demonstrated in figure {MEMVRST}.
<CENTER><IMG src="Chapter 10 Virtual Methods.files/MEMVRST.gif"></CENTER>The
most significant thing about figure {MEMVRST} is the locations of the two vtable
pointers, and the areas in the vtable that they are pointing to. Although
<TT>S</TT> points to the start of the vtable, <TT>T</TT> points to the third
entry. <TT>R</TT> shares <TT>S</TT>'s vtable pointer, and begins its indexing at
four.
<P>Additionally, since <TT>T::baz()</TT> has been overridden by
<TT>R::baz()</TT>, The delta for this entry is set to the difference between a
pointer to <TT>T</TT> and a pointer to <TT>R</TT>. We will now explain the use
of the delta.
<P>The delta is useful in multiple and in shared inheritance. Consider the class
in listing {CLSVRST}, and a pointer to base class <TT>T</TT>, declared like so: <PRE> var
pT: ^T;
</PRE>The pointer <TT>pT</TT> can be used to point to the base class <TT>T</TT>
of an instance of <TT>R</TT>, like so: <PRE> begin
pT:= new(R);
. . .
</PRE>This is very different from having <PRE> begin
pT:= new(T);
. . .
</PRE>In both cases, <TT>pT</TT> points to an instance of class <TT>T</TT>.
However, in the first case, the instance of <TT>T</TT> is a part of (a base
class for) an instance of <TT>R</TT>. In the second case, <TT>pT</TT> points to
a pure instance of class <TT>T</TT>.
<P>In the second case, an instance of <TT>T</TT> will have a vtable layout much
like the layout for class <TT>C</TT> in listing {CLSVC} and figure {MEMVC}. In
the first case, the instance's vtable pointer will point to an area within
<TT>R</TT>'s vtable. In this case, a call to <TT>pT^.baz();</TT> will result in
an invocation of <TT>R::baz()</TT>. In the second case, it will not. This is
further explained in figure {PTRARB}.
<CENTER><IMG src="Chapter 10 Virtual Methods.files/PTRARB.gif"></CENTER>The
general pattern presented here for layout of vtables in multiple inheritance is
consistant for the layout of more complex heirarchies. Consider listing {CLSVPQ}
<PRE> type
Q is class
x, y, z: int;
virtual proc foobar;
begin
write "I am Q::foobar().\n";
end proc;
virtual proc foobaz;
begin
write "I am Q::foobaz().\n";
end proc;
end class;
P is class // S T
extends Q, R; // \ /
// \ /
u, v, w: int; // Q R
// \ /
proc foo; // \ /
begin // P
write "I am P::foo().\n";
end proc;
proc foobar;
begin
write "I am P::foobar().\n";
end proc;
end class;
<B>Listing {CLSVRST}.</B> A more complex virtual inheritance hierarchy.
</PRE>In this case, class <TT>Q</TT> will come first in the layout for instances
of <TT>P</TT>. Additionally, <TT>P</TT> will begin its virtual indexing at nine,
since <TT>Q</TT> has two virtual methods, and <TT>R</TT> has seven. An instance
of <TT>P</TT> is portrayed in figure {MEMVP}
<CENTER><IMG src="Chapter 10 Virtual Methods.files/MEMVP.gif"></CENTER>
<H3>10.2.3 Virtual Methods With Shared Inheritance</H3><!-------------------------------------------------------------------------------->The
same rules apply to shared inheritance that were used in single and multiple
inheritance. The only addition to these rules is the group concept. So then,
just as class instances are organized into groups, so are their vtables. Listing
{CLSVYZ} has a base class and a deriving class that inherits a shared instance
of the base class.
<P><PRE> type
Z is class
p, q, r: int;
virtual proc foo;
begin
write "I am Z::foo().\n";
end proc;
virtual proc bar;
begin
write "I am Z::bar().\n";
end proc;
end class;
Y is class
extends shared Z;
a, b, c: int;
proc foo;
begin
write "I am Y::foo().\n";
end proc;
virtual proc baz;
begin
write "I am Y::baz().\n";
end proc;
end class;
<B>Listing {CLSYZ}.</B> two classes demonstrating virtual functions in
shared inheritance.
</PRE>As can be seen by the layout in figure {MEMVYZ}, The class is partitioned
into two groups in both the instance and the vtable. Vtables under shared
inheritance are always laid out by group using the same method for single and
multiple inheritance within each group layout. A significant difference with
shared inheritance over multiple inheritance is in virtual indexing. A deriving
class normally adds the count of virtual methods for all base classes together
to get its starting virtual index. Under shared inheritance, a deriving class
adds the count of virtual methods for all base classes that are not shared. So,
if a class inherits three base classes and only one of those are shared, it will
add the virtual counts of the two unique base classes and begin its virtual
indexing at that result. Figure {MEMVYZ} demonstrates this.
<CENTER><IMG src="Chapter 10 Virtual Methods.files/MEMVYZ.gif"></CENTER>Class
<TT>Y</TT> only overrides one of <TT>Z</TT>'s methods. Notice the delta in
<TT>Z</TT>'s virtual table for method <TT>foo()</TT>. With a pointer to
<TT>Z</TT>, a call to <TT>foo()</TT> will be routed to <TT>Y::foo()</TT>, and a
delta of -20 will be added to the reference to self promoting the pointer to
<TT>Z</TT> to a pointer to <TT>Y</TT>, so that the call can be completed
successfully.
<P>Next, we will make another class that inherits from <TT>Z</TT> called
<TT>X</TT>, and then declare a base class that inherits both <TT>Y</TT> and
<TT>X</TT>. See Listing {CLSVW}. <PRE> type
X is class
extends shared Z;
i, j, k: int;
proc foo;
begin
write "I am X::foo().\n";
end proc;
virtual proc baz;
begin
write "I am X::baz().\n";
end proc;
end class;
W is class
extends X;
extends Y;
t, u, v: int;
proc bar;
begin
write "I am W::bar().\n";
end proc;
proc baz;
begin
write "I am W::baz().\n";
end proc;
end class;
<B>Listing {CLSVW}.</B> Another class that inherits a shared instance of Z
called X, and a class that inherits both Y and X called W.
</PRE>This hierarchy introduces another question that has to be solved in shared
inheritance. Both <TT>X</TT> and <TT>Y</TT> inherit a shared instance of
<TT>Z</TT>, and they both override <TT>Z::foo()</TT>. So whenever
<TT>Z::foo()</TT> is invoked, which one really gets called? For a long time in
C++ this situation was undefined. In SAL it depends upon the hierarchy, and in
this case, <TT>X::foo()</TT> takes precidence. In all cases, the compiler
traverses the hierarchy left edge first at compile time. The first virtual
method match that is lowest in the hierarchy going in a leftmost traversal is
the one that overrides.
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -