Re: Virtual function call from constructor
"Eric Sosman" <esosman@acm-dot-org.invalid> wrote in message
news:j6KdnZCfVvlWfuPbnZ2dnUVZ_segnZ2d@comcast.com...
Mike Schilling wrote:
"Eric Sosman" <esosman@acm-dot-org.invalid> wrote in message
news:dp-dnSoXCdbi6OPbnZ2dnUVZ_hadnZ2d@comcast.com...
I *did* use the word "bloat," and it still seems justifiable.
The implementation you describe (if I've understood you correctly)
requires each instance to carry a pointer per inheritance level;
that's certainly larger than the one bit per level I described as
a hypothetical implementation, and that in turn is larger than
no per-instance "construction status" at all.
Not at all. It requires each instance to hold one pointer, period. The
*value* of this pointer is changed during construction.
Aha! So if you've got a class that's N levels deep in the
inheritance hierarchy, you've got N+1 versions of the vtable,
each corresponding to a different amount of progress through
the constructor chain. Is that it?
Each class that contains virtual functions defines a vtable. Each instance
of one of these classes contains one pointer, which points to its class's
vtable. So an instance of String points to String's vtable, an instance of
Thread points to Thread's vtable,etc. So far, just as you'd expect. If you
replace "vtable" by "Class object" and observe that all Java classes contain
virtual functions (the ones they inherit from Object, at least), exactly
like Java.
What C++ does differently is this: During construction, the value of that
vtable pointer can changes. It will always point to the vtable for the
class that defines the constructor. So (to use a Java-like example, for
familiarity), when a PrintStream is being constructed, it does something
,like this:
Point to Object vtable
Run Object constructor
Point to OutputStream vtable
Run OutputStream constructor
Point to FilterOutputStream vtable
Run FilterOutputStream constructor
Point to PrintStream vtable
Run PrintStream constructor
At the end of this, the vtable is (correctly) left pointing to the
PrintStream vtable, which it keeps for the rest of its left. It's possible
that the reverse process happens during destruction, but I can't say for
sure. If so, it would be nicely symmetrical.
Hmmm... If that's the way it works, then defining an Nth
level class really defines N+1 distinct classes, in the sense
that a class is the set of its behaviors.
Not really, because the superclasses already exist. You're defining only
one new class.
If applied to an
object in the midst of construction, which of those N+1 classes
should getClass() return? And how should instanceof behave?
C++ doesn't have either of those per se. It does have some limited
reflection, for instance the <dynamic_cast> operator, which does a similar
job to instanceof, which I presume would base the current type of the
object on the current vtable, so that, in effect,
x instanceof PrintStream
would be false during the running of the FilterOutputStream constructor.
Which makes a certain amount of sense: none of the PrintStream fields have
been initialized, nor are PrintStream-specific methods available.
Think of it this way. When the Object constructor is running, the instance
*is* an Object. It may have some extra space allocated at the end, but no
one can make any use of it. Now, when the OutputStream constructor is
running, the instance *is* an OutputStream. It may have some extra space
allocated at the end, but no one can make any use of it. etc. Finally, when
the PrintStream constructor runs, it *is* a PrintStream.