Topic: virtual mechanism in ctor/dtor


Author: AllanW <allan_w@my-dejanews.com>
Date: 1999/05/22
Raw View
In article <7h79h0$dhr$1@nnrp1.deja.com>,
  gbush@my-dejanews.com wrote:
>
> In article <7h61il$jru$1@engnews1.eng.sun.com>,
>   clamage@eng.sun.com (Steve Clamage) wrote:
> > C++ uses a different rule, by deliberate design. During construction
> > of an object, the current type of the object is the type of the
> > constructor that is currently running. Virtual dispatch is not
> > required in the code residing in the constructor, because the
> > dynamic type of the object (at that moment) is known at compile
> > time.
> Probably, I was unclear in my previous post. Your last paragraph is
> exactly what I was talking about. The base classes use static type of
> "this" instead of its dynamic type. The later can be of a derived
> class. This restriction seems unnecessary and causes one to use extra
> work (like call-back) to achieve what virtual mechanism is meant to.
> Gene.

This restriction takes special effort on the part of the
implementor, but it is both deliberate and neccesary!

    class Base {
        void init(int i) {
            x = i;
            std::cout << name() << '(' << x << ')' << std::endl;
        }
    public:
        virtual const char*name() { return "NoName"; }
        Base(int i=0) { init(i); }
    };
    class Der {
        static int objectCount;
        const char*myname;
    public:
        Der(const char*newname="Der")
            : base(++objectCount)
            // Ignores possibility of newname==0 or new[] failure
            , myname(strcpy(new char[1+strlen(newname)],newname)
        {
        }
    };

Before a new Der is constructed, the Base sub-object is constructed.
The Base constructor calls init(), which in turn calls name(). If
this call resolved to Der::name(), then it would deference
Der::myname before it was initialized.

Check Bjarne Stroustrup's "The Design and Evolution of C++" for
more details.

----
Allan_W@my-dejanews.com is a "Spam Magnet" --
never read.


--== Sent via Deja.com http://www.deja.com/ ==--
---Share what you know. Learn what you don't.---
---
[ 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: gbush@my-dejanews.com
Date: 1999/05/23
Raw View
In article <7i4ppf$6m6$1@engnews1.eng.sun.com>,
  clamage@eng.sun.com (Steve Clamage) wrote:
>
> I'd be very surprised to find "compilers with all imaginable
> extensions".  And if you see the standard as a straight-jacket, I
> think you don't understand the purpose or uses of a standard.

Just a brief comment in the end of this lengthy discussion. A number of
extensions to the standard is already in heavy use. For example,
Borland C++ Builder, that I like more than anything else in the market,
uses successfully virtual dispatch in ctor/dtor in VCL; it has
excellent __property and __closure implementations; it has __fastcall
function specification that speaks for itself; it has published:
section in addition to private:, public:, protected:; it has __asm
keyword for including assembler instructions (great for Windows,
useless for Unix due to huge number of flavors); it has __finally in
addition to try ... catch; and many other features, and probably more
to come. All these extensions already demonstrated their usefulness in
practice and I would expect the other compiler vendors to follow the
fray (at least those who "don't understand the purpose or uses of a
standard") if they want to survive.
Gene.


--== Sent via Deja.com http://www.deja.com/ ==--
---Share what you know. Learn what you don't.---


[ 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: stephen.clamage@sun.com (Steve Clamage)
Date: 1999/05/23
Raw View
gbush@my-dejanews.com writes:


>In article <7i4ppf$6m6$1@engnews1.eng.sun.com>,
>  clamage@eng.sun.com (Steve Clamage) wrote:
>>
>> I'd be very surprised to find "compilers with all imaginable
>> extensions".  And if you see the standard as a straight-jacket, I
>> think you don't understand the purpose or uses of a standard.

>Just a brief comment in the end of this lengthy discussion. A number of
>extensions to the standard is already in heavy use. For example, ...
>    All these extensions already demonstrated their usefulness in
>practice and I would expect the other compiler vendors to follow the
>fray (at least those who "don't understand the purpose or uses of a
>standard") if they want to survive.

Please don't read more into my comment than I wrote.

There's nothing wrong with compilers providing extensions, but
IMHO they should clearly label extensions as such. When extensions
are proved generally useful and are widely adopted, they will
find their way into a future revision of the standard. (That's one
of the things a standards body does: ratify existing practice.)

Far from forbidding extensions, the standard provides some explicit
hooks for conforming implementations to provide extensions. Every
"undefined" or "unspecified" item is a hook for an implementation
to provide extensions, for example. Where ever the standard is
silent on a feature (dynamic libraries, multi-threading, ORB
interfaces, etc) there is an opportunity for an extension.
The #pragma directive is another explicit hook for extensions.

That's what I meant by not viewing a standard as a straight-jacket.

A standard provides an open agreement between C++ implementors and
C++ users. When an implementor and user both choose to follow the
agreement, both can have increased confidence that user code will
have agreed-upon meaning and operation. Absent a standard, you
cannot be sure what code will compile or run as you expect on
any given implementation.

--
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: "Wil Evers" <bouncer@dev.null>
Date: 1999/05/25
Raw View
gbush@my-dejanews.com wrote in article <7i814l$ko0$1@nnrp1.deja.com>...

> Just a brief comment in the end of this lengthy discussion. A number of
> extensions to the standard is already in heavy use. For example,
> Borland C++ Builder, that I like more than anything else in the market,
> uses successfully virtual dispatch in ctor/dtor in VCL; it has
> excellent __property and __closure implementations;

...etc...

> All these extensions already demonstrated their usefulness in
> practice and I would expect the other compiler vendors to follow the
> fray (at least those who "don't understand the purpose or uses of a
> standard") if they want to survive.

The features you mention were introduced into C++ Builder because they're
needed to provide binary compatibility with a library (the VCL) written in
a different language (Borland's Object Pascal).  Many of them don't have
any justification other than binary VCL compatibility; for almost every
'advanced' Borland Object Pascal language feature, one can provide an
equivalent or better library-based solution in standard C++ without
requiring any language extensions at all.

Instead of porting the VCL to C++, or wrapping it in some inter-language
communication infrastructure like CORBA, Borland took the easy way out and
changed the C++ compiler.  I can see how that serves Borland's interests,
but I'm not so sure how the C++ community as a whole would benefit from yet
more ways to accomplish the same thing.  As far as I'm concerned, C++ is
big enough, and learning C++ is hard enough.

- Wil

Wil Evers, DOOSYS IT Consultants, Maarssen, Holland
[Wil underscore Evers at doosys dot 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: gbush@my-dejanews.com
Date: 1999/05/21
Raw View
In article <37394088.6126493@news>,
  enrightm@acm.org wrote:

> Or perhaps what you are looking for is that the final override defined
> by the most derived type would be invoked. That would require that the
> code in a constructor be able to invoke virtual functions _very_
> flexibly, in a borderline-divine, almost-SmallTalk-like way. And the
> most derived constructors haven't prepared those most derived
> overrides to be run.
Yeah, that's what I'm looking for. And Pascal proved that it's working
just fine. And it's working just fine in the visual component library
in Borland C++ Builder, except that programmers are confused when it
comes to the standard.
Gene.


--== Sent via Deja.com http://www.deja.com/ ==--
---Share what you know. Learn what you don't.---
---
[ 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: gbush@my-dejanews.com
Date: 1999/05/21
Raw View
In article <memo.19990511025514.62493D@btinternet.com>,
  brangdon@cix.co.uk wrote:
Geez, almost to every question I ask, the answer is: it would be too
difficult, too confusing, too obscure, too whatever. I worked for years
in Object Pascal and it happened not to be too difficult, too
confusing, too whatever. In fact the opposite is true.
It looks like while other languages enjoy a plethora of features, C++
is on a position of excusing its behavior, instead of making a progress.

I wouldn't be surprised if instead of unifying standard we will see
compilers with all imaginable extensions that will make the existence
of strait-jacket standard irrelevant.
Gene.


--== Sent via Deja.com http://www.deja.com/ ==--
---Share what you know. Learn what you don't.---


[ 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: 1999/05/21
Raw View
gbush@my-dejanews.com writes:

>In article <memo.19990511025514.62493D@btinternet.com>,
>  brangdon@cix.co.uk wrote:
>Geez, almost to every question I ask, the answer is: it would be too
>difficult, too confusing, too obscure, too whatever. I worked for years
>in Object Pascal and it happened not to be too difficult, too
>confusing, too whatever. In fact the opposite is true.
>It looks like while other languages enjoy a plethora of features, C++
>is on a position of excusing its behavior, instead of making a progress.

Different languages have different purposes and different design
goals. If a feature F works well in language X bit is lacking in
language Y, it doesn't necessarily mean that Y should have feature
F.  It might be that feature F is redundant in Y, or has bad
interactions with other features in Y, or violates some design
constraint of Y.

If you approach language Y with the mind-set of language X, you
will always be dissatisfied. You will find some features of Y to
have no purpose, some important features of X missing in Y, and
some features in Y having the wrong semantics.

Please notice I haven't said which language is X and which is Y.

A better approach is first to understand the design goals of
language Y. If you find those goals to be inappropriate, it
doesn't matter very much what features Y has or lacks; you will
not like Y regardless.

Once you understand the design goals of language Y, you can
better appreciate arguments about the merits of a proposed
feature.

>I wouldn't be surprised if instead of unifying standard we will see
>compilers with all imaginable extensions that will make the existence
>of strait-jacket standard irrelevant.

I'd be very surprised to find "compilers with all imaginable
extensions".  And if you see the standard as a straight-jacket, I
think you don't understand the purpose or uses of a standard.

--
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: Valentin Bonnard <Bonnard.V@wanadoo.fr>
Date: 1999/05/19
Raw View
Joerg Barfurth wrote:
>
> Wil Evers wrote:
>
> > Taking this line of reasoning one step further, one might even suggest
> > that the type of 'this' in Derived::Derived() should be 'Base * const',
> > and the type of 'this' in Base::Base() should be 'void * const'.
>
> And having
>         struct Derived2 : Base1, Base2 { Derived2(); };
>
> ...what should the type of 'this' be in Derived2::Derived2() by your reasoning ?
> btw: I'd not like 'this->myMember' to mean something else than just
> 'myMember', even in a ctor

I think he was jocking. At least that's how I took
his message.

--

Valentin Bonnard
---
[ 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: 1999/05/20
Raw View
"Wil Evers" <bouncer@dev.null> writes:

>So what is the type of an object when its constructor body is running?
>If we look at the way C++'s virtual dispatch mechanism works, its type is
>the class in which that constructor is declared.

That is also the definition in the standard.

>But if we go by the
>rules in C++'s exception handling mechanism, it is not: if an exception
>occurs in a constructor body, the corresponding destructor is not called.
> After all, the object's invariant may not have been established yet.
>This apparent inconsistency has always surprised me.

I don't see an inconsistency. If the constructor exits via
an exception, object construction is not complete, so the
corresponding destructor must not be run. OTOH, any members
of that class which have been constructed do get destroyed.

The normal destruction sequence is
 run body of destructor
 destroy members
 destroy immediate base class(es)
 destroy virtual base class(es)
If the constructor exits via an exception, we simply skip
the first step because it should not be done.

If the class designer chooses to call members of the class
from a constructor, that's a design choice; it can't happen
by accident. If a constructor passes "this" to an outside
function, it opens the door to all kinds of unexpected
consequences. You don't always know what that function
will do with the pointer.

--
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: "Wil Evers" <bouncer@dev.null>
Date: 1999/05/20
Raw View
Valentin Bonnard <Bonnard.V@wanadoo.fr> wrote in article
<37420D70.62E4@wanadoo.fr>...

> I think he was jocking. At least that's how I took
> his message.

Well, I'm not sure if I was joking :-).

The 'right' answer to people who want Delphi-style virtual dispatch in C++,
where virtual functions calls from base class constructors resolve to the
most derived overrider, is that that's unsafe because these calls end up in
an uninitialised context.  I'm arguing that while the C++ rules are
certainly safer, they're not completely fullproof, because (indirect)
member functions calls from constructors are still dispatched to an object
for which the invariant may not have been set up.

A hypothetical language that said "an X is not an X until its constructor
has run to completion" would not have this problem.  I'm not saying that
C++ should have such a rule;  however, thinking about the consequences of a
rule like this does help in identifying potentially dangerous constructs
which are allowed in present-day C++.  For example, I would certainly not
be upset if a compiler warned me about passing 'this' to a function called
from a constructor.

- Wil

Wil Evers, DOOSYS IT Consultants, Maarssen, Holland
[Wil underscore Evers at doosys dot 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: "Wil Evers" <bouncer@dev.null>
Date: 1999/05/18
Raw View
Dave Harris <scorp@btinternet.com> wrote in article
<memo.19990511025514.62493D@btinternet.com>...

> Incidently, this stuff need to be understood in the light of
> Bertrand Meyer's notion of "Design by Contract". Roughly, each
> class has a "class  invariant" which is guaranteed to be true
> on entry (and exit) to every routine. Knowing the class
> invariant, we can reason about the class's behaviour and
> convince ourselves that the code works. The job of the
> constructor, then, is to set up the class invariant at the
> beginning. If there's a way to by-pass the constructor, all
> our careful reasoning about the code's behaviour goes for
> nothing.

I agree that the C++ rule makes it impossible to (accidentally) bypass a
constructor.  However, it does not guarantee that the class invariant is
established on entry to every virtual member function: a virtual function
which is - perhaps indirectly - called from within a constructor ends up
in a sub-object that still is in the process of being constructed.

So what is the type of an object when its constructor body is running?
If we look at the way C++'s virtual dispatch mechanism works, its type is
the class in which that constructor is declared.  But if we go by the
rules in C++'s exception handling mechanism, it is not: if an exception
occurs in a constructor body, the corresponding destructor is not called.
 After all, the object's invariant may not have been established yet.
This apparent inconsistency has always surprised me.

C++ could have supported a stronger notion of class invariants if
(virtual) member function calls from constructors would have been defined
as a call to the implemenation in the object's base class, and if there
is no base class, as a compile-time error or a pure virtual function
call.

Taking this line of reasoning one step further, one might even suggest
that the type of 'this' in Derived::Derived() should be 'Base * const',
and the type of 'this' in Base::Base() should be 'void * const'.

- Wil

Wil Evers, DOOSYS IT Consultants, Maarssen, Holland

[Wil underscore Evers at doosys dot 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: James.Kanze@dresdner-bank.com
Date: 1999/05/18
Raw View
In article <7hcjg5$jnn$1@nnrp1.deja.com>,
  Michael Podolsky <michael_podolsky@my-dejanews.com> wrote:
> In article <7h79h0$dhr$1@nnrp1.deja.com>,
>   gbush@my-dejanews.com wrote:
>
> > The base classes use static type of
> > "this" instead of its dynamic type.
>
> May be.

Is.

> > The later can be of a derived
> > class.
>
> Incorrect.

Correct.

> In the next case
>
> class Base
> {
>    Base(){f();}
>    void f(){g();}
>    virtual void g();
> };
>
> Base::g() would be called if f() function is called from
> Base::Base(). Yet... function f() can't know that it
> was called from the constructor, so 'this' is really
> of 'Base' type when Base constructor (or destructor) is
> executed.

That is exactly what he said.  The dynamic type is that of the
constructor being executed.

> Actually it is assignment of vtbl pointer that makes 'this'
> to be of particular dynamic type and such assignment is made
> by derived class constructor after base constructor have been called.

No.  The assignment is made be every constructor in the hierarchy, for
the class in question.

This is most evident in a deaper inheritance hierarchy:

    struct Base
    {
        virtual void    f()
        {
            cout << "In Base\n" ;
        }
        void            g()
        {
            f() ;
        }
    } ;

    struct Intermediate : Base
    {
        Intermediate()
        {
            g() ;
        }
        virtual void    f()
        {
            cout << "In Intermediate\n" ;
        }
    } ;

    struct Derived : Intermediate
    {
    } ;

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

This program had better output "In Intermediate", which can only occur
if the call to f() in g() is virtual.

--
James Kanze                         mailto:
James.Kanze@dresdner-bank.com
Conseils en informatique orient   e objet/
                        Beratung in objekt orientierter
Datenverarbeitung
Ziegelh   ttenweg 17a, 60598 Frankfurt, Germany  Tel. +49 (069) 63 19 86
27


--== Sent via Deja.com http://www.deja.com/ ==--
---Share what you know. Learn what you don't.---


[ 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.Kanze@dresdner-bank.com
Date: 1999/05/18
Raw View
In article <7hciqb$j6v$1@nnrp1.deja.com>,
  Michael Podolsky <michael_podolsky@my-dejanews.com> wrote:
> In article <7h96jc$s42$1@nnrp1.deja.com>,
>   James.Kanze@dresdner-bank.com wrote:
> > The only time I needed this sort of thing, it was easily
> > accomplished by means of an initialization class: rather than a
> > default constructor:
> >
> >     MyBase::MyBase( MyInitializer = MyInitializer() ) ;
> >
> > Which also served as the constructor taking a string.  MyInitializer
> > looked something like:
> >
> >     class MyInitializer
> >     {
> >     friend class MyBase ;
> >     public:
> >         MyInitializer() : myInit( "" ) , myOwner( NULL ) {}
> >         MyInitializer( string const& initValue )
> >             :   myInit( initValue ) , myOwner( NULL ) {}
> >         ~MyInitializer() {
> >             if ( myOwner != NULL )
> >                 myOwner->initialize( myInit ) ;
> >          }
> >     private:
> >         string const&   myInit ;
> >         MyBase*         myOwner ;
> >     } ;
> >
>
> Am I correct that you also have to provide artificial constructor
> for derived classes with your solution --
> like:
>   MyDerived::MyDerived( const MyInitializer &mi= MyInitializer() )
>     : MyBase(mi) {} // call myOwner->initialize(.) after
>                     // full construction

Correct.

> yet...   in this case your code seems to be incorrect as your
> MyBase constructor does not take MyInitalizer reference.
>
> Could you clarify?

It's what comes of not verifying what you've typed before posting.  The
constructor for MyBase in fact should take a const reference to
MyInitalizer.  MyBase casts away const in order to modify
MyInitalizer::myOwner; today, I'd surely just make myOwner mutable, but
the option wasn't available when I experimented with this.

I might add that when I did this, it was exactly that, an experiment.  I
rather doubt that I'd do anything like this in production code, which
others might have to maintain; it is far too subtle, IMHO, and there are
too many ways to get it wrong.

--
James Kanze                         mailto:
James.Kanze@dresdner-bank.com
Conseils en informatique orient   e objet/
                        Beratung in objekt orientierter
Datenverarbeitung
Ziegelh   ttenweg 17a, 60598 Frankfurt, Germany  Tel. +49 (069) 63 19 86
27


--== Sent via Deja.com http://www.deja.com/ ==--
---Share what you know. Learn what you don't.---


[ 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.Kanze@dresdner-bank.com
Date: 1999/05/18
Raw View
In article <7halud$gun$1@engnews1.eng.sun.com>,
  stephen.clamage@sun.com (Steve Clamage) wrote:

> I can imagine a design where derived classes contain no data, but
> are derived only to get different behavior. In that case, it might
> be sensible to want to call a derived-class function from the
> base class ctor or dtor. But it might not be sensible. The
> derived-class ctor or dtor might affect the state of the base class
> sub-object in ways that matter to the function, in which case
> the program would become unstable.

> I still think that a design meeting all the implied restrictions
> above is uncommon. (Not impossible, or even a bad idea; just
> uncommon.) The most common designs involve derived classes whose
> virtual functions depend on derived-class data.

Just to confirm Steve's supposition: in 9 years of C++, this case only
happened to me once. At the time, I used the solution described in
another posting, but on thinking about it, the case actually was the
result of a questionable design decision; the polymorphic behavior
actually should have been part of a separate class, which served to
customize the base class.  (Delegation, rather than direct inheritance.)

--
James Kanze                         mailto:
James.Kanze@dresdner-bank.com
Conseils en informatique orient   e objet/
                        Beratung in objekt orientierter
Datenverarbeitung
Ziegelh   ttenweg 17a, 60598 Frankfurt, Germany  Tel. +49 (069) 63 19 86
27


--== Sent via Deja.com http://www.deja.com/ ==--
---Share what you know. Learn what you don't.---


[ 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: Joerg Barfurth <jbarfurth@vossnet.de>
Date: 1999/05/19
Raw View
Wil Evers wrote:

> =

> Taking this line of reasoning one step further, one might even suggest
> that the type of 'this' in Derived::Derived() should be 'Base * const',=

> and the type of 'this' in Base::Base() should be 'void * const'.

And having
 struct Derived2 : Base1, Base2 { Derived2(); };

=2E..what should the type of 'this' be in Derived2::Derived2() by your re=
asoning ?
btw: I'd not like 'this->myMember' to mean something else than just
'myMember', even in a ctor

-- J=F6rg Barfurth
---
[ 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: gbush@my-dejanews.com
Date: 1999/05/10
Raw View
In article <7h61il$jru$1@engnews1.eng.sun.com>,
  clamage@eng.sun.com (Steve Clamage) wrote:
> C++ uses a different rule, by deliberate design. During construction
> of an object, the current type of the object is the type of the
> constructor that is currently running. Virtual dispatch is not
> required in the code residing in the constructor, because the
> dynamic type of the object (at that moment) is known at compile
> time.
Probably, I was unclear in my previous post. Your last paragraph is
exactly what I was talking about. The base classes use static type of
"this" instead of its dynamic type. The later can be of a derived
class. This restriction seems unnecessary and causes one to use extra
work (like call-back) to achieve what virtual mechanism is meant to.
Gene.


--== Sent via Deja.com http://www.deja.com/ ==--
---Share what you know. Learn what you don't.---


[ 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: 1999/05/11
Raw View
gbush@my-dejanews.com writes:

>In article <7h61il$jru$1@engnews1.eng.sun.com>,
>  clamage@eng.sun.com (Steve Clamage) wrote:
>> C++ uses a different rule, by deliberate design. During construction
>> of an object, the current type of the object is the type of the
>> constructor that is currently running. Virtual dispatch is not
>> required in the code residing in the constructor, because the
>> dynamic type of the object (at that moment) is known at compile
>> time.

>Probably, I was unclear in my previous post. Your last paragraph is
>exactly what I was talking about. The base classes use static type of
>"this" instead of its dynamic type. The later can be of a derived
>class. This restriction seems unnecessary and causes one to use extra
>work (like call-back) to achieve what virtual mechanism is meant to.

As I said, it is a language design and definition issue.

It seems unusual to want to call a derived-class member function
as part of initializing a base-class sub-object (or after the
derived portion has ceased to exist).  If that member function
doesn't reference anything derived from the base class, why isn't
it a member of that class instead of a derived class? (Rhetorical
question, but it makes the point.  Evidently you have some reason
for wanting to do so.)

If the derived-class function uses anything from a derived class,
it is dangerous to call from a base-class ctor or dtor.

If the language rule said that the object type was the most-derived
even when constructing (destroying) base sub-objects, you would
have to be very careful about calling any virtual function from
a ctor or dtor. No matter how careful YOU were, everyone ELSE
deriving from the class would have to understand that overriders
of any virtual function called (directly or indirectly) from any
ctor or dtor could not refer to anything derived from that base class.

Since failure to follow that rule (which cannot be enforced by the
compiler in general) would be catastrophic, the only safe design
is never to call a virtual function from a constructor or
destructor. That in turn means making an extra non-virtual version
of every virtual function called (directly or indirectly) from a
ctor or dtor. But since you can't in general know about indirect
calls, it would also mean that you should never pass "this" to any
other function from a ctor or dtor.

So in order to accomodate the unusual requirement of wanting to
call derived-class functions when the derived portion of the
object doesn't exist, you complicate the design and use of every
class. Sounds like a bad tradeoff to me.

--
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: Dominic North <Dominic.North@usa.net>
Date: 1999/05/11
Raw View
In article <7h7n9d$a8p$1@engnews1.eng.sun.com>, Steve Clamage wrote:
> It seems unusual to want to call a derived-class member function
> as part of initializing a base-class sub-object (or after the
> derived portion has ceased to exist).  If that member function
> doesn't reference anything derived from the base class, why isn't
> it a member of that class instead of a derived class? (Rhetorical
> question, but it makes the point. ...

This makes for an interesting comparison with Java. Generally, it is
the Java language designers who take a more patronising attitude ("you
can't be trusted not to get in trouble with multiple inheritance, so we
won't let you have it"), while C++ gives you choice, and so enough rope
to hang yourself sometimes <g>!

However, in this particular case, the roles are reversed: C++ prevents
you from doing what you might want, while Java lets you go ahead,
allowing you to have full polymorphic behaviour in constructors, while
warning you of the potentially dire consequences of using state from
objects which are not yet fully constructed.

> ... Evidently you have some reason
> for wanting to do so.)
>

The reason you might want to use this is that, while indeed derived
objects might not have been fully constructed, you may want their full
*behaviour*, rather than state.

All Steve's remaining points are entirely valid, and I don't
necessarily take issue with them. There are other ways of getting fully
polymorphic behaviour in constructors, notably by using delegation to
an object of another class, which can be fully constructed, then passed
down to the base class constructor from the derived class. As is often
the case, with some slight overhead, one more level of indirection can
give you what you want with safety.

Dominic
New Malden, Tue, 11 May 1999 06:35 +0100
also cis:106136,2400
using Virtual Access 4.52 build 277 (32-bit)
on WinNT4 build 1381 (4.0 SP3)



[ 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: scorp@btinternet.com (Dave Harris)
Date: 1999/05/11
Raw View
gbush@my-dejanews.com () wrote:
> Probably, I was unclear in my previous post. Your last paragraph is
> exactly what I was talking about. The base classes use static type of
> "this" instead of its dynamic type. The later can be of a derived
> class.

Actually it's more accurate to say that it uses the dynamic type, but the
dynamic type is that of the base rather than the eventual most-derived
class. Just being pedantic ;-)

I personally prefer it this way. If the rule were changed as you propose,
it would be hard to be sure that undefined behaviour couldn't happen. You
could get a sequence of edits like:

    Alice writes a plain Base constructor.
    Bob writes the Derived class and overrides a virtual function.
    Alice changes the Base constructor to call the virtual function.

Your undefined behaviour results. This is quite subtle. Alice and Bob are
at separate sites, so Alice can't see that she's done anything wrong. She
can't test Derived; she doesn't have it. Bob has Derived but does not have
access to Alice's source code and it's not obvious that her implementation
change will break his subclass. Certainly the code still compiles. He can
test his code anyway, but we're talking undefined behaviour so it might
work 99.9% of the time, pass the tests, and only fail in the field.

Incidently, Java has a rule like yours except that instead of undefined
behaviour the Derived variables are guaranteed to have their default
values. That guarantee is useful but not as strong as knowing the
constructor has been run. In my view it's a bit of a nightmare. One just
has to cross one's fingers and hope that situations like the above don't
happen very often.

Incidently, this stuff need to be understood in the light of Bertrand
Meyer's notion of "Design by Contract". Roughly, each class has a "class
invariant" which is guaranteed to be true on entry (and exit) to every
routine. Knowing the class invariant, we can reason about the class's
behaviour and convince ourselves that the code works. The job of the
constructor, then, is to set up the class invariant at the beginning. If
there's a way to by-pass the constructor, all our careful reasoning about
the code's behaviour goes for nothing.

  Dave Harris, Nottingham, UK | "Weave a circle round him thrice,
      brangdon@cix.co.uk      |   And close your eyes with holy dread,
                              |  For he on honey dew hath fed
 http://www.bhresearch.co.uk/ |   And drunk the milk of Paradise."
---
[ 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: Francis Glassborow <francis@robinton.demon.co.uk>
Date: 1999/05/11
Raw View
In article <7h7n9d$a8p$1@engnews1.eng.sun.com>, Steve Clamage
<clamage@eng.sun.com> writes
>>Probably, I was unclear in my previous post. Your last paragraph is
>>exactly what I was talking about. The base classes use static type of
>>"this" instead of its dynamic type. The later can be of a derived
>>class. This restriction seems unnecessary and causes one to use extra
>>work (like call-back) to achieve what virtual mechanism is meant to.
>
>As I said, it is a language design and definition issue.

I think it is stronger than that.  If a final over-rider for a virtual
function was the one called at all stages during the process of
constructing an instance of a derived class the writers of derived
classes would need to know that the virtual function was called in the
definition (implementation) of a base sub-object before they provide an
over-rider.

Of course C++ could have been designed with the derived ctor over-riding
the base one (i.e. the base ctor is not called implicitly) but that
would result in a very different language to C++ (Smalltalk, for
example).

It takes quite a long time for most people to understand the
implications of the design of C++, but once you do you realise that
there are many things that could only be done differently if you
radically redesigned the language.  Not all the features of C++ stem
from its C ancestry, many stem from deliberate decisions made by its
principle designer based on his experiences with other languages.


Francis Glassborow      Journal Editor, Association of C & C++ Users
64 Southfield Rd
Oxford OX4 1PA          +44(0)1865 246490
All opinions are mine and do not represent those of any organisation
---
[ 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.Kanze@dresdner-bank.com
Date: 1999/05/11
Raw View
In article <VA.0000091b.cfca5f3b@dominic-viglen>,
  Dominic.North@usa.net wrote:
>
> In article <7h7n9d$a8p$1@engnews1.eng.sun.com>, Steve Clamage wrote:
> > It seems unusual to want to call a derived-class member function
> > as part of initializing a base-class sub-object (or after the
> > derived portion has ceased to exist).  If that member function
> > doesn't reference anything derived from the base class, why isn't
> > it a member of that class instead of a derived class? (Rhetorical
> > question, but it makes the point. ...

> This makes for an interesting comparison with Java. Generally, it is
> the Java language designers who take a more patronising attitude ("you
> can't be trusted not to get in trouble with multiple inheritance, so
> we won't let you have it"), while C++ gives you choice, and so enough
> rope However, in this particular case, the roles are reversed: C++
> prevents you from doing what you might want, while Java lets you go
> ahead, allowing you to have full polymorphic behaviour in
> constructors, while warning you of the potentially dire consequences
> of using state from objects which are not yet fully constructed.

Correct.  And having now used Java in a project of reasonable size, I
can appreciate the wisdom of the C++ rule.

> > ... Evidently you have some reason
> > for wanting to do so.)

> The reason you might want to use this is that, while indeed derived
> objects might not have been fully constructed, you may want their full
> *behaviour*, rather than state.

> All Steve's remaining points are entirely valid, and I don't
> necessarily take issue with them. There are other ways of getting
> fully polymorphic behaviour in constructors, notably by using
> delegation to an object of another class, which can be fully
> constructed, then passed down to the base class constructor from the
> derived class. As is often the case, with some slight overhead, one
> more level of indirection can give you what you want with safety.

Correct.  The only time I needed this sort of thing, it was easily
accomplished by means of an initialization class: rather than a default
constructor:

    MyBase::MyBase( MyInitializer = MyInitializer() ) ;

Which also served as the constructor taking a string.  MyInitializer
looked something like:

    class MyInitializer
    {
    friend class MyBase ;
    public:
        MyInitializer() : myInit( "" ) , myOwner( NULL ) {}
        MyInitializer( string const& initValue )
            :   myInit( initValue ) , myOwner( NULL ) {}
        ~MyInitializer() {
            if ( myOwner != NULL )
                myOwner->initialize( myInit ) ;
         }
    private:
        string const&   myInit ;
        MyBase*         myOwner ;
    } ;

The constructor for MyBase set the myOwner field in MyInitializer; since
the instances of MyInitializer were always temporaries, the destructor
got called at the end of the full expression.

This trick doesn't always work, of course.  In an expression like
f( MyDerived( "abc" ) ) ;, the initializer will only be called after the
return from f.  But in my case, the design of the class was such that it
wouldn't ever make sense to use it as a temporary anyway.

--
James Kanze                         mailto:
James.Kanze@dresdner-bank.com
Conseils en informatique orient   e objet/
                        Beratung in objekt orientierter
Datenverarbeitung
Ziegelh   ttenweg 17a, 60598 Frankfurt, Germany  Tel. +49 (069) 63 19 86
27


--== Sent via Deja.com http://www.deja.com/ ==--
---Share what you know. Learn what you don't.---


[ 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: source@netcom.com (David Harmon)
Date: 1999/05/11
Raw View
On 11 May 1999 00:12:18 GMT in comp.std.c++, clamage@eng.sun.com (Steve
Clamage) wrote:
>It seems unusual to want to call a derived-class member function
>as part of initializing a base-class sub-object (or after the
>derived portion has ceased to exist).

I think you are mistaken about that; it qualifies as a
Frequently Asked Question over on comp.lang.c++.

>If that member function
>doesn't reference anything derived from the base class, why isn't
>it a member of that class instead of a derived class?

In order to override the default behaviour of the base class, pretty
much like any other use of a virtual function.   It makes sense that it
may not depend on the state of the derived object in a constructor,
since the newly constructed object has no prior history.



[ 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: stephen.clamage@sun.com (Steve Clamage)
Date: 1999/05/12
Raw View
source@netcom.com (David Harmon) writes:


>On 11 May 1999 00:12:18 GMT in comp.std.c++, clamage@eng.sun.com (Steve
>Clamage) wrote:
>>It seems unusual to want to call a derived-class member function
>>as part of initializing a base-class sub-object (or after the
>>derived portion has ceased to exist).

>I think you are mistaken about that; it qualifies as a
>Frequently Asked Question over on comp.lang.c++.

It is common for newcomers to C++ to want to do unusual things
because they do not understand the consequences. Once the
consequences are explained, they make different design choices.
So the frequency of the question might only reflect the subtlety
of the language rule, and not a well-founded desire on the
part of the questioners.

Similarly, in this newsgroup a given language change may be
suggested frequently. Each time, the reasons why it is a bad idea
are explained, and that usually ends the discussion -- until
someone else has the same idea and doesn't think it through.

>>If that member function
>>doesn't reference anything derived from the base class, why isn't
>>it a member of that class instead of a derived class?

>In order to override the default behaviour of the base class, pretty
>much like any other use of a virtual function.   It makes sense that it
>may not depend on the state of the derived object in a constructor,
>since the newly constructed object has no prior history.

You left out the part where I said it was a rhetorical question.
I was not making a design pronouncement.

In any event, the difficulties go beyond depending on the state of
the derived portion of the object. If the derived-class function
refers in any way to derived-class data, the results of the program
are undefined if it is called from a base-class ctor or dtor.

I can imagine a design where derived classes contain no data, but
are derived only to get different behavior. In that case, it might
be sensible to want to call a derived-class function from the
base class ctor or dtor. But it might not be sensible. The
derived-class ctor or dtor might affect the state of the base class
sub-object in ways that matter to the function, in which case
the program would become unstable.

I still think that a design meeting all the implied restrictions
above is uncommon. (Not impossible, or even a bad idea; just
uncommon.) The most common designs involve derived classes whose
virtual functions depend on derived-class data.

--
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: Michael Podolsky <michael_podolsky@my-dejanews.com>
Date: 1999/05/12
Raw View
In article <7h96jc$s42$1@nnrp1.deja.com>,
  James.Kanze@dresdner-bank.com wrote:
> The only time I needed this sort of thing, it was easily
> accomplished by means of an initialization class: rather than a
default
> constructor:
>
>     MyBase::MyBase( MyInitializer = MyInitializer() ) ;
>
> Which also served as the constructor taking a string.  MyInitializer
> looked something like:
>
>     class MyInitializer
>     {
>     friend class MyBase ;
>     public:
>         MyInitializer() : myInit( "" ) , myOwner( NULL ) {}
>         MyInitializer( string const& initValue )
>             :   myInit( initValue ) , myOwner( NULL ) {}
>         ~MyInitializer() {
>             if ( myOwner != NULL )
>                 myOwner->initialize( myInit ) ;
>          }
>     private:
>         string const&   myInit ;
>         MyBase*         myOwner ;
>     } ;
>

Am I correct that you also have to provide artificial constructor
for derived classes with your solution --
like:
  MyDerived::MyDerived( const MyInitializer &mi= MyInitializer() )
    : MyBase(mi) {} // call myOwner->initialize(.) after
                    // full construction

yet...   in this case your code seems to be incorrect as your
MyBase constructor does not take MyInitalizer reference.

Could you clarify?

Michael


--== Sent via Deja.com http://www.deja.com/ ==--
---Share what you know. Learn what you don't.---
---
[ 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: Michael Podolsky <michael_podolsky@my-dejanews.com>
Date: 1999/05/12
Raw View
In article <7h79h0$dhr$1@nnrp1.deja.com>,
  gbush@my-dejanews.com wrote:

> The base classes use static type of
> "this" instead of its dynamic type.

May be.

> The later can be of a derived
> class.

Incorrect. In the next case

class Base
{
   Base(){f();}
   void f(){g();}
   virtual void g();
};

Base::g() would be called if f() function is called from
Base::Base(). Yet... function f() can't know that it
was called from the constructor, so 'this' is really
of 'Base' type when Base constructor (or destructor) is
executed.

Actually it is assignment of vtbl pointer that makes 'this'
to be of particular dynamic type and such assignment is made
by derived class constructor after base constructor have been called.

Michael


--== Sent via Deja.com http://www.deja.com/ ==--
---Share what you know. Learn what you don't.---
---
[ 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: seitz@ix.netcom.com
Date: 1999/05/12
Raw View
In article <I9hHTDA3R+N3EwP2@robinton.demon.co.uk>,
  Francis Glassborow <francisG@robinton.demon.co.uk> wrote:
> Not all the features of C++ stem
> from its C ancestry, many stem from deliberate decisions made by its
> principle designer based on his experiences with other languages.

And if you want to read the principal designer's explanation of why he
made this decision, see THE DESIGN AND EVOLUTION OF C++, Section 13.2.4


--== Sent via Deja.com http://www.deja.com/ ==--
---Share what you know. Learn what you don't.---


[ 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: sbnaran@localhost.localdomain.COM (Siemel Naran)
Date: 1999/05/10
Raw View
On 9 May 1999 13:06:59 GMT, superdude <me@web1.ucar.edu> wrote:

>As we all know C++ standard doesn't allow virtual mechanism in ctor/dtors.
>The only reason I'm aware of is that when base class is initialized some
>virtual function may try to access uninitialized members of derived class.
>That, certainly, is a possibility, and I expected the standard would define
>this as unspecified behavior rather than killing virtual mechanism
>completely. I'm not aware of any other problems that prevent using virtual
>mechanism. In fact, Borland does use virtual function mechanism in
>constructors for their visual library borrowing from Pascal. So it can work
>and in times it's very convenient. Question, why is ISO so unnecessary
>restrictive here?

I suppose the feature could lead to misuse in the long run.  There is
a reasonable alternative: pass callback functions and callback objects
down to the base class from the derived class.  Don't pass pointers to
member functions as this will not give virtual binding.  There's lots
of typing, but so it is.

--
----------------------------------
Siemel B. Naran (sbnaran@uiuc.edu)
----------------------------------


[ 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: enrightm@acm.org (Mike Enright)
Date: 1999/05/10
Raw View
"superdude" <me@web1.ucar.edu> wrote:

>
>I apologize if this topic has been already discussed, I searched Dejanews
>and it returned lotsa references but I couldn't find anything relevant. So
>here it goes...
>As we all know C++ standard doesn't allow virtual mechanism in ctor/dtors.
>The only reason I'm aware of is that when base class is initialized some
>virtual function may try to access uninitialized members of derived class.
>That, certainly, is a possibility, and I expected the standard would define
>this as unspecified behavior rather than killing virtual mechanism
>completely. I'm not aware of any other problems that prevent using virtual
>mechanism. In fact, Borland does use virtual function mechanism in
>constructors for their visual library borrowing from Pascal. So it can work
>and in times it's very convenient. Question, why is ISO so unnecessary
>restrictive here?
>Gene.

There are numerous pitfalls in invoking virtual functions from within
the constructor. However, in the Standard, 12.6.2/8 it says that
virtual functions can be called. At 12.7/3 it defines what happens. At
10.4/6 it says that the effect is undefined if the function in
question is pure virtual (and I understand this to mean, pure virtual
functions w.r.t. the type as it would be known within the constructor,
not w.r.t some base class). So ISO is only as restrictive as
necessary; perhaps some people confuse what happens with pure virtual
functions with what happens to other virtual functions.

The weakness of virtual functions within a constructor is that for all
practical purposes they aren't dynamically dispatched. For example:

class Base
{
public:
  virtual int GetRocks()=0;
  // Base()
  // {
  //   std::cout << GetRocks(); // undefined
  // }
};

class Concrete : public Base
{
public:
  Concrete()
  : rocks(3)
  {
    std::cout << GetRocks(); // defined
                      // always invokes Concrete::GetRocks()
  }
  int GetRocks() { return rocks; }
private:
  int rocks;
};

class Derived : public Concrete
{
public:
  Derived()
  : stones(3), pebbles(5)
  {
  }
  // This doesn't change output generated in
  // Concrete destructor.
  int GetRocks() { return stones+pebbles; }
};

Or perhaps what you are looking for is that the final override defined
by the most derived type would be invoked. That would require that the
code in a constructor be able to invoke virtual functions _very_
flexibly, in a borderline-divine, almost-SmallTalk-like way. And the
most derived constructors haven't prepared those most derived
overrides to be run.


--
Mike Enright
enrightm@acm.org (Email replies cheerfully ignored, use the news group)
http://www.users.cts.com/sd/m/menright/
Cardiff-by-the-Sea, California, USA



[ 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: 1999/05/10
Raw View
"superdude" <me@web1.ucar.edu> writes:

>As we all know C++ standard doesn't allow virtual mechanism in ctor/dtors.
>The only reason I'm aware of is that when base class is initialized some
>virtual function may try to access uninitialized members of derived class.
>That, certainly, is a possibility, and I expected the standard would define
>this as unspecified behavior rather than killing virtual mechanism
>completely.

Your premise is wrong.  The virtual mechanism is NOT disabled in
ctors and dtors.

For example, try this program:

#include <iostream>

struct base {
    virtual void f() { std::cout << "base::f\n"; };
};

void foo(base* p) { p->f(); }

struct der : public base {
    virtual void f() { std::cout << "der::f\n"; };
    der() { foo(this); }
    ~der() { foo(this); }
};

int main()
{
    der d;
}

Suppose the virtual mechanism were disabled during ctors and dtors.
Then during the construction and destruction of the der part of d,
foo would get a base*, and the program would print base::f twice.
Instead, it prints der::f twice, proving that the virtual mechanism
is intact.  (How else could foo, which knows only about base
objects, cause a function from der to be invoked?)

As a language design issue, one could take the view that during
construction, the type of that object starts as and remains the
type of the complete (most-derived) object. Some languages have
that property. It is up to the programmer not to invoke, directly
or indirectly, any operation on parts of the object that haven't
yet been initialized.

C++ uses a different rule, by deliberate design. During construction
of an object, the current type of the object is the type of the
constructor that is currently running. Virtual dispatch is not
required in the code residing in the constructor, because the
dynamic type of the object (at that moment) is known at compile
time.

--
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: "superdude" <me@web1.ucar.edu>
Date: 1999/05/09
Raw View
I apologize if this topic has been already discussed, I searched Dejanews
and it returned lotsa references but I couldn't find anything relevant. So
here it goes...
As we all know C++ standard doesn't allow virtual mechanism in ctor/dtors.
The only reason I'm aware of is that when base class is initialized some
virtual function may try to access uninitialized members of derived class.
That, certainly, is a possibility, and I expected the standard would define
this as unspecified behavior rather than killing virtual mechanism
completely. I'm not aware of any other problems that prevent using virtual
mechanism. In fact, Borland does use virtual function mechanism in
constructors for their visual library borrowing from Pascal. So it can work
and in times it's very convenient. Question, why is ISO so unnecessary
restrictive here?
Gene.



[ 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              ]