[comp.lang.c++] Virtual functions used in constructor illegal ! ??

basti@orthogo.UUCP (Sebastian Wangnick) (11/23/90)

I just recognized that my cfront 2.0 installs the vtable
of a derived class only *after* the constructor of the
base class is called.

This implies that you are not allowed to use virtual member
functions within the constructor of an abstract base class.

Here an example program that you can compile to see whether
other compilers do the same:

extern "C" void abort ();
extern "C" void printf (...);
typedef int Rect;

class Window
   {
public:
   Window (Window* parent = 0);
   virtual Rect Size ();
   virtual void ChildAdd (Rect size) {}
   };

Window::Window (Window* parent)
   {if (parent)
      parent->ChildAdd(Size());
   }

Rect Window::Size () 
	{printf("SubclassResponsibility\n"); abort(); return 0;}

class NullWindow: public Window
   {
public:
   NullWindow (Window* parent = 0) : (parent) {}
   virtual Rect Size () {return 0;}
   };

void main ()
   {Window* parent = new NullWindow;
   Window* child = new NullWindow(parent);
   }

What will happen if you compile this? Well, my cfront2.0-generated code 
returns "SubclassResponsibility" because from within the constructor of
class Window the function Window::Size is called, not NullWindow::Size
as I expected!

Now: Is this a bug or a feature ??

Sebastian Wangnick (basti@orthogo.uucp)

jbuck@galileo.berkeley.edu (Joe Buck) (11/27/90)

Not illegal, they just don't do what you think.

In article <822@orthogo.UUCP>, basti@orthogo.UUCP (Sebastian Wangnick) writes:
> I just recognized that my cfront 2.0 installs the vtable
> of a derived class only *after* the constructor of the
> base class is called.

> This implies that you are not allowed to use virtual member
> functions within the constructor of an abstract base class.

This is documented in Ellis and Stroustrup's Annotated C++ Reference
Manual, which the ANSI committee is using as the base document for
the official standard.  The standard actually says that if you
do call a virtual method in the constructor, that the base class
method is always called, even if you redefine the method.  That is,
if you have

class Derived: public Base {
	...
}

any virtual methods you call in the constructor for Derived act
as though the object were of type Base.

> Now: Is this a bug or a feature ??

It's a feature (and a required one at that).  Any compiler that
does what you want violates the standard.


--
Joe Buck
jbuck@galileo.berkeley.edu	 {uunet,ucbvax}!galileo.berkeley.edu!jbuck	

rpk@rice-chex.ai.mit.edu (Robert Krajewski) (11/27/90)

If the base class constructor could use a function designed to be used
with a derived class instance, that (derived) function might try to refer to
data members that weren't yet initialized.  In a sense, an object
``evolves'' as more and more specialied constructors are run.

The problem is that we would like the C++ constructor and destructor
mechanism to handle *all* the semantics of creating and destroying and
object, including tasks that must be invoked (using virtual functions)
on all members of base class from which other classes are expected to
be derived.  You can get around this calling separate functions for
initialization and deletion, but such a technique is awkward for
stack-allocated objects.
----
Robert P. Krajewski
Internet: rpk@ai.mit.edu ; Lotus: robert_krajewski.lotus@crd.dnet.lotus.com

chip@tct.uucp (Chip Salzenberg) (11/30/90)

According to jbuck@galileo.berkeley.edu (Joe Buck):
>[E&S] actually says that if you do call a virtual method in the
>constructor, that the base class method is always called, even
>if you redefine the method.

This is true, but only if you are calling the virtual function from
the actual constructor function body.  If you call a virtual function
from a constructor by other means, such as calling a function that
calls the virtual function, E&S says that the behavior is undefined,
i.e. all bets are off.
-- 
Chip Salzenberg at Teltronics/TCT     <chip@tct.uucp>, <uunet!pdn!tct!chip>
    "I've been cranky ever since my comp.unix.wizards was removed
         by that evil Chip Salzenberg."   -- John F. Haugh II

jimad@microsoft.UUCP (Jim ADCOCK) (12/04/90)

In article <822@orthogo.UUCP> basti@orthogo.UUCP (Sebastian Wangnick) writes:
|I just recognized that my cfront 2.0 installs the vtable
|of a derived class only *after* the constructor of the
|base class is called.
|
|This implies that you are not allowed to use virtual member
|functions within the constructor of an abstract base class.
....
|Now: Is this a bug or a feature ??

This is a "feature" -- IE this is how the C++ language is defined.  While
in the base class constructor your object is only a base object, it does
not become a derived object until the derived constructor begins to work
on it.  Compilers may rely on this language definition to play with the
nasty bits such as vtable and vbase pointers during construction.  Thus,
attempting to defeat this language "feature" will be problematic and 
non-portable at best.

Likewise in destructors, while in the derived class destructor your object
is a derived object, but afterwards when the base destructor is called
your object has regressed to becoming just a base object again.

These "features" allow base class constructors and destructors to be
implemented in sensible ways despite what future class implementors might
do in derived classes.  Even the permission to use derived class virtual
functions in the derived class constructor could be viewed as problematic,
since your derived class object does not fully become such until the
end of the derived class constructor.  However, it was assumed that
derived class writers could reasonably be held responsible for their
own actions in using their own virtual functions within their own 
constructors.  But beware: deamons lurk in wait for those who so use
virtual functions!

[In my opinion, one is best not to do substantive work inside a constructor
in the first place.  Constructors are best used to do things to 
place an object into the simplest mode where that object can meet its
class invariants.  Do your substative work, such as virtual function calls,
after the constructors [standard disclaimer]]

pal@xanadu.wpd.sgi.com (Anil Pal) (12/05/90)

In article <27556AD1.350C@tct.uucp>, chip@tct.uucp (Chip Salzenberg) writes:
[ Referring to constructor calling base class virtual function]
|> This is true, but only if you are calling the virtual function from
|> the actual constructor function body.  If you call a virtual function
|> from a constructor by other means, such as calling a function that
|> calls the virtual function, E&S says that the behavior is undefined,
|> i.e. all bets are off.

Are you sure about this?  My copy of E&S says (page 294, sec. 12.7)

    Member functions may be called in constructors and destructors.
    This implies that virtual functions may be called (DIRECTLY OR
    INDIRECTLY [emphasis mine]).  The function called will be the one
    defined in the constructor's (or destructor's) own class  or its
    bases, but *not* any function overriding it in a derived class.
    [...]

    The effect of calling a PURE [emphasis mine] virtual function
    directly or indirectly [...] is undefined.

If what you say is in fact stated somewhere else in E&S, then there is
a definite contradiction.

-- 
Anil A. Pal,	Silicon Graphics, Inc.
pal@sgi.com	(415)-335-7279

chip@tct.uucp (Chip Salzenberg) (12/08/90)

A long time ago, someone (okay, it was me) wrote:
> If you call a virtual function from a constructor [indirectly],
> E&S says that the behavior is undefined, i.e. all bets are off.

In response, pal@sgi.com quoted E&S page 294, section 12.7:
>    Member functions may be called in constructors and destructors.
>    This implies that virtual functions may be called (DIRECTLY OR
>    INDIRECTLY [emphasis mine]).  The function called will be the one
>    defined in the constructor's (or destructor's) own class  or its
>    bases, but *not* any function overriding it in a derived class.
>    [...]
>
>    The effect of calling a PURE [emphasis mine] virtual function
>    directly or indirectly [...] is undefined.

Mea culpa, mea culpa, mea maxima culpa.  Pal's quotation is correct,
I was wrong, the truth is known, and the world is a better place.
-- 
Chip Salzenberg at Teltronics/TCT     <chip@tct.uucp>, <uunet!pdn!tct!chip>
      "I'm really sorry I feel this need to insult some people..."
            -- John F. Haugh II    (He thinks HE'S sorry?)

pkt@lpi.liant.com (Scott Turner) (12/08/90)

In article <27556AD1.350C@tct.uucp> chip@tct.uucp (Chip Salzenberg) writes:
>This is true, but only if you are calling the virtual function from
>the actual constructor function body.  If you call a virtual function
>from a constructor by other means, such as calling a function that
>calls the virtual function, E&S says that the behavior is undefined,
>i.e. all bets are off.

Actually, p. 294 of E&S says that virtual functions can be called
from constructors "directly or indirectly".  What Chip may have
in mind is that a call to a _pure_ virtual function from a constructor
is in general undefined.

--
Prescott K. Turner, Jr.
Language Processors, Inc.
959 Concord St., Framingham, MA 01701 USA    (508) 626-0006
UUCP: uunet!lpi!pkt                          Internet: pkt@lpi.liant.com