Topic: virtual calls in constructor


Author: Loic Tregan <Loic.Tregan@cert.fr>
Date: 1998/03/04
Raw View
Kirk Odle wrote:
> curiosity rather than something of any practical use. I agree
> wholeheartedly that the practice of calling virtual functions from
> constructors is a likely source of "bugs" or unexpected program
> behavior.

 As the author of the original message, I remember the need for
virtual calls in ctor :
   class A {
  private :
     int _x;
  public
     A(int x) { SetX(x) };
     virtual int GetX();
     virtual void SetX( int x );
  }

 class B : public A {
   B() {.. }
   virtual SetX( int x );
 }

it is the paradigm of "properties", used in JAVA, Delphi, C++Builder.
Now the question is : should the call of SetX() be virtual or not ?
Sure, it safer to answer no ( as B::SetX may need as preconditions
some inits done in B::B() ).
Sure, it is more pragmatic to answer yes. because if the virtual calls
are not allowled, in B::B() I have to call expliclty SetX. if they are
10 properties, it may be a bit annoying ... And what about if a new
property is added to the base class :  all the derived classes have to
be updated.

Another solution is to make the difference between the construction of
the object and its initialisation : so it is 'forbidden' to give the
values of the properties at object creating :

  A a( 5 ); // no !!!

  A a;
  a.SetX( 5); // OK

I don't like this, because my feeling is that we must give all the
parameters that are needed for the object to its ctor : it is stupid to
create a Customer object without specifiying its name or its ID. None
of the methods of the Customer may work if its name is not given. So
for mee, the name must be given to the constructor, so virtual calls in
ctor are needed.  Another reason against the separation of construction
and initialization is that properties are initialized with default
value ( A(v1,v2,..) member1(v1), memeber2(v2) .. {} is not allowed ).

It is the responsability of the programmer to check in its overriden
function if the ctor has been previously called or not. The
preconditions of the functions must always be checked, since the cases
where these preconditions are filled by the ctor are very very sparse.
---
[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://reality.sgi.com/austern_mti/std-c++/faq.html              ]





Author: jkanze@otelo.ibmmail.com
Date: 1998/03/06
Raw View
In article <34FD5043.A70@cert.fr>,
  Loic Tregan <Loic.Tregan@cert.fr> wrote:
>
> Kirk Odle wrote:
> > curiosity rather than something of any practical use. I agree
> > wholeheartedly that the practice of calling virtual functions from
> > constructors is a likely source of "bugs" or unexpected program
> > behavior.
>
>  As the author of the original message, I remember the need for
> virtual calls in ctor :
>    class A {
>   private :
>      int _x;
>   public
>      A(int x) { SetX(x) };
>      virtual int GetX();
>      virtual void SetX( int x );
>   }
>
>  class B : public A {
>    B() {.. }
>    virtual SetX( int x );
>  }

This particular case is actually easily handled by means of a helper
class, e.g.:

    class AHelper ;
    class A ;

    class A
    {
    public:
       A( AHelper const& initialValue ) ;
 virtual             ~A() ;
 virtual             setX( int x ) const = 0 ;
 virtual             getX() = 0 ;
    } ;

    class AHelper
    {
 friend class        A ;
    public:
       AHelper( int x ) ;
       ~AHelper() ;
    private:
 int                 myValue ;
 A*                  myOwner ;
    } ;

    A::A( AHelper const& initialValue )
 ,   myX( 0 )
    {
 initialValue.myOwner = this ;
    }

    AHelper::AHelper( int x )
 :   myValue( x )
 ,   myOwner( NULL )
    {
    }

    AHelper::~AHelper()
    {
 if ( myOwner != NULL )
     myOwner->setX( myValue ) ;
    }

The int passed as argument automatically converts to a temporary AHelper,
whose destructor is called at the end of the full expression, i.e. when
the constructor of A, and of all its derived classes, has finished running,
and the object has its final type.  Obviously, the derived classes must
declare an appropriate constructor, and pass the object down.

This isn't a general solution, of course, but it may be useful specific
cases like the above.

--
James Kanze    +33 (0)1 39 23 84 71    mailto: kanze@gabi-soft.fr
        +49 (0)69 66 45 33 10    mailto: jkanze@otelo.ibmmail.com
GABI Software, 22 rue Jacques-Lemercier, 78000 Versailles, France
Conseils en informatique orient   e objet --
              -- Beratung in objektorientierter Datenverarbeitung

-----== Posted via Deja News, The Leader in Internet Discussion ==-----
http://www.dejanews.com/   Now offering spam-free web-based newsreading
---
[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://reality.sgi.com/austern_mti/std-c++/faq.html              ]





Author: Pete Becker <petebecker@acm.org>
Date: 1998/03/01
Raw View
David Goh wrote:
>
>
> And construct one of them... and you'll get the following:
>
> Base::Base()
> Base::f()
> Derived::Derived()
> Derived::f()
> Grandkid::Grandkid()
> Derived::f()
> GreatGrandkid::GreatGrandkid()
> GreatGrandkid::f()
> GreatGrandkid::~GreatGrandkid()
> GreatGrandkid::f()
> Grandkid::~Grandkid()
> Derived::f()
> Derived::~Derived()
> Derived::f()
> Base::~Base()
> Base::f()
>
> The point is, the call *is* virtual, because Grandkid's call to f() calls
> Derived::f() successfully... and the call is not ambiguous.

This does not mean that the call to f() is virtual. If you remove the
virtual keyword throughout, you'll get exactly the same behavior.
---
[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://reality.sgi.com/austern_mti/std-c++/faq.html              ]





Author: Pete Becker <petebecker@acm.org>
Date: 1998/03/01
Raw View
Pete Becker wrote:
>
 This does not mean that the call to f() is virtual. If you remove the
> virtual keyword throughout, you'll get exactly the same behavior.

Whoops, never mind. I misread the example.
 -- Pete
---
[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://reality.sgi.com/austern_mti/std-c++/faq.html              ]





Author: "Kirk Odle" <kodle@ghg.net>
Date: 1998/03/01
Raw View
I'm replying to myself.

I overlooked a very important qualifier in the original poster's
text. That is, he correctly conveyed the message that calling
a virtual function from the BODY of a constructor is defined
by the standard. It is assuredly not defined for the initializer
list. The effect of calling the virtual function from the body
(whether you attempt to force static binding with fully-qualified
syntax) is the same as for a static call. In effect, at the time the
body of a constructor body is executed, the type of the object
is the class of which the constructor is a member.

Kirk Odle wrote in message <34ecf572.0@news.ghgcorp.com>...
>Valentin Bonnard wrote in message <34EB9CAD.74A3@pratique.fr>...
>>Piet Van Vlierberghe wrote:
>>
>>> Still, I believe the restraint on the constructor is a petty one, since
>>> it IS allowed to call nonvirtual member functions from the constructor,
>>> and these functions are free to call whatever virtual function they
>>> like.
>>
>>You can call virtual or non-virtual functions in a ctor, just not
>>a pure virtual function.
>
>True, you can call them.
>
>>Virtual functions will be called according
>>to the dynamic type, as usuall. In the body of ctor T::T the dynamic
>>type is T.
>
>That could happen.  Or it might not.  The standard says the result is
>undefined.
>Please don't sell me any software that you've written that practices this.
---
[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://reality.sgi.com/austern_mti/std-c++/faq.html              ]





Author: "Kirk Odle" <kodle@ghg.net>
Date: 1998/03/01
Raw View
Jon Sturgeon wrote in message <34f42849.430238440@news.flash.net>...

>OK, That point I take.  Perhaps I was answering a subtly different
>question to the one originally asked.  I suspect that calling a
>virtual function in a ctor is going to be a likely source of bugs;
>however I accept that it *is* a virtual call.


Whether it is virtual or not is, I believe, a matter of intellectual
curiosity rather than something of any practical use. I agree
wholeheartedly that the practice of calling virtual functions from
constructors is a likely source of "bugs" or unexpected program
behavior. The key is the expectation.  Will a given programmer consider
that the behavior of the virtual function may differ from that defined
by whatever the static type of the fully-constructed object might be?
If so, will he conclude correctly that the static type associated with
the constructor's class best describes that behavior? Will he verify
his conclusion, whatever it is, by consulting the standard's document?
If not, will he attempt to verify his conclusion with a nontrivial test
case?

If we can draw conclusions from the behavior of preeminent contributors
to this newsgroup, I think the answer to each of those questions is "no"
and unexpected behavior will result.
---
[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://reality.sgi.com/austern_mti/std-c++/faq.html              ]





Author: Pete Becker <petebecker@acm.org>
Date: 1998/03/01
Raw View
Pete Becker wrote:
>
> This does not mean that the call to f() is virtual. If you remove the
> virtual keyword throughout, you'll get exactly the same behavior.

Whoops, ignore my retraction. I did read the example correctly.
 -- Pete


[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://reality.sgi.com/austern_mti/std-c++/faq.html              ]






Author: "John D. Hickin" <hickin@CAM.ORG>
Date: 1998/03/02
Raw View
Pete Becker wrote:

> This does not mean that the call to f() is virtual. If you remove the
> virtual keyword throughout, you'll get exactly the same behavior.

One way to get information is to make the one of the classes have a pure
virtual f() and call it from the constructor. Then either:

1) The compiler will warn you right away that you are calling a pure
   virtual, or
2) You will get a core dump or access violation if you run it.

Note that a pure virtual may have an implementation and that it can be
invoked using the :: resolution.

To summarize:

1) If f() is virtual then this->f() is a virtual call.
2) X::f() is never a virtual call.


[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://reality.sgi.com/austern_mti/std-c++/faq.html              ]






Author: "Mark Rodgers" <mark.rodgers@xtra.co.nz>
Date: 1998/02/23
Raw View
Jon Sturgeon wrote in message <34ed8c2b.157445033@news.flash.net>...
>On 19 Feb 98 03:20:30 GMT, Valentin Bonnard <bonnardv@pratique.fr>
>wrote:
>>You can call virtual or non-virtual functions in a ctor, just not
>>a pure virtual function. Virtual functions will be called according
>>to the dynamic type, as usuall. In the body of ctor T::T the dynamic
>>type is T.
>
>No! This is not correct.  Virtual functions when called in a class's
>*constructor* will be called with the object's static type at that
>time, ie they will NOT be virtual.  This is because if a class D
>derives from class B, class D has not been constructed by the time the
>B ctorhas been called.  Therefore, it is not possible to call any
>methods in D.


You didn't read what Valentin wrote.  The function is called according
to the object's *dynamic* type, it's just that the dynamic type is not
what its ultimate dynamic type will be (Valentin's last sentence).

Consider this:

#include <iostream>
struct C1      {       virtual void foo() { cout << "C1"; } };
struct C2 : C1 { C2(); virtual void foo() { cout << "C2"; } };
struct C3 : C2 {       virtual void foo() { cout << "C3"; } };

C2::C2() { C1 *c = this; c->foo(); }

int main()
{
     C3 c;
}

This is well formed and will print "C2".  The function is virtual
and despite being called through the C1 pointer, the object's
dynamic type is used to determine the function called.  It's just
that the dynamic type is C2 and not yet C3.

Mark
mark.rodgers@xtra.co.nz



[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://reality.sgi.com/austern_mti/std-c++/faq.html              ]






Author: "Martijn Lievaart" <mlievaar@orion.nl>
Date: 1998/02/23
Raw View
Kirk Odle wrote:
>Valentin Bonnard wrote in message <34EB9CAD.74A3@pratique.fr>...
>>Piet Van Vlierberghe wrote:
>>
>>> Still, I believe the restraint on the constructor is a petty one, since
>>> it IS allowed to call nonvirtual member functions from the constructor,
>>> and these functions are free to call whatever virtual function they
>>> like.
>>
>>You can call virtual or non-virtual functions in a ctor, just not
>>a pure virtual function.
>
>True, you can call them.
>
>>Virtual functions will be called according
>>to the dynamic type, as usuall. In the body of ctor T::T the dynamic
>>type is T.
>
>That could happen.  Or it might not.  The standard says the result is
>undefined.
>Please don't sell me any software that you've written that practices this.


I don't have the new standard here, but based on the ARM I have to agree
with Valentin.

ARM r.12.7
"Member functions may be called in constructors and destructors. This
implies that virtual functions may be called (directly or indirectly) . The
function called will be the one defined in the constructors (or destructors)
own class or its bases, but *not* any function overriding it in a derived
class. This ensures that unconstructed objects will not be accessed during
construction or destruction.
[Example deleted]
The effect of calling a pure virtual function directly or indirectly for the
object being constructed from a constructor, except using explicit
qualification, is undefined (r.10.3)"

Can you explain why you think this is undefined? Is this a change in the
standard?

Greetz,
Martijn
(mlievaar(at)nospam(remove-that)orion(dot)nl)




[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://reality.sgi.com/austern_mti/std-c++/faq.html              ]






Author: Gerard Weatherby <gerardw@alum.mit.edu>
Date: 1998/02/23
Raw View
Jon Sturgeon wrote:

> No! This is not correct.

You just said the same thing as Valentin.

Valentin said:
"In the body of ctor T::T the dynamic type is T."

and you say,
"B's ctor will call B::f(),"


[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://reality.sgi.com/austern_mti/std-c++/faq.html              ]






Author: JonS@futuresoft.nospam.com (Jon Sturgeon)
Date: 1998/02/23
Raw View
On 22 Feb 1998 16:49:57 GMT, Valentin Bonnard <bonnardv@pratique.fr>
wrote:

>Jon Sturgeon <JonS@futuresoft.nospam.com> writes:
[snip]
>> Virtual functions when called in a class's
>> *constructor* will be called with the object's static type at that
>> time, ie they will NOT be virtual.
>
>This wrong. Virtual functions are called according to the
>dynamic type except when they are explicitly qualified with
>a clas name as in X::f ().
>
>Calling a virtual function is ok unless it is pure virtual
>in the class (in which case undefined behaviour follows
>(which in most cases prints 'pure function called')).
>
>> Hope this clears this up.
>
>Everything is already clear to me.

Well, Valentin, I wanted to prove your point to myself, so I tried the
following program: [code inline for brevity only]

#include <iostream.h>

class Base
{
public:
   Base()                     {   cout << "Base::Base()\n";     f(); }
   virtual ~Base()     {   cout <<  "Base::~Base()\n";  f();  }

   virtual void f() {   cout << "Base::f()\n"; }
};

class Derived : public Base
{
public:
   Derived()           {  cout << "Derived::Derived()\n";   f();}
   virtual ~Derived() {   cout << "Derived::~Derived()\n";   f();}

   virtual void f() {   cout << "Derived::f()\n"; }
};

int main()
{
   Derived d;
   return 0;
}

//eof


When I ran the program, I received the following output:

Base::Base()
Base::f()
Derived::Derived()
Derived::f()
Derived::~Derived()
Derived::f()
Base::~Base()
Base::f()

...from the output it is plain to see that when the virtual function
f() is called from the Base ctor, even when a Derived is the object
under construction.  This is the behaviour I would expect and is the
only logical behaviour, IMHO.  However, I wouldn't recommend it and if
it would prove necessary to call a virtual function from a ctor, I
would try to make it clear to the poor maintenance programmer by
making the call non-virtual explicitly, ie:

Base::Base()
{
   Base::f();  //Non-virtual call to f()
}

Do you say I have a non-conforming compiler, or is my point taken?

Jon Sturgeon
JonS@futuresoft.com



[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://reality.sgi.com/austern_mti/std-c++/faq.html              ]






Author: david@unico.com.au (David Goh)
Date: 1998/02/24
Raw View
In comp.std.c++, on 23 Feb 1998 16:49:22 GMT
Jon Sturgeon <JonS@futuresoft.nospam.com> wrote:
>On 22 Feb 1998 16:49:57 GMT, Valentin Bonnard <bonnardv@pratique.fr>
>wrote:
>>This wrong. Virtual functions are called according to the
>>dynamic type except when they are explicitly qualified with
>>a clas name as in X::f ().

>>Calling a virtual function is ok unless it is pure virtual
>>in the class (in which case undefined behaviour follows
>>(which in most cases prints 'pure function called')).

>Well, Valentin, I wanted to prove your point to myself, so I tried the
>following program: [code inline for brevity only]

>#include <iostream.h>
>class Base
>{
>public:
>   Base()                     {   cout << "Base::Base()\n";     f(); }
>   virtual ~Base()     {   cout <<  "Base::~Base()\n";  f();  }
>   virtual void f() {   cout << "Base::f()\n"; }
>};

>class Derived : public Base
>{
>public:
>   Derived()           {  cout << "Derived::Derived()\n";   f();}
>   virtual ~Derived() {   cout << "Derived::~Derived()\n";   f();}
>   virtual void f() {   cout << "Derived::f()\n"; }
>};

>int main()
>{
>   Derived d;
>   return 0;
>}

>//eof

>When I ran the program, I received the following output:
>Base::Base()
>Base::f()
>Derived::Derived()
>Derived::f()
>Derived::~Derived()
>Derived::f()
>Base::~Base()
>Base::f()

>...from the output it is plain to see that when the virtual function
>f() is called from the Base ctor, even when a Derived is the object
>under construction.  This is the behaviour I would expect and is the
>only logical behaviour, IMHO.

Valentin's point is that when you call a virtual function in a
constructor, it *does* behave virtually.

Do the following:

class Grandkid : public Derived
{
public:
   Grandkid()           {  cout << "Grandkid::Grandkid()\n";   f();}
   virtual ~Grandkid() {   cout << "Grandkid::~Grandkid()\n";   f();}
   // INTENTIONALLY DO NOT DEFINE THIS FUNCTION
   // virtual void f() {   cout << "Grandkid::f()\n"; }
};

class GreatGrandkid : public Grandkid
{
public:
 GreatGrandkid() {  cout << "GreatGrandkid::GreatGrandkid()\n";   f();}
 virtual ~GreatGrandkid() { cout << "GreatGrandkid::~GreatGrandkid()\n"; f();}
 virtual void f() {   cout << "GreatGrandkid::f()\n"; }
};

And construct one of them... and you'll get the following:

Base::Base()
Base::f()
Derived::Derived()
Derived::f()
Grandkid::Grandkid()
Derived::f()
GreatGrandkid::GreatGrandkid()
GreatGrandkid::f()
GreatGrandkid::~GreatGrandkid()
GreatGrandkid::f()
Grandkid::~Grandkid()
Derived::f()
Derived::~Derived()
Derived::f()
Base::~Base()
Base::f()

The point is, the call *is* virtual, because Grandkid's call to f() calls
Derived::f() successfully... and the call is not ambiguous.

Grandkid's constructor, of course, does *not* call GreatGrandkid::f(), because
the object in question is *not* a GreatGrandkid object yet!  It *will*
be, but it is not yet so.

>However, I wouldn't recommend it and if
>it would prove necessary to call a virtual function from a ctor, I
>would try to make it clear to the poor maintenance programmer by
>making the call non-virtual explicitly, ie:
>Derived::Derived() {  cout << "Derived::Derived()\n";   Derived::f();}

I agree with this statement...  In the sense that how virtual
functions work in constructors is *not* very well understood, so it's
best *not* to use it, simply because a lot of people will fail to see
what is actually happening.

>Do you say I have a non-conforming compiler, or is my point taken?

You have a conforming compiler, but your point is not taken.

The complaint is about the words you are using.  "non-virtual" has a
pretty specific meaning, and in this instance, the call to f() is *not*
non-virtual.

It *is* virtual... it's just that the object is *not* fully constructed,
and hence, of course, the object cannot call any functions in the
further derived objects, since it *isn't* an instance of the derived
object yet.

Ie, in Grandkid::Grandkid(), the object's dynamic type is Grandkid, not
GreatGrandkid, despite the fact that in the future, it will become a
GreatGrandkid.

Hence, when Grandkid::Grandkid() calls a virtual function, it calls the
virtual function as if it were just a Grandkid object.

Later,

    David

--
| david@unico.com.au (David Goh, Unico Computer Systems, +61-3-9866-5688)
Beware of Programmers who carry screwdrivers.
                -- Leonard Brandwein


[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://reality.sgi.com/austern_mti/std-c++/faq.html              ]






Author: JonS@futuresoft.nospam.com (Jon Sturgeon)
Date: 1998/02/25
Raw View
On 24 Feb 1998 16:39:22 GMT, david@unico.com.au (David Goh) wrote:

>The point is, the call *is* virtual, because Grandkid's call to f() calls
>Derived::f() successfully... and the call is not ambiguous.
>
>Grandkid's constructor, of course, does *not* call GreatGrandkid::f(), because
>the object in question is *not* a GreatGrandkid object yet!  It *will*
>be, but it is not yet so.

OK, That point I take.  Perhaps I was answering a subtly different
question to the one originally asked.  I suspect that calling a
virtual function in a ctor is going to be a likely source of bugs;
however I accept that it *is* a virtual call.

Jon Sturgeon
JonS@futuresoft.com
---
[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://reality.sgi.com/austern_mti/std-c++/faq.html              ]





Author: Oleg Zabluda <zabluda@math.psu.edu>
Date: 1998/02/19
Raw View
Valentin Bonnard <bonnardv@pratique.fr> wrote:
: Piet Van Vlierberghe wrote:

: > Still, I believe the restraint on the constructor is a petty one, since
: > it IS allowed to call nonvirtual member functions from the constructor,
: > and these functions are free to call whatever virtual function they
: > like.

: You can call virtual or non-virtual functions in a ctor, just not
: a pure virtual function. V

Unless the pure virtual function has a definition, and the call is
elaborated, of course :-)

class A {
public:
  A() { A::f(); }
  virtual void f() = 0;
};

void A::f() {}

Oleg.
--
Life is a sexually transmitted, 100% lethal disease.


[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://reality.sgi.com/austern_mti/std-c++/faq.html              ]






Author: JonS@futuresoft.nospam.com (Jon Sturgeon)
Date: 1998/02/20
Raw View
On 19 Feb 98 03:20:30 GMT, Valentin Bonnard <bonnardv@pratique.fr>
wrote:

>Piet Van Vlierberghe wrote:
>
>> Still, I believe the restraint on the constructor is a petty one, since
>> it IS allowed to call nonvirtual member functions from the constructor,
>> and these functions are free to call whatever virtual function they
>> like.
>
>You can call virtual or non-virtual functions in a ctor, just not
>a pure virtual function. Virtual functions will be called according
>to the dynamic type, as usuall. In the body of ctor T::T the dynamic
>type is T.

No! This is not correct.  Virtual functions when called in a class's
*constructor* will be called with the object's static type at that
time, ie they will NOT be virtual.  This is because if a class D
derives from class B, class D has not been constructed by the time the
B ctorhas been called.  Therefore, it is not possible to call any
methods in D.

I would recommend explicitly specifying the scope of the actual
function that is called to avoid potential confusion for maintenance
programmers.

class B
{
public:
  B() { f(); }
  virtual void f();
};

class D : public B
{
public:
  D() { }
  virtual void f();
}

In the example above, when an object of class D is constructed, B's
ctor will call B::f(), NOT D::f().  Therefore, I'd recommend
explicitly writing it as such, ie:

B::B()
{
  B::f();  //Explicit call to B::f() to make things clearer
}

Hope this clears this up.

Jon Sturgeon
JonS@futuresoft.com



[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://reality.sgi.com/austern_mti/std-c++/faq.html              ]






Author: clamage@Eng.Sun.COM (Steve Clamage)
Date: 1998/02/21
Raw View
In article 7f0acac1@amundsen, "Piet Van Vlierberghe" <pvv@lms.be> writes:
>Daniel Parker <danielp@localhost.com> wrote in article
><6ac4sk$j56$1@news.interlog.com>...
>> I think you've answered your own question:  the reason virtual function
>> calls are not supported in the constructor is because the state of the
>> object which supplies the overriding function is not yet determined.  You
>> could call an initailize function after you've constructed the obect if
>> there is no other way of arranging the constructor.
>
>Still, I believe the restraint on the constructor is a petty one, since
>it IS allowed to call nonvirtual member functions from the constructor,
>and these functions are free to call whatever virtual function they
>like.

You can call virtual functions from a constructor, directly or
indirectly; the result is consistent and well-defined.

While the constructor runs, the type of the object under construction
is the constructor's own type, not necessarily the type of the
ultimate object. All virtual functions called during the lifetime
of the constructor are resolved according to that rule. Example:

#include <iostream.h>
class Base;
void f(Base*);

class Base {
public:
        Base() { whatami(); f(this); }
        virtual void whatami() { cout << "I'm a Base\n"; }
};

void f(Base* b) { b->whatami(); }

class Derived : public Base {
public:
        Derived() { whatami(); f(this); }
        virtual void whatami() { cout << "I'm a Derived\n"; }
};

int main()
{
    Derived d;
    return 0;
}

The output should be "I'm a Base" twice from the Base constructor,
then "I'm a Derived" twice from the Derived constructor. Getting
"Derived" when passing a Derived* to f shows that virtual dispatch
really does occur from the constructor.

The same thing applies to destructors: While a destructor runs, the
type of the object is the destructor's own type, not necessarily
the type of the original object being destroyed.

Other languages have different object models, and may allow a base-class
constructor/destructor to (attempt to) access automatically parts of an
object that might not currently exist. The C++ view is that if you
need to do that, something is wrong with the logic of your design.

---
Steve Clamage, stephen.clamage@sun.com
---
[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://reality.sgi.com/austern_mti/std-c++/faq.html              ]





Author: "Kirk Odle" <kodle@ghg.net>
Date: 1998/02/21
Raw View
Valentin Bonnard wrote in message <34EB9CAD.74A3@pratique.fr>...
>Piet Van Vlierberghe wrote:
>
>> Still, I believe the restraint on the constructor is a petty one, since
>> it IS allowed to call nonvirtual member functions from the constructor,
>> and these functions are free to call whatever virtual function they
>> like.
>
>You can call virtual or non-virtual functions in a ctor, just not
>a pure virtual function.

True, you can call them.

>Virtual functions will be called according
>to the dynamic type, as usuall. In the body of ctor T::T the dynamic
>type is T.

That could happen.  Or it might not.  The standard says the result is
undefined.
Please don't sell me any software that you've written that practices this.
---
[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://reality.sgi.com/austern_mti/std-c++/faq.html              ]





Author: "Kirk Odle" <kodle@ghg.net>
Date: 1998/02/21
Raw View
Oleg Zabluda wrote in message <6chfha$1lfm@r02n01.cac.psu.edu>...
>Valentin Bonnard <bonnardv@pratique.fr> wrote:
>: Piet Van Vlierberghe wrote:
>
>: > Still, I believe the restraint on the constructor is a petty one, since
>: > it IS allowed to call nonvirtual member functions from the constructor,
>: > and these functions are free to call whatever virtual function they
>: > like.
>
>: You can call virtual or non-virtual functions in a ctor, just not
>: a pure virtual function. V
>
>Unless the pure virtual function has a definition, and the call is
>elaborated, of course :-)

And... unless you want defined results.  :-)
---
[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://reality.sgi.com/austern_mti/std-c++/faq.html              ]





Author: Oleg Zabluda <zabluda@math.psu.edu>
Date: 1998/02/21
Raw View
Kirk Odle <kodle@ghg.net> wrote:
: Oleg Zabluda wrote in message <6chfha$1lfm@r02n01.cac.psu.edu>...
: >Valentin Bonnard <bonnardv@pratique.fr> wrote:
: >: Piet Van Vlierberghe wrote:
: >
: >: > Still, I believe the restraint on the constructor is a petty one, since
: >: > it IS allowed to call nonvirtual member functions from the constructor,
: >: > and these functions are free to call whatever virtual function they
: >: > like.
: >
: >: You can call virtual or non-virtual functions in a ctor, just not
: >: a pure virtual function. V
: >
: >Unless the pure virtual function has a definition, and the call is
: >elaborated, of course :-)

: And... unless you want defined results.  :-)

Wrong. What I descrbed is perfectly defined. The only thing is
that what I call ``elaborated'' normal people call ``qualified''.
Qualified call disables virtual funcation call mechanism.
See my orginal post for an example of how you an call a pure
virtual function from an object's constructor.

Oleg.
--
Life is a sexually transmitted, 100% lethal disease.


[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://reality.sgi.com/austern_mti/std-c++/faq.html              ]






Author: Valentin Bonnard <bonnardv@pratique.fr>
Date: 1998/02/22
Raw View
Jon Sturgeon <JonS@futuresoft.nospam.com> writes:

> On 19 Feb 98 03:20:30 GMT, Valentin Bonnard <bonnardv@pratique.fr>
> wrote:
>
> >You can call virtual or non-virtual functions in a ctor, just not
> >a pure virtual function. Virtual functions will be called according
> >to the dynamic type, as usuall. In the body of ctor T::T the dynamic
> >type is T.
>
> No! This is not correct.

Of course it is.

> Virtual functions when called in a class's
> *constructor* will be called with the object's static type at that
> time, ie they will NOT be virtual.

This wrong. Virtual functions are called according to the
dynamic type except when they are explicitly qualified with
a clas name as in X::f ().

Calling a virtual function is ok unless it is pure virtual
in the class (in which case undefined behaviour follows
(which in most cases prints 'pure function called')).

> Hope this clears this up.

Everything is already clear to me.

--

Valentin Bonnard                mailto:bonnardv@pratique.fr
info about C++/a propos du C++: http://www.pratique.fr/~bonnardv/


[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://reality.sgi.com/austern_mti/std-c++/faq.html              ]






Author: Valentin Bonnard <bonnardv@pratique.fr>
Date: 1998/02/22
Raw View
Kirk Odle <kodle@ghg.net> writes:

> Oleg Zabluda wrote in message <6chfha$1lfm@r02n01.cac.psu.edu>...
> >Valentin Bonnard <bonnardv@pratique.fr> wrote:
> >: Piet Van Vlierberghe wrote:
> >
> >: > Still, I believe the restraint on the constructor is a petty one, since
> >: > it IS allowed to call nonvirtual member functions from the constructor,
> >: > and these functions are free to call whatever virtual function they
> >: > like.
> >
> >: You can call virtual or non-virtual functions in a ctor, just not
> >: a pure virtual function. V
> >
> >Unless the pure virtual function has a definition, and the call is
> >elaborated, of course :-)
>
> And... unless you want defined results.  :-)

Wrong... unless you have a very strange C++ compiler

Wrong... unless you don't care about the language definition

Sorry, but you are wrong. Oleg (and me) are right. Read
the standard if you aren't convinced (no, I won't dig throu
the std for you).

--

Valentin Bonnard                mailto:bonnardv@pratique.fr
info about C++/a propos du C++: http://www.pratique.fr/~bonnardv/


[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://reality.sgi.com/austern_mti/std-c++/faq.html              ]






Author: Valentin Bonnard <bonnardv@pratique.fr>
Date: 1998/02/19
Raw View
Piet Van Vlierberghe wrote:

> Still, I believe the restraint on the constructor is a petty one, since
> it IS allowed to call nonvirtual member functions from the constructor,
> and these functions are free to call whatever virtual function they
> like.

You can call virtual or non-virtual functions in a ctor, just not
a pure virtual function. Virtual functions will be called according
to the dynamic type, as usuall. In the body of ctor T::T the dynamic
type is T.

--

Valentin Bonnard                mailto:bonnardv@pratique.fr
info about C++/a propos du C++: http://www.pratique.fr/~bonnardv/
---
[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://reality.sgi.com/austern_mti/std-c++/faq.html              ]





Author: "Piet Van Vlierberghe" <pvv@lms.be>
Date: 1998/02/16
Raw View
Daniel Parker <danielp@localhost.com> wrote in article
<6ac4sk$j56$1@news.interlog.com>...
> Loic Tregan wrote in message <34C61A2C.3B9A@cert.fr>...
> >allowing virtual calls in the ctor would allow code using this paradigm
> >of 'properties' to be ten times easier to write and only 1.1 a little
> >bit more sensible to bugs (because XX:SetProp() may be called in X:X(),
> >so before XX:XX() )
> >
> >The question is :
> > - why no virtual calls in the ctors ?
> > - how can I do the same thing with the current implementation ?
>
>
> I think you've answered your own question:  the reason virtual function
> calls are not supported in the constructor is because the state of the
> object which supplies the overriding function is not yet determined.  You
> could call an initailize function after you've constructed the obect if
> there is no other way of arranging the constructor.
>

Still, I believe the restraint on the constructor is a petty one, since
it IS allowed to call nonvirtual member functions from the constructor,
and these functions are free to call whatever virtual function they
like. IMHO either  _all_ nonstatic member function access is prohibited
in the constructor, or virtual functions are allowed as well.
Obviously, the latter would be troublesome, so the former is
preferable.

The same holds for member variables: if the constructor body would not
have access to _this_ at all, but only to the member variables
directly, there would be less of a problem. The intent of a constructor
was to make sure that there is no such thing as an object that _almost_
belongs to a type: either an object exists and belongs to a type, or it
does not exist at all. The current C++ standard allows full access to
objects that  _almost_ exist, which means that all invariants of the
class are _almost_ fulfilled.
---
[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://reality.sgi.com/austern_mti/std-c++/faq.html              ]





Author: James Kuyper <kuyper@wizard.net>
Date: 1998/02/18
Raw View
Piet Van Vlierberghe wrote:
...
> Still, I believe the restraint on the constructor is a petty one, since
> it IS allowed to call nonvirtual member functions from the constructor,
> and these functions are free to call whatever virtual function they
> like.

false - Section 10.4 "Abstract classes", paragraph 6:
| ... the effect of making a virtual call
| to a pure virtual  function  directly  or  indirectly  for  the
                                             ^^^^^^^^^^
| object  being  created  (or  destroyed)  from  such  a constructor (or
| destructor) is undefined.
---
[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://reality.sgi.com/austern_mti/std-c++/faq.html              ]





Author: John Gilchrist <johng@symphony.aud.alcatel.com>
Date: 1998/01/29
Raw View
Loic Tregan wrote:
> the trumble is that XX:SetProp is not called, but X:SetProp() instead.
...
> The question is :
>         - why no virtual calls in the ctors ?
>         - how can I do the same thing with the current implementation ?

Believe that technically the derived object does not yet exist in the
base classes constructor and so it would be a mistake to attempt to
access it.

Guess you need some public void init() in X which then calls SetProp.
---
[ comp.std.c++ is moderated.  To submit articles: try just posting with      ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu         ]
[ FAQ:      http://reality.sgi.com/employees/austern_mti/std-c++/faq.html    ]
[ Policy:   http://reality.sgi.com/employees/austern_mti/std-c++/policy.html ]
[ Comments? mailto:std-c++-request@ncar.ucar.edu                             ]





Author: Loic Tregan <tregan@cert.fr>
Date: 1998/01/22
Raw View
it is common to have :

class X{
private:
 int _prop;
public:
 X( int prop);
 virtual int GetProp();
 virtual void SetProp(int prop);
}

X:X(int prop )
{
 SetProp( prop );
}

then a derived class :

class XX{
public:
 virtual void SetProp(int prop);
}

XX(33);

the trumble is that XX:SetProp is not called, but X:SetProp() instead.

allowing virtual calls in the ctor would allow code using this paradigm
of 'properties' to be ten times easier to write and only 1.1 a little
bit more sensible to bugs (because XX:SetProp() may be called in X:X(),
so before XX:XX() )

The question is :
 - why no virtual calls in the ctors ?
 - how can I do the same thing with the current implementation ?
---
[ comp.std.c++ is moderated.  To submit articles: try just posting with      ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu         ]
[ FAQ:      http://reality.sgi.com/employees/austern_mti/std-c++/faq.html    ]
[ Policy:   http://reality.sgi.com/employees/austern_mti/std-c++/policy.html ]
[ Comments? mailto:std-c++-request@ncar.ucar.edu                             ]





Author: "C. Grant" <camg100@hermes.cam.ac.uk>
Date: 1998/01/23
Raw View
Loic Tregan wrote:
>
> it is common to have :
>
> class X{
> private:
>         int _prop;
> public:
>         X( int prop);
>         virtual int GetProp();
>         virtual void SetProp(int prop);
> }
>
> X:X(int prop )
> {
>         SetProp( prop );
> }
>
> then a derived class :
>
> class XX{
> public:
>         virtual void SetProp(int prop);
> }
>
> XX(33);
>
> the trumble is that XX:SetProp is not called, but X:SetProp() instead.
>
> allowing virtual calls in the ctor would allow code using this paradigm
> of 'properties' to be ten times easier to write and only 1.1 a little
> bit more sensible to bugs (because XX:SetProp() may be called in X:X(),
> so before XX:XX() )
>
> The question is :
>         - why no virtual calls in the ctors ?
>         - how can I do the same thing with the current implementation

This behaviour is correct and entirely reasonable.  C++ does not allow
objects to be used before they have been constructed.

Unfortunately the C++ paradigm is applied correctly here, and there is
no way of calling a derived class from a constructor.  The reason is
because the base class constructor is always called before the derived
class constructor, so were the base class constructor to call the
derived class's methods, the derived class's methods would be invoked
before the derived class had been constructed, which would be very bad
indeed.

However due to the order in which virtual function table pointers are
set, a derived class constructor calling a base class method can call
virtual functions in the derived class.

The solution to your problem is to have a seperate method in the base
class called "Initialize", which is called during or after construction
of the derived class.

-- Calum
---
[ comp.std.c++ is moderated.  To submit articles: Try just posting with your
                newsreader.  If that fails, use mailto:std-c++@ncar.ucar.edu
  comp.std.c++ FAQ: http://reality.sgi.com/austern/std-c++/faq.html
  Moderation policy: http://reality.sgi.com/austern/std-c++/policy.html
  Comments? mailto:std-c++-request@ncar.ucar.edu
]





Author: Colin Rafferty <craffert@ml.com>
Date: 1998/01/23
Raw View
Loic Tregan writes:

> allowing virtual calls in the ctor would allow code using this paradigm
> of 'properties' to be ten times easier to write and only 1.1 a little
> bit more sensible to bugs (because XX:SetProp() may be called in X:X(),
> so before XX:XX() )

This question comes up every couple of months.

As one of the participants in the last flame-war, I suggest that you
look at dejanews to see what everyone said.

--
Colin
---
[ comp.std.c++ is moderated.  To submit articles: Try just posting with your
                newsreader.  If that fails, use mailto:std-c++@ncar.ucar.edu
  comp.std.c++ FAQ: http://reality.sgi.com/austern/std-c++/faq.html
  Moderation policy: http://reality.sgi.com/austern/std-c++/policy.html
  Comments? mailto:std-c++-request@ncar.ucar.edu
]





Author: Phlip <tegan@deltanet.com>
Date: 1998/01/23
Raw View
Loic Tregan escribi=F3:

> it is common to have :

<call from constructor to virtual 'set' method snipped>

No.

> The question is :
>         - why no virtual calls in the ctors ?

You are trying to break the rule Say Exactly What You Mean. You are const=
ructing a
Base, so do not mess with the Derived yet. If the compiler permitted this=
, you
could peek or poke variables in the Derived that are not constructed yet.

>         - how can I do the same thing with the current implementation ?

Let your constructors do the minimum needed so the destructor will not cr=
ash. Then
provide a 'Base::Init ()' that assigns all the get/set properties.

Construction and initialization are not exactly the same thing, but the l=
anguage
usually lets us lump them together. Think of initialization as what you d=
o only to
complete objects.

  --  Phlip
=3D=3D=3D=3D=3D=3D=3D http://users.deltanet.com/~tegan/home.html =3D=3D=3D=
=3D=3D=3D=3D
  --  The big decision. Go Postal, or write some more VB  --
---
[ comp.std.c++ is moderated.  To submit articles: Try just posting with your
                newsreader.  If that fails, use mailto:std-c++@ncar.ucar.edu
  comp.std.c++ FAQ: http://reality.sgi.com/austern/std-c++/faq.html
  Moderation policy: http://reality.sgi.com/austern/std-c++/policy.html
  Comments? mailto:std-c++-request@ncar.ucar.edu
]





Author: "Bradd W. Szonye" <bradds@concentric.net>
Date: 1998/01/24
Raw View
Loic Tregan wrote in message <34C61A2C.3B9A@cert.fr>...
[edited for brevity and syntax]

>class X {
>private: int _prop;
>public:
>    X(int prop) { SetProp(prop); }
>    virtual void SetProp(int prop);
>};
>
>class XX: public X{
>public:
>    XX(int prop): X(prop) { }
>    virtual void SetProp(int prop);
>};
>
>XX(33);
>
>the trumble is that XX:SetProp is not called, but X:SetProp() instead.
>
>The question is :
> - why no virtual calls in the ctors ?
> - how can I do the same thing with the current implementation ?

Others have addressed the issue, "Why C++ does it this way." I'll attempt to
get at the underlying design issues.

One way I avoid this issue in general is to consider private data of the
base class the base class's responsibility. That is, I design the base class
such that it initializes its private members in a way that "works" for all
derived classes, and then leave the responsibility for initialization solely
in the base class.

If the initialization of a property can't be done in a general enough way in
the base class, then that property's behavior may just not have a reasonable
default. In this case, treat the base class as an interface, not an
implementation. The base class declares Get/SetProp as pure virtual and
unimplemented and does not declare the "real" data member; this establishes
that the property exists, but puts the burden of defining and implementing
its behavior on derived classes. This also fits in with the guideline,
"Usually avoid concrete base classes."

Finally, if you really need to define the property in the base, then
redefine it in the derived class, you can do it, but it's considerably more
work and more error-prone. First, make sure that the property has an
"uninitialized" value--the int in the example satisfies this. Next, provide
a protected constructor in the base that does not initialize the property.
Finally, call the actual initializer in the derived class.

This last method is dangerous, because there are several ways to get it
wrong in defining the derived class. You can forget to ever actually
initialize the property; you can accidentally initialize it more than once,
which is a problem if SetProp is not trivial; you might actually need to use
the property in the base class. This last method is appropriate only if you
really, really need it, and you can be sure it works for your framework.
---
Bradd W. Szonye
bradds@concentric.net
http://www.concentric.net/~Bradds




[ comp.std.c++ is moderated.  To submit articles: try just posting with      ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu         ]
[ FAQ:      http://reality.sgi.com/employees/austern_mti/std-c++/faq.html    ]
[ Policy:   http://reality.sgi.com/employees/austern_mti/std-c++/policy.html ]
[ Comments? mailto:std-c++-request@ncar.ucar.edu                             ]





Author: "Daniel Parker" <danielp@localhost.com>
Date: 1998/01/24
Raw View
Loic Tregan wrote in message <34C61A2C.3B9A@cert.fr>...
>allowing virtual calls in the ctor would allow code using this paradigm
>of 'properties' to be ten times easier to write and only 1.1 a little
>bit more sensible to bugs (because XX:SetProp() may be called in X:X(),
>so before XX:XX() )
>
>The question is :
> - why no virtual calls in the ctors ?
> - how can I do the same thing with the current implementation ?


I think you've answered your own question:  the reason virtual function
calls are not supported in the constructor is because the state of the
object which supplies the overriding function is not yet determined.  You
could call an initailize function after you've constructed the obect if
there is no other way of arranging the constructor.

Please do not use reply, use danielp@anabasis.com instead.





[ comp.std.c++ is moderated.  To submit articles: try just posting with      ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu         ]
[ FAQ:      http://reality.sgi.com/employees/austern_mti/std-c++/faq.html    ]
[ Policy:   http://reality.sgi.com/employees/austern_mti/std-c++/policy.html ]
[ Comments? mailto:std-c++-request@ncar.ucar.edu                             ]