Covariant returns

Jim Dehnert dehnert at baalbek.engr.sgi.com
Wed Jul 5 21:23:40 UTC 2000


Let me try introducing some concreteness into this discussion.  I
think I've figured out the source of confusion, but then maybe I've
just become confused...

Suppose we have:

	class A { ... };
	class B: public A { ... };

	class V {
		...
		virtual A* f ();
		...
	};
	class W: virtual public V {
		...
		virtual B* f ();
		...
	};

	W *w;
	V *v = w;

Suppose initially that no bases are primary.  (And check my example
before you believe anything...)

Now, if I call w->f(), I get the basic W::f, with no adjustments.
This is what should happen if I use the "normal" entry for f in the W
vtable.

If I call v->f(), it's more complicated.  I get a thunk which (a)
adjusts v to a W*, (b) calls W::f, and (c) adjusts the resulting B*
back to an A*.  This is what should happen if I use the "normal" entry
for f in the V-in-W secondary vtable.

So far, so good.  The W vtable contains the overriding W::f vptr.
The V-in-W secondary vtable contains the thunk vptr.  Nothing special
for the covariant return types, except that the thunk is messier.
I note, as an aside so far, that if W did not override V::f, we would
have a "promoted" vptr for it in the W vtable to make it easier to
call.  But that has nothing to do with covariant return types either.

Next, suppose V is the primary base of W.  Now they share a vtable, and
therefore an f vptr.  If the f's had the same return type, there would
be no adjustments to be made, and that f vptr could just point to the
overriding W::f.  But because they have covariant return types, v->f()
must still adjust on return, so the "shared" vptr must do that, and W's
vtable needs to have another entry for the "normal" W::f vptr.  What we
decided before (issue B-2), and what seems to have started Mark down
this discussion path, is that we will have two such entries whether or
not a caller could figure out the necessary adjustment (B* to A*, I
presume), though I don't know how it could be possible in general if he
is calling v->f().

(My thoughts went down a dark alley at this point.  Even if the return
types were the same, if X is derived from V and W in such a way that V
is no longer primary in the W subobject, then V::f and W::f would need
different adjustments and therefore distinct entries.  So I thought
briefly that this required two entries in the W vtable.  But if V and W
are split in this way, the main entry in the W-in-X vtable is no longer
shared with the V-in-X vtable, so this was a red herring.)

Finally, suppose we have:

	class X: virtual public W {
	  ...
	};

Now, we specify that the vptrs from W get promoted to the X vtable.
That presumably means both of them in the case at hand.  Correct?
I'm guessing that this was Mark's original point.  Correct?  Am I
missing anything that Jason or Mark was trying to point out? Screwing
it up?  Where precisely do we need to say more in the draft?

Jim

-	    Jim Dehnert		dehnert at sgi.com
				(650)933-4272




More information about the cxx-abi-dev mailing list