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