⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 chapter 10 virtual methods.htm

📁 英文版编译器设计:里面详细介绍啦C编译器的设计
💻 HTM
📖 第 1 页 / 共 3 页
字号:
<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 + -