Topic: As long as everyone is asking for new features...
Author: Valentin.Bonnard@free.fr (Valentin Bonnard)
Date: Mon, 18 Jun 2001 04:29:39 GMT Raw View
Anthony Williams wrote:
> "Thomas A. Horsley" <Tom.Horsley@worldnet.att.net> wrote in message
> news:usnh51jfs.fsf@worldnet.att.net...
> > >> How do people keep missing this?
> > >
> > >I think that they do not.
>
> > OK, they are missing something else instead :-).
The fact that you aren't interrested ?
> > >Example: Base class needs to be connected to a primitive
> > >environment, so it defines a post-constructor ++Base which does
> > >that work. A derived class (let's be original and call it
> > >"Derived") is then written which needs to be connected to a
> > >higher-level environment. Should Derived then define another
> > >post-constructor to run after the post-constructor of Base?
> > Obviously yes. Different classes in the heirarchy can all have
> > different constructors, why wouldn't different classes in the
> > heirarchy be able to have different post constructors too? Why
> > wouldn't all post constructors in the heirarchy be run after the
> > entire object is created just like all constructors are run during
> > the object creation?
> > (Maybe that's the part people keep missing?).
No. You assume that other people miss something. They don't.
> > >> If you have code that needs to come after that, it can go at
> > >> the end of the previous code in the post constructor.
> > >
> > >Post constructor of which class in the hierarchy?
>
> > The class that needs the actions to occur, of course.
>
> > >Maybe you think that "post post constructor" means two post
> > >constructors defined in the same class, whereas others are
> > >thinking in terms of inheritance hierarchies.
>
> > Actually, I don't think "post post" or "post post post"
> > constructor means anything at all.
As the one who first introduced this idea here (at least I think so),
I can tell you that it does means something. It parses as post-(post-
constructor). In other words, it's to a post-constructor what a post-
constructor is to a constructor.
> > This is also why I don't know what "post post" constructor means.
So don't say that it means nothing.
> > That's the point I'm interested in. I'm not interested in any
> > other points in time. That's why I don't know what "post post"
> > constructor means.
Because you aren't interrested.
> > Come to think of it, I don't know what "attaching to the
> > environment" means either, that's another phrase someone else in
> > this thread invented :-).
>
> OK, so what if we have a class hierarchy, where each class has a
> post constructor, and we instantiate an object of the most derived
> class. Firstly, all the constructors are run. Then all the post
> constructors are run (in the same order, I presume). Does the object
> count as fully constructed during these calls?
Yes. It's fully -constructed.
^
emphasis here
> Can I start calling functions that assume it is fully constructed?
Yes
> What if one of the post constructors throws an exception?
The object is -destructed.
> Do we "unwind" by calling each of the pre-destructors, and then
> destructors?
No.
> Also, your idea is that virtual functions can be called in
> post-constructors.
Yes: -virtual functions can be called in -post-contructors.
^ ^
> How does a virtual function in a derived class know which of its
> base classes have had their post-constructors called, and which
> haven't?
It doesn't, by definition of -virtual function.
> Indeed, how does it know whether its own class's post constructor
> has been called or not?
Same answer.
> Don't get me wrong, I can see the case for wanting such a feature; I
> just can't see how all the details would fit together.
By introducing -virtual, post-virtual, post-post-virtual,
omega-post-virtual, omega-omega-post-virtual... functions.
--
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://www.research.att.com/~austern/csc/faq.html ]
Author: Michiel Salters<Michiel.Salters@cmg.nl>
Date: Wed, 13 Jun 2001 16:21:05 GMT Raw View
In article <t3g0d9g3w7.fsf@watts.itp.tuwien.ac.at>, Christopher Eltschka says...
>
>Michiel Salters<Michiel.Salters@cmg.nl> writes:
>
>> In article <3B1679BE.9575059C@dollywood.itp.tuwien.ac.at>, Christopher Eltschka
>> says...
>> >
>> >Michiel Salters wrote:
>> >>
>> >> In article <3B153C6E.4448D2E4@dollywood.itp.tuwien.ac.at>, Christopher Eltschka
>> >> says...
>> >>
>> >> [ Arguing for post-constructors ]
>>
>> >> A solution to that would be to add a template class
>> >> Connect<T>: public T, which would be the only class able to
>> >> create classes derived from base_window. You would then have
>> >> to write Connect<MyWindow> foo. The ctor for Connect runs
>> >> after the ctor for MyWindow, solving the order problem.
>> >> It also makes it clear that the act of connecting is not
>> >> performed by MyWindow.
>> >
>> >This has several problems:
>> >
>> >a) Forwarding arguments to the class constructor (note that
>> > for each derived class the constructor argument list can be
>> > different, and especially is not predictable).
>> >
>> >b) How do you specify in a base class that it's derived
>> > classes(!) may not be created directly, but only by
>> > the Connect<T> object?
>> >
>> >However, this is the best approximation I've yet seen.
>> >So maybe solving problems a and b would be a better solution
>> >than introducing post-constructors.
>>
>> For (a) we'd probably need a set of template constructors:
>>
>> template <typename Window, typename T1>
>> Connect::Connect(T1 t1) : Window(t1) ...
>> template <typename Window, typename T1, typename T2>
>> Connect::Connect(T1 t1, T2 t2) : Window(t1, t2) ...
>>
>> This limits the maximum number of arguments, but I don't think
>> a limit of 16 is likely to be exceeded.
>
>But this allows only per-value argument passing. OTOH, using
>references then generates the rvalue passing problem (a non-const
>rvalue causes the non-const type to be used on templates, but rvalues
>cannot be bound to non-const references).
>
>But this is a problem which IMHO should be solved generally in C++
>(and adding variable argument templates would be a good thing too,
>IMHO).
Well, we could provide both Tn& and Tn const& variants, but if we
have to provide all variants with up to 16 arguments we'll have
something like 1<<17 variants. We need a syntax for variable
argument lists, but I don't think we need more than "pass
unmodified". We don't have to parse the list (in this example).
I.e.
template <argumentlist Al>
int get_obj ( A a )
{
return get_obj_indirect(true, a);
}
would mean that get_obj (1,2) calls get_obj_indirect(bool, int, int).
That would be enough for the ctor forwarding.
>> For (b) I'm thinking about a helper class, which is a virtual
>> base class of our logical base class. It befriends Connect<T>,
>> which allows Connect<T> to use the private ctor for base class.
>> As a result you can't create Window but you can create
>> Connect<Window>.
>
>I don't think it's allowed to do this. g++ (the Codesourcery online
>compiler) doesn't like the following code, and I believe it is right
>to complain:
>
>class X
>{
> friend class Z;
>private:
> X();
>};
>
>class Y: public virtual X { Y() {} };
>
>class Z: public Y {};
>
>The error message is:
>
>/usr/tmp/@25091.7.cc: In constructor `Y::Y()':
>/usr/tmp/@25091.7.cc:5: `X::X()' is private
>/usr/tmp/@25091.7.cc:8: within this context
It is perfectly Ok. I ran into the same problem; when I posted it
I assumed incorrectly that the error would only be diagnosed when
Y::Y would be instantiated - but the class Y typically isn't a
template!
>However, inspired from this, I've found a solution:
>
>class X {
> friend class Z;
>private:
> class Key;
> virtual void unlock(Key)=0;
>};
>class Y: public virtual X
>{
> // void unlock(Key); would not compile, since Key is private
>};
>class Z: public Y { void unlock(Key); };
>
>// Y y; would not compile since void unlock(Key) is abstract
>
>Z z;
>
>If this does not have any flaw, it's an acceptable solution.
I think it does the trick; if Z would be a template
(template <typename Y> class Z: public Y ) it can be
provided by the author of X and its ctor would run after Ys.
>Therefore if the template forwarder proble gets solved (and it IMHO
>should be solved anyway, since it occurs in many contexts), we have an
>acceptable solution to the post-constructor problem, and therefore I
>don't see any more any value in adding post-constructors to the
>language.
I agree. But I'm afraid the proposal for such forwarders is going to
be quite complex. Loki's Typelist or similar mechanisms are too ugly.
Regards,
Michiel Salters
--
Michiel Salters
Consultant Technical Software Engineering
CMG Trade, Transport & Industry
Michiel.Salters@cmg.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://www.research.att.com/~austern/csc/faq.html ]
Author: Matvei Brodski <mbrodski@bear.com>
Date: Wed, 13 Jun 2001 17:42:25 GMT Raw View
Anthony Williams wrote:
> OK, so what if we have a class hierarchy, where each class has a post
> constructor, and we instantiate an object of the most derived class.
> Firstly, all the constructors are run. Then all the post constructors are
> run (in the same order, I presume).
This one is easy: let's consider a post-ctor to be a special case
of a virtual function (one, that is called by a compiler when the
construction of a most derived class is done). In this case a
post-ctor of the most derived type is going to be called (since
compiler DOES know at the moment which class is being constructed).
Now, if you want to "add" something in your Derived class post-ctor
to a post-ctor of base, you just call it as usual:
class Base {
public:
Base();
virtual void foo();
Base++() { foo() }; // implicitly virtual post-ctor
virtual ~Base() {}
};
class Derived : public Base {
public:
Derived();
virtual void foo();
virtual void bar()
Derived++() { Base++(); bar(); }
virtual ~Derived() {}
};
name Derived++ is different from Base++, but so are ~Base and ~Derived.
> Does the object count as fully
> constructed during these calls? Can I start calling functions that assume it
> is fully constructed?
yes. yes.
> What if one of the post constructors throws an
> exception? Do we "unwind" by calling each of the pre-destructors, and then
> destructors? Now some of the classes will have had constructor,
> post-constructor, pre-destructor and destructor called. Others will have
> just constructor and destructor called. Is this a problem?
As far as I understand, when running a destructor, compiler has some
kind of a flag set telling program if that was the most base destructor,
so that if it was, we can call function releasing memory.
Similarly here, compiler may set a flag telling us if the constructor
body we are in is on of the most derived class, so that if it is, we
can (as the last thing we do before returning from it) call the
post-ctor (which is just some virtual function from the point of view
of the program at the moment). It is as if we were to write:
Base::Base()
{
...
if ( most_derived ) Base++();
}
Derived::Derived()
{
...
if ( most_derived ) Base++();
}
Note, that the last line calls Derived++() (if provided) through the
normal virtual function call mechanism that ought to be in a finilized
state at the moment.
Exceptions ought to be handled just so :o)
> Also, your idea is that virtual functions can be called in
> post-constructors. How does a virtual function in a derived class know which
> of its base classes have had their post-constructors called, and which
> haven't?
Why should it know?
> Indeed, how does it know whether its own class's post constructor
> has been called or not? The reason for introducing post-constructors is
> because there might be a _necessary_ step which depends on virtual
> functions. In which case, if this _necessary_ step hasn't been completed, is
> the object usable?
In the case above we either return normally from the construction
site (and so - claim an object usable) or throw.
> If the step isn't necessary, then the need for
> post-constructors goes away entirely - the user can decide whether or not to
> call any additional, optional, setup functions _after_ construction.
Or (s)he can forget to. What is the point of having a constructor,
if we can just allocate memory and then call an init() member
function? Post-ctor is meant to solve all the same problems that
constructor solves with some little twist: it is called after the
vtable is done and so, unlike ctor, can call virtual functions
correctly.
Matvei.
---
[ 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://www.research.att.com/~austern/csc/faq.html ]
Author: Tom.Horsley@worldnet.att.net (Thomas A. Horsley)
Date: Mon, 11 Jun 2001 21:16:30 GMT Raw View
>How can you know that? One of the reasons postulated was to connect
>the object to its environment. Suppose I have initialization code
>that can only be executed once the object has been connected?
How do people keep missing this? If you have code like that, it goes at the
end of the post constructor. If you have code that needs to come after that,
it can go at the end of the previous code in the post constructor. You can
lump an infinite sequence of actions into the post constructor, but you have
to have a post constructor in order to be able to have a place to put them
all :-).
--
>>==>> The *Best* political site <URL:http://www.vote-smart.org/> >>==+
email: Tom.Horsley@worldnet.att.net icbm: Delray Beach, FL |
<URL:http://home.att.net/~Tom.Horsley> Free Software and Politics <<==+
---
[ 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://www.research.att.com/~austern/csc/faq.html ]
Author: James Dennett <jdennett@acm.org>
Date: Mon, 11 Jun 2001 21:40:48 GMT Raw View
"Thomas A. Horsley" wrote:
>
> >How can you know that? One of the reasons postulated was to connect
> >the object to its environment. Suppose I have initialization code
> >that can only be executed once the object has been connected?
>
> How do people keep missing this?
I think that they do not.
> If you have code like that, it goes at the
> end of the post constructor.
Example: Base class needs to be connected to a primitive environment,
so it defines a post-constructor ++Base which does that work. A
derived class (let's be original and call it "Derived") is then
written which needs to be connected to a higher-level environment.
Should Derived then define another post-constructor to run after
the post-constructor of Base?
> If you have code that needs to come after that,
> it can go at the end of the previous code in the post constructor.
Post constructor of which class in the hierarchy?
> You can
> lump an infinite sequence of actions into the post constructor, but you have
> to have a post constructor in order to be able to have a place to put them
> all :-).
A general assumption of writing C++ code is that base classes should
not need to be modified when derived classes are written (ignoring
exceptions to this rule, of course). How does this work if you do
not want "post post constructors"? Maybe you think that "post post
constructor" means two post constructors defined in the same class,
whereas others are thinking in terms of inheritance hierarchies.
-- James Dennett
---
[ 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://www.research.att.com/~austern/csc/faq.html ]
Author: Matvei Brodski <mbrodski@bear.com>
Date: Tue, 12 Jun 2001 21:14:00 GMT Raw View
James Kanze wrote:
> "Andrei Alexandrescu" <andrewalex@hotmail.com> wrote
> > "Michiel Salters" <Michiel.Salters@cmg.nl> wrote
> > > In article <ur8y2tae0.fsf@worldnet.att.net>, Thomas A. Horsley says...
> > > > 1. "post constructors" - a new kind of constructor that gets
> > > > called following the final constructor for the whole
> > > > object. Virtual functions would work as expected in the
> > > > post constructors
> > > I believe Valentin Bonnard once pointed out that this area
> > > contains the largest number of features which could be trivially
> > > added, namely post-constructros, post-post-constructors,
> > > post-post-post-constructors, etc.
> > But that's wrong. The request is legit and does not go ad
> > infinitum. It's about invoking a virtual function after the full
> > object was created. There's not going to be a supplemental need
> > after that.
>
> How can you know that? One of the reasons postulated was to connect
> the object to its environment.
I thought the reason was the completion of object construction.
In particular - its polymorphism providing mechanisms. Say, I
want to end object initialization with the call to a virtual
function that I want to be called correctly (in case someone
derives from the class I am writing and provides new definition
for the said function). For this I need somehow to call it
when the "outermost" constructor finished its vtable-processing.
Say, proverbial class Shape can call virtual draw() in its
post-ctor, so that whenever we instantiate Circle, as soon as
it is constructed, appropriate draw() is called.
> Suppose I have initialization code
> that can only be executed once the object has been connected?
So, make your post-ctor longer. Instead of
void post_ctor() { foo(); }
void post_post_ctor() { bar(); }
do this:
void post_ctor() { foo(); bar(); }
Point here is before you call foo() you want to be sure that vtable
is done. You need compiler to find that moment (since you can not
be sure if you are in a ctor of your type or some derived type).
Once a class is constructed there is nothing else that can change
its vtable. There is 1 critical point in polymorphic object's creation.
Whatever you do after that - it would be you, not the compiler, i.e. -
you have full control when and what functions to call. So, if
bar() can be called only after foo() - by all means do so.
Same with the destruction. Say, I want my objects to save themselves
before being destructed. So, I want to provide virtual function save()
and call it in pre-destructor (to make sure the correct save() is called).
I do not need a pre-pre-destructor, since, again, there is only one
critical point between the state where vtable was "ok" and the one where
it is not.
Did I miss something?
Matvei.
---
[ 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://www.research.att.com/~austern/csc/faq.html ]
Author: Tom.Horsley@worldnet.att.net (Thomas A. Horsley)
Date: Tue, 12 Jun 2001 21:35:54 GMT Raw View
>> How do people keep missing this?
>
>I think that they do not.
OK, they are missing something else instead :-).
>Example: Base class needs to be connected to a primitive environment,
>so it defines a post-constructor ++Base which does that work. A
>derived class (let's be original and call it "Derived") is then
>written which needs to be connected to a higher-level environment.
>Should Derived then define another post-constructor to run after
>the post-constructor of Base?
Obviously yes. Different classes in the heirarchy can all have different
constructors, why wouldn't different classes in the heirarchy be able to have
different post constructors too? Why wouldn't all post constructors in the
heirarchy be run after the entire object is created just like all
constructors are run during the object creation? (Maybe that's the part
people keep missing?). That's not a post-post constructor or a
post-post-post constructor, its just a different class with its own
post-constructor.
>> If you have code that needs to come after that,
>> it can go at the end of the previous code in the post constructor.
>
>Post constructor of which class in the hierarchy?
The class that needs the actions to occur, of course.
>Maybe you think that "post post
>constructor" means two post constructors defined in the same class,
>whereas others are thinking in terms of inheritance hierarchies.
Actually, I don't think "post post" or "post post post" constructor means
anything at all. Other people in this thread keep dredging up that
particular boogey man :-).
Maybe I should cast this in a completely different light: What I think is
that the compiler (and absolutely nobody else right now) is the only one
that knows when an entire object has been completely constructed. If I want
to run some code once the object is constructed (and I encounter this
situation with extreme frequency), then the only completely reliable way to
make sure that code is always run, is to have a compiler extension to
support some new way of running code after the object is constructed.
Hence the name "post constructor".
This is also why I don't know what "post post" constructor means.
There is only one point in time when the object has been fully constructed.
That's the point I'm interested in. I'm not interested in any other points
in time. That's why I don't know what "post post" constructor means.
Come to think of it, I don't know what "attaching to the environment" means
either, that's another phrase someone else in this thread invented :-).
--
>>==>> The *Best* political site <URL:http://www.vote-smart.org/> >>==+
email: Tom.Horsley@worldnet.att.net icbm: Delray Beach, FL |
<URL:http://home.att.net/~Tom.Horsley> Free Software and Politics <<==+
---
[ 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://www.research.att.com/~austern/csc/faq.html ]
Author: kanze@gabi-soft.de (James Kanze)
Date: Mon, 11 Jun 2001 16:25:19 GMT Raw View
"Andrei Alexandrescu" <andrewalex@hotmail.com> wrote in message news:<9eaflh$1ntmk$1@ID-14036.news.dfncis.de>...
> "Michiel Salters" <Michiel.Salters@cmg.nl> wrote in message
> news:OsvJ6.4244$vg1.327313@www.newsranger.com...
> > In article <ur8y2tae0.fsf@worldnet.att.net>, Thomas A. Horsley says...
> > >I've got two on my list:
> > > 1. "post constructors" - a new kind of constructor that gets
> > > called following the final constructor for the whole
> > > object. Virtual functions would work as expected in the
> > > post constructors and you wouldn't have to remember to use
> > > whatever convention you've adopted to get aound not having
> > > post constructors.
> > I believe Valentin Bonnard once pointed out that this area
> > contains the largest number of features which could be trivially
> > added, namely post-constructros, post-post-constructors,
> > post-post-post-constructors, etc.
> But that's wrong. The request is legit and does not go ad
> infinitum. It's about invoking a virtual function after the full
> object was created. There's not going to be a supplemental need
> after that.
How can you know that? One of the reasons postulated was to connect
the object to its environment. Suppose I have initialization code
that can only be executed once the object has been connected?
Obviously, the number of cases where a post-post-constructor is needed
will be less than the number of cases where a post-constructor is
needed, but in the end, there is no a priori reason for the sequence
to even be finite.
With regards to the single post-constructor, it is possible (although
a bit awkward) to implement it within the present language.
--
James Kanze mailto:kanze@gabi-soft.de
Conseils en informatique orient e objet/
Beratung in objektorientierter Datenverarbeitung
Ziegelh ttenweg 17a, 60598 Frankfurt, Germany Tel. +49(069)63198627
---
[ 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://www.research.att.com/~austern/csc/faq.html ]
Author: "Anthony Williams" <anthwil@nortelnetworks.com>
Date: Wed, 13 Jun 2001 13:15:09 GMT Raw View
"Thomas A. Horsley" <Tom.Horsley@worldnet.att.net> wrote in message
news:usnh51jfs.fsf@worldnet.att.net...
> >> How do people keep missing this?
> >
> >I think that they do not.
>
> OK, they are missing something else instead :-).
>
> >Example: Base class needs to be connected to a primitive environment,
> >so it defines a post-constructor ++Base which does that work. A
> >derived class (let's be original and call it "Derived") is then
> >written which needs to be connected to a higher-level environment.
> >Should Derived then define another post-constructor to run after
> >the post-constructor of Base?
>
> Obviously yes. Different classes in the heirarchy can all have different
> constructors, why wouldn't different classes in the heirarchy be able to
have
> different post constructors too? Why wouldn't all post constructors in the
> heirarchy be run after the entire object is created just like all
> constructors are run during the object creation? (Maybe that's the part
> people keep missing?). That's not a post-post constructor or a
> post-post-post constructor, its just a different class with its own
> post-constructor.
>
> >> If you have code that needs to come after that,
> >> it can go at the end of the previous code in the post constructor.
> >
> >Post constructor of which class in the hierarchy?
>
> The class that needs the actions to occur, of course.
>
> >Maybe you think that "post post
> >constructor" means two post constructors defined in the same class,
> >whereas others are thinking in terms of inheritance hierarchies.
>
> Actually, I don't think "post post" or "post post post" constructor means
> anything at all. Other people in this thread keep dredging up that
> particular boogey man :-).
>
> Maybe I should cast this in a completely different light: What I think is
> that the compiler (and absolutely nobody else right now) is the only one
> that knows when an entire object has been completely constructed. If I
want
> to run some code once the object is constructed (and I encounter this
> situation with extreme frequency), then the only completely reliable way
to
> make sure that code is always run, is to have a compiler extension to
> support some new way of running code after the object is constructed.
> Hence the name "post constructor".
>
> This is also why I don't know what "post post" constructor means.
>
> There is only one point in time when the object has been fully
constructed.
>
> That's the point I'm interested in. I'm not interested in any other points
> in time. That's why I don't know what "post post" constructor means.
>
> Come to think of it, I don't know what "attaching to the environment"
means
> either, that's another phrase someone else in this thread invented :-).
OK, so what if we have a class hierarchy, where each class has a post
constructor, and we instantiate an object of the most derived class.
Firstly, all the constructors are run. Then all the post constructors are
run (in the same order, I presume). Does the object count as fully
constructed during these calls? Can I start calling functions that assume it
is fully constructed? What if one of the post constructors throws an
exception? Do we "unwind" by calling each of the pre-destructors, and then
destructors? Now some of the classes will have had constructor,
post-constructor, pre-destructor and destructor called. Others will have
just constructor and destructor called. Is this a problem?
Also, your idea is that virtual functions can be called in
post-constructors. How does a virtual function in a derived class know which
of its base classes have had their post-constructors called, and which
haven't? Indeed, how does it know whether its own class's post constructor
has been called or not? The reason for introducing post-constructors is
because there might be a _necessary_ step which depends on virtual
functions. In which case, if this _necessary_ step hasn't been completed, is
the object usable? If the step isn't necessary, then the need for
post-constructors goes away entirely - the user can decide whether or not to
call any additional, optional, setup functions _after_ construction.
Don't get me wrong, I can see the case for wanting such a feature; I just
can't see how all the details would fit together.
Anthony
--
Anthony Williams
Software Engineer, Nortel Networks Optoelectronics
The opinions expressed in this message are not necessarily those of my
employer
---
[ 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://www.research.att.com/~austern/csc/faq.html ]
Author: celtschk@web.de ("Christopher Eltschka")
Date: Sun, 10 Jun 2001 05:02:52 GMT Raw View
Michiel Salters<Michiel.Salters@cmg.nl> writes:
> In article <3B1679BE.9575059C@dollywood.itp.tuwien.ac.at>, Christopher Eltschka
> says...
> >
> >Michiel Salters wrote:
> >>
> >> In article <3B153C6E.4448D2E4@dollywood.itp.tuwien.ac.at>, Christopher Eltschka
> >> says...
> >>
> >> [ Arguing for post-constructors ]
>
> >> A solution to that would be to add a template class
> >> Connect<T>: public T, which would be the only class able to
> >> create classes derived from base_window. You would then have
> >> to write Connect<MyWindow> foo. The ctor for Connect runs
> >> after the ctor for MyWindow, solving the order problem.
> >> It also makes it clear that the act of connecting is not
> >> performed by MyWindow.
> >
> >This has several problems:
> >
> >a) Forwarding arguments to the class constructor (note that
> > for each derived class the constructor argument list can be
> > different, and especially is not predictable).
> >
> >b) How do you specify in a base class that it's derived
> > classes(!) may not be created directly, but only by
> > the Connect<T> object?
> >
> >However, this is the best approximation I've yet seen.
> >So maybe solving problems a and b would be a better solution
> >than introducing post-constructors.
>
> For (a) we'd probably need a set of template constructors:
>
> template <typename Window, typename T1>
> Connect::Connect(T1 t1) : Window(t1) ...
> template <typename Window, typename T1, typename T2>
> Connect::Connect(T1 t1, T2 t2) : Window(t1, t2) ...
>
> This limits the maximum number of arguments, but I don't think
> a limit of 16 is likely to be exceeded.
But this allows only per-value argument passing. OTOH, using
references then generates the rvalue passing problem (a non-const
rvalue causes the non-const type to be used on templates, but rvalues
cannot be bound to non-const references).
But this is a problem which IMHO should be solved generally in C++
(and adding variable argument templates would be a good thing too,
IMHO).
>
> For (b) I'm thinking about a helper class, which is a virtual
> base class of our logical base class. It befriends Connect<T>,
> which allows Connect<T> to use the private ctor for base class.
> As a result you can't create Window but you can create
> Connect<Window>.
I don't think it's allowed to do this. g++ (the Codesourcery online
compiler) doesn't like the following code, and I believe it is right
to complain:
class X
{
friend class Z;
private:
X();
};
class Y: public virtual X { Y() {} };
class Z: public Y {};
The error message is:
/usr/tmp/@25091.7.cc: In constructor `Y::Y()':
/usr/tmp/@25091.7.cc:5: `X::X()' is private
/usr/tmp/@25091.7.cc:8: within this context
However, inspired from this, I've found a solution:
class X
{
friend class Z;
private:
class Key;
virtual void unlock(Key)=0;
};
class Y: public virtual X
{
// void unlock(Key); would not compile, since Key is private
};
class Z: public Y { void unlock(Key); };
// Y y; would not compile since void unlock(Key) is abstract
Z z;
If this does not have any flaw, it's an acceptable solution.
Therefore if the template forwarder proble gets solved (and it IMHO
should be solved anyway, since it occurs in many contexts), we have an
acceptable solution to the post-constructor problem, and therefore I
don't see any more any value in adding post-constructors to the
language.
>
> The problem with this solution of (b) is the nasty user providing
> template<> Connect<Window>. But since we're protecting against
> Murphy, not Machiavelli, so I'm going to call this a feature.
> "By default it does what the base class author intended, but it is
> configurable".
This I don't consider a problem either. Specializing a template is
something one doesn't do by accident, and it isn't any more dangerous
in this case than it is in any other case (I can specialize
std::vector<MyClass> to something which doesn't even remotely resemble
a vector!)
---
[ 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://www.research.att.com/~austern/csc/faq.html ]
Author: Michiel Salters<Michiel.Salters@cmg.nl>
Date: Thu, 31 May 2001 13:10:45 GMT Raw View
In article <3B153C6E.4448D2E4@dollywood.itp.tuwien.ac.at>, Christopher Eltschka
says...
[ Arguing for post-constructors ]
>It again has the problem that you can forget to do the second
>thing: You can write
>
> MyWindow foo;
>
>without writing
>
> WindowConnection bar(foo)
>
>after it. So it's not yet better than having to call
>
> foo->connect()
>
>after construction. The intention is that after
>
> MyWindow foo;
>
>the window _automatically_ gets connected.
A solution to that would be to add a template class
Connect<T>: public T, which would be the only class able to
create classes derived from base_window. You would then have
to write Connect<MyWindow> foo. The ctor for Connect runs
after the ctor for MyWindow, solving the order problem.
It also makes it clear that the act of connecting is not
performed by MyWindow.
>Moreover, if you want to add to the "post-constructor" (i.e.
>the constructor of WindowConnection), you get the problem
>to remember to construct a WindowConnection for Window1,
>Window2 and Window3, to construct a Window4Connection for
>Window4 and Window5 (which is derived from Window4) and
>a Window6Connection for Window6. This is even more error-prone
>than to just remember calling foo->connect().
Why would you need to remember that ? The post-constructor run
for Window1 is the same as for Window6; the post-constructor of
the base_window, right? BTW, even if the difference is true one
could overload WindowConnection::WindowConnection().
--
Michiel Salters
Consultant Technical Software Engineering
CMG Trade, Transport & Industry
Michiel.Salters@cmg.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://www.research.att.com/~austern/csc/faq.html ]
Author: Christopher Eltschka <celtschk@dollywood.itp.tuwien.ac.at>
Date: Thu, 31 May 2001 17:11:25 GMT Raw View
Michiel Salters wrote:
>
> In article <3B153C6E.4448D2E4@dollywood.itp.tuwien.ac.at>, Christopher Eltschka
> says...
>
> [ Arguing for post-constructors ]
>
> >It again has the problem that you can forget to do the second
> >thing: You can write
> >
> > MyWindow foo;
> >
> >without writing
> >
> > WindowConnection bar(foo)
> >
> >after it. So it's not yet better than having to call
> >
> > foo->connect()
> >
> >after construction. The intention is that after
> >
> > MyWindow foo;
> >
> >the window _automatically_ gets connected.
>
> A solution to that would be to add a template class
> Connect<T>: public T, which would be the only class able to
> create classes derived from base_window. You would then have
> to write Connect<MyWindow> foo. The ctor for Connect runs
> after the ctor for MyWindow, solving the order problem.
> It also makes it clear that the act of connecting is not
> performed by MyWindow.
This has several problems:
a) Forwarding arguments to the class constructor (note that
for each derived class the constructor argument list can be
different, and especially is not predictable).
b) How do you specify in a base class that it's derived
classes(!) may not be created directly, but only by
the Connect<T> object?
However, this is the best approximation I've yet seen.
So maybe solving problems a and b would be a better solution
than introducing post-constructors.
The solution to a would be very useful in othre contexts
as well (basically everywhere you need a generic forwarding
function).
The solution to b might already be possible in current C++,
however I don't see how.
>
> >Moreover, if you want to add to the "post-constructor" (i.e.
> >the constructor of WindowConnection), you get the problem
> >to remember to construct a WindowConnection for Window1,
> >Window2 and Window3, to construct a Window4Connection for
> >Window4 and Window5 (which is derived from Window4) and
> >a Window6Connection for Window6. This is even more error-prone
> >than to just remember calling foo->connect().
>
> Why would you need to remember that ?
Because if I write
WindowConnection(win6var);
I don't get the post-construction specific to Windows6, but only
those to Window.
> The post-constructor run
> for Window1 is the same as for Window6; the post-constructor of
> the base_window, right?
Wrong. The post constructr run for Window6 is the Window6 post
constructor (which of course calls the Base post constructor).
> BTW, even if the difference is true one
> could overload WindowConnection::WindowConnection().
How do you overload a constructor without changing the class
it is a constructor of? (Note that the base class + window
connection class will likely be in a library, and the user
of the library derives different windows!)
With your template suggestion above, this is easily solved by
having the template class just call the post constructor virtual
function of the newly created class.
So maybe the correct solution is to solve problems a and b
from above (so the template solution actually works).
---
[ 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://www.research.att.com/~austern/csc/faq.html ]
Author: Yannick de Kercadio <kercadio@limsi.fr>
Date: Thu, 31 May 2001 19:32:22 GMT Raw View
Christopher Eltschka wrote:
>
> It again has the problem that you can forget to do the second
> thing: You can write
>
> MyWindow foo;
>
> without writing
>
> WindowConnection bar(foo)
>
> after it. So it's not yet better than having to call
>
> foo->connect()
>
> after construction. The intention is that after
>
> MyWindow foo;
>
> the window _automatically_ gets connected.
>
You're right: I did not solve the problem. Sorry for the noise.
--
Yannick de Kercadio
kercadio@limsi.fr
---
[ 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://www.research.att.com/~austern/csc/faq.html ]
Author: Michiel Salters<Michiel.Salters@cmg.nl>
Date: Thu, 31 May 2001 19:32:35 GMT Raw View
In article <3B153C6E.4448D2E4@dollywood.itp.tuwien.ac.at>, Christopher Eltschka
says...
[ Arguing for post-constructors ]
>It again has the problem that you can forget to do the second
>thing: You can write
>
> MyWindow foo;
>
>without writing
>
> WindowConnection bar(foo)
>
>after it. So it's not yet better than having to call
>
> foo->connect()
>
>after construction. The intention is that after
>
> MyWindow foo;
>
>the window _automatically_ gets connected.
A solution to that would be to add a template class
Connect<T>: public T, which would be the only class able to
create classes derived from base_window. You would then have
to write Connect<MyWindow> foo. The ctor for Connect runs
after the ctor for MyWindow, solving the order problem.
It also makes it clear that the act of connecting is not
performed by MyWindow.
>Moreover, if you want to add to the "post-constructor" (i.e.
>the constructor of WindowConnection), you get the problem
>to remember to construct a WindowConnection for Window1,
>Window2 and Window3, to construct a Window4Connection for
>Window4 and Window5 (which is derived from Window4) and
>a Window6Connection for Window6. This is even more error-prone
>than to just remember calling foo->connect().
Why would you need to remember that ? The post-constructor run
for Window1 is the same as for Window6; the post-constructor of
the base_window, right? BTW, even if the difference is true one
could overload WindowConnection::WindowConnection().
--
Michiel Salters
Consultant Technical Software Engineering
CMG Trade, Transport & Industry
Michiel.Salters@cmg.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://www.research.att.com/~austern/csc/faq.html ]
Author: Michiel Salters<Michiel.Salters@cmg.nl>
Date: Fri, 1 Jun 2001 16:51:21 GMT Raw View
In article <3B1679BE.9575059C@dollywood.itp.tuwien.ac.at>, Christopher Eltschka
says...
>
>Michiel Salters wrote:
>>
>> In article <3B153C6E.4448D2E4@dollywood.itp.tuwien.ac.at>, Christopher Eltschka
>> says...
>>
>> [ Arguing for post-constructors ]
>> A solution to that would be to add a template class
>> Connect<T>: public T, which would be the only class able to
>> create classes derived from base_window. You would then have
>> to write Connect<MyWindow> foo. The ctor for Connect runs
>> after the ctor for MyWindow, solving the order problem.
>> It also makes it clear that the act of connecting is not
>> performed by MyWindow.
>
>This has several problems:
>
>a) Forwarding arguments to the class constructor (note that
> for each derived class the constructor argument list can be
> different, and especially is not predictable).
>
>b) How do you specify in a base class that it's derived
> classes(!) may not be created directly, but only by
> the Connect<T> object?
>
>However, this is the best approximation I've yet seen.
>So maybe solving problems a and b would be a better solution
>than introducing post-constructors.
For (a) we'd probably need a set of template constructors:
template <typename Window, typename T1>
Connect::Connect(T1 t1) : Window(t1) ...
template <typename Window, typename T1, typename T2>
Connect::Connect(T1 t1, T2 t2) : Window(t1, t2) ...
This limits the maximum number of arguments, but I don't think
a limit of 16 is likely to be exceeded.
For (b) I'm thinking about a helper class, which is a virtual
base class of our logical base class. It befriends Connect<T>,
which allows Connect<T> to use the private ctor for base class.
As a result you can't create Window but you can create
Connect<Window>.
The problem with this solution of (b) is the nasty user providing
template<> Connect<Window>. But since we're protecting against
Murphy, not Machiavelli, so I'm going to call this a feature.
"By default it does what the base class author intended, but it is
configurable".
Comments welcome.
Regards,
Michiel Salters
--
Michiel Salters
Consultant Technical Software Engineering
CMG Trade, Transport & Industry
Michiel.Salters@cmg.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://www.research.att.com/~austern/csc/faq.html ]
Author: Yannick de Kercadio <kercadio@limsi.fr>
Date: Wed, 30 May 2001 17:45:23 GMT Raw View
Thomas A. Horsley wrote:
>
> You seem to have the impression that the post constructor for D1 will
> be called immediately following the constructor to D1. That would indeed
> be pointless, but that isn't the idea.
>
> The idea is that post constructors, no matter which class they are defined
> in, no matter where they are in the heirarchy don't get called until *the
> whole* heirarchy is constructed. Every single constructor for every single
> class has finished running before the first post constructor is called. They
> don't impose any special requirements on any class anywhere in the
> heirarchy (any more than any other function that calls virtual functions
> imposes).
I don't understand the situation you're pointing at. I see two cases.
First case: I'm wrapping a handle which is a number returned by an
external agent (e.g., the operating system), and I am providing some
methods (or static functions + this pointer) to this agent as callbacks.
If such a callback is called by the agent before the hierarchy is
entirely constructed, the behaviour is undefined.
Second case: I have to call a virtual method in the constructor, and I
would like the implementation of the most-derived class to be called,
and not the one of the currently under construction class. For instance,
an object that automatically displays itself at construction, the Draw
method of which is virtual.
In both cases, the behaviour of the object during its initialization
depends on the actual class hierachy, and some base class needs to use
the full object, and not the object of its class.
Well. Thats bad! ;-)
It means that two classes were collapsed into a single one.
In the first case, there should be an "everything but the income link to
the external environment (callbacks)" class, and a "link that object to
the environment" class, accepting as an argument of its constructor a
reference to an object of the previous class (or a class derived from
it).
class Window { ... };
class WindowConnection { WindowConnection(Window &w) {
connect_callback(&w); } };
class MyWindow : public Window { ... };
MyWindow foo;
WindowConnection bar(foo);
The post-constructor is simply the constructor of WindowConnection.
In the second case, which is very similar, there would be a
GraphicalObject, and an AutoDisplayObject, constructing itself accepting
a reference to a GraphicalObject. And a Circle would of course derive
form GraphicalObject...
Does that fit your needs, or is there an entirely different third case?
--
Yannick de Kercadio
kercadio@limsi.fr
---
[ 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://www.research.att.com/~austern/csc/faq.html ]
Author: Christopher Eltschka <celtschk@dollywood.itp.tuwien.ac.at>
Date: Wed, 30 May 2001 18:44:01 GMT Raw View
"Andrew F. Vesper" wrote:
>
> Christopher Eltschka wrote:
>
> > Post-constructors are needed because some objects should be
> > automatically connected with the environment (entered in
> > registries, f.ex.), but _not_ before they are completely
> > constructed. If auomatic connection is done in the constructor,
> > it's done too early. If connection is done with an explicit
> > member call (i.e. not automatic), then it's error prone
> > (you may forget it).
>
> What about post-post-constructors -- just in case some objects
> should be automatically connected to a low level environment,
> and then need to be connected to a high level environment.
Not needed. Since in post-constructors, the object is already
fully constructed, you can just use the usual pattern
class X
{
public:
X(...);
+X() // post-constructor
{
low_level_connect();
high_level_connect();
}
protected:
virtual void low_level_connect();
virtual void high_level_connect();
};
Derived classes can then override low_level_connect
and/or high_level_connect.
>
> And how about post-post-post constructors?
Not needed either.
---
[ 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://www.research.att.com/~austern/csc/faq.html ]
Author: Christopher Eltschka <celtschk@dollywood.itp.tuwien.ac.at>
Date: Wed, 30 May 2001 19:09:45 GMT Raw View
Yannick de Kercadio wrote:
>
> Thomas A. Horsley wrote:
> >
> > You seem to have the impression that the post constructor for D1 will
> > be called immediately following the constructor to D1. That would indeed
> > be pointless, but that isn't the idea.
> >
> > The idea is that post constructors, no matter which class they are defined
> > in, no matter where they are in the heirarchy don't get called until *the
> > whole* heirarchy is constructed. Every single constructor for every single
> > class has finished running before the first post constructor is called. They
> > don't impose any special requirements on any class anywhere in the
> > heirarchy (any more than any other function that calls virtual functions
> > imposes).
>
> I don't understand the situation you're pointing at. I see two cases.
>
> First case: I'm wrapping a handle which is a number returned by an
> external agent (e.g., the operating system), and I am providing some
> methods (or static functions + this pointer) to this agent as callbacks.
> If such a callback is called by the agent before the hierarchy is
> entirely constructed, the behaviour is undefined.
>
> Second case: I have to call a virtual method in the constructor, and I
> would like the implementation of the most-derived class to be called,
> and not the one of the currently under construction class. For instance,
> an object that automatically displays itself at construction, the Draw
> method of which is virtual.
>
> In both cases, the behaviour of the object during its initialization
> depends on the actual class hierachy, and some base class needs to use
> the full object, and not the object of its class.
No, in both cases, the action you describe is _not_ part of it's
initialization, but part of it's connection (to thr agent, to the
display). Of course, the object you want to connect is the object
you just constructed.
>
> Well. Thats bad! ;-)
>
> It means that two classes were collapsed into a single one.
No.
>
> In the first case, there should be an "everything but the income link to
> the external environment (callbacks)" class, and a "link that object to
> the environment" class, accepting as an argument of its constructor a
> reference to an object of the previous class (or a class derived from
> it).
The "link that object to the environment" is an action, not an
object. Of course, it _can_ be modeled as a class (as can other
actions - see strategy pattern), but you wouldn't say that classes
shouldn't have member functions, because you can make classes
out of all of them, would you?
>
> class Window { ... };
> class WindowConnection { WindowConnection(Window &w) {
> connect_callback(&w); } };
> class MyWindow : public Window { ... };
>
> MyWindow foo;
> WindowConnection bar(foo);
>
> The post-constructor is simply the constructor of WindowConnection.
>
> In the second case, which is very similar, there would be a
> GraphicalObject, and an AutoDisplayObject, constructing itself accepting
> a reference to a GraphicalObject. And a Circle would of course derive
> form GraphicalObject...
>
> Does that fit your needs, or is there an entirely different third case?
It again has the problem that you can forget to do the second
thing: You can write
MyWindow foo;
without writing
WindowConnection bar(foo)
after it. So it's not yet better than having to call
foo->connect()
after construction. The intention is that after
MyWindow foo;
the window _automatically_ gets connected.
Moreover, if you want to add to the "post-constructor" (i.e.
the constructor of WindowConnection), you get the problem
to remember to construct a WindowConnection for Window1,
Window2 and Window3, to construct a Window4Connection for
Window4 and Window5 (which is derived from Window4) and
a Window6Connection for Window6. This is even more error-prone
than to just remember calling foo->connect().
---
[ 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://www.research.att.com/~austern/csc/faq.html ]
Author: Michiel Salters<Michiel.Salters@cmg.nl>
Date: Mon, 28 May 2001 22:59:00 GMT Raw View
In article <3B0AD9D5.C3430777@dollywood.itp.tuwien.ac.at>, Christopher Eltschka
says...
>
>Michiel Salters wrote:
>>
>> In article <9eaflh$1ntmk$1@ID-14036.news.dfncis.de>, Andrei Alexandrescu says...
>> >
>> >"Michiel Salters" <Michiel.Salters@cmg.nl> wrote in message
>>
>> >> >I've got two on my list:
>> >> >
>> >> > 1. "post constructors" - a new kind of constructor that gets called
>> >> > following the final constructor for the whole object. Virtual
>> >> > functions would work as expected in the post constructors and you
>> >> > wouldn't have to remember to use whatever convention you've adopted
>> >to
>> >> > get aound not having post constructors.
>> >>
>> >> I believe Valentin Bonnard once pointed out that this area contains
>> >> the largest number of features which could be trivially added, namely
>> >> post-constructros, post-post-constructors, post-post-post-constructors,
>> >> etc.
>> >
>> >But that's wrong. The request is legit and does not go ad infinitum. It's
>> >about invoking a virtual function after the full object was created. There's
>> >not going to be a supplemental need after that.
>> >
>> >Andrei
>>
>> I'm not sure. Why are post-constructors needed? Because the object wasn't
>> finished after the (most-derived) constructors have run.
>
>Wrong. Did you read my posting about that subject?
>Post-constructors are needed because some objects should be
>automatically connected with the environment (entered in
>registries, f.ex.), but _not_ before they are completely
>constructed. If auomatic connection is done in the constructor,
>it's done too early. If connection is done with an explicit
>member call (i.e. not automatic), then it's error prone
>(you may forget it).
Ok. I see linking with the environment as part of the construction,
but I can reasons to separate them. I still disagree with your setup,
though. How does a base class know if/when a derived class fits
into a registry? I think that decision is up to the/a derived class.
>> Is it finished
>> when the (most-derived) post-constructors have run?
>
> Construction has finished when the (most-derived) constructor has
> finished. Connecting has finished when the (most-derived)
> post-constructor has finished.
> Disconnecting has finished when the (last) pre-destructor finished.
> Destruction has finished when the last destructor has finished.
Ok, that would make sense. Defining exactly what "connecting" means
is something else.
>> About the need to invoke a virtual function: when we have a deep hierarchy,
>> should the base be able to call all virtual functions that become available?
>
>Of course: When the post-constructor runs, the object is completely
>constructed, therefore it should behave like a completely destructed
>object.
>> I.e
>> class B {
>> virtual void f();
>> };
>> class D1 : B {
>> virtual void f();
>> }
>> class D2 : D1 {
>> virtual void f();
>> }
>>
>> Should B have the ability to call D1::f() virtually after D1::D1 has
>> run, but before D2::D2 runs?
>
>How could it? D1::f() gets available *after* B's constructor runs,
>but gets replaced by D2::f() *before* any post-constructor runs.
Now you say two different things, or I don't understand you. D1::f() becomes
"available" after D1::D1 runs. The author of B might think
he can call it. D2::f() would stop that. (If e.g. B and D1 are written
by the same author.)
The result of this would be that a base class author would define an
interface that all derived classes must adhere to, because the registry
could call those methods. And the derived class must establish this
interface, although *its* post-constructor hasn't run yet. On destruction
the same applies.
The derived class thus can be called from three different phases of
construction: pre-connecting, connected, and disconnected. As a result,
a derived class might need to provide three different interfaces in
three different states, instead of the single interface established by
the constructor finishing.
Which in turn might lead to the need to call the derived class after
it has "connected" to *its* environment. Voila, post-post-constructors.
>> I personally don't think there is anything
>> special with the most derived class that warrants giving it privileges
>> here.
>
>There are no privileges.
>It's just that after each construction of an object the compiler
>inserts an automatic call to the post-constructor of the object
>(i.e. the same thing which currently is sometimes done with init
>functions, except that it's automatically inserted by the compiler,
>instead of manually by the user, and also in situations where
>the user could not do it, like at the definition of global variables,
>and it may include automatic calls to base post-constructors, similar
>to constructor logic).
That still leaves the derived class the privilege of determining what
interface the base class post-constructor sees. For an init-method
that doesn't apply, because in that case the user explicitly invokes
MostDerived::init(). If the user wanted Intermediate::init, he could
write that.
>> This scheme is fragile if B assumes it calls Dn, and somebody
>> derives Dn+1 from Dn.
>
>Since
>
>D2 d; d.post_construct();
>
>isn't fragile, the post-constructor cannot be fragile, since it's
>basically the same, only automatic (you cannot forget it).
Actually, that is different because D2::post_construct is called
before Base::post_construct. Normal post-constructors are called
in the same order as constructors, right?
>> So you would have to mandate that D[latest]
>> provides a proper f().
>
>Why? If the most derivde class doesn't provide an f(), the
>inherited f() is used, just as with any other virtual function.
>Remember: *The* *object* *is* *already* *completely* *constructed*.
>This sentence cannot be emphasized too much.
Hmmm. *The* *object* *isn't* *fully* *connected* *yet*. There must be
a last step before an object is turned over to a user. Tacking on a
post-constructor step after the normal constructor step does not take
away the ability of a derived class to have the last say - it has a
post-constructor too. And that remains, no matter how many steps are
added.
>> But if you start imposing requirements on the
>> most derived class, why not impose the requirement that it calls f()?
>> I don't think one requirement is more likely to be forgotten than the
>> other.
>
>There are no requirements on the most-derived class.
Oh yes there are. Unlike the base class, it must be fully operational
(virtual functions can be called etc.) after its constructor has run,
but before its post-constructor has run. And exactly because of that
requirement on the most-derived constructor, I think it is easier to
demand (in documentation) that it calls f(), when it enters a state in
which it can call f(). That leaves the decision when the most derived
class supports a call to f() right where it belongs - with the most
derived class.
Regards,
Michiel Salters
--
Michiel Salters
Consultant Technical Software Engineering
CMG Trade, Transport & Industry
Michiel.Salters@cmg.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://www.research.att.com/~austern/csc/faq.html ]
Author: brangdon@cix.co.uk (Dave Harris)
Date: Thu, 24 May 2001 21:20:30 GMT Raw View
andy.vesper@acm.org (Andrew F. Vesper) wrote (abridged):
> What about post-post-constructors -- just in case some objects
> should be automatically connected to a low level environment,
> and then need to be connected to a high level environment.
>
> And how about post-post-post constructors?
Sure, why not? And why not generalise it to other methods rather than
just constructors.
CLOS has "method-combinators" for doing this kind of thing. When
declaring an overriding method one can specify it gets executed "before"
or "after" other overrides. Multiple "before" methods get executed in
some natural order. There are also "around" methods and probably some
others I forget. Apparently they help enormously when writing mix-in
classes. As their name suggests, they make it easier to combine methods,
especially orthogonal methods that don't know about each other.
I've never needed this myself in C++, and I think it goes beyond the kind
of language changes the next standard should include. Still, the idea
itself is reasonable. I recommend you look at how it works in the other
languages that have it.
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://www.research.att.com/~austern/csc/faq.html ]
Author: "Andrew F. Vesper" <andy.vesper@acm.org>
Date: Thu, 24 May 2001 01:38:19 GMT Raw View
Christopher Eltschka wrote:
> Post-constructors are needed because some objects should be
> automatically connected with the environment (entered in
> registries, f.ex.), but _not_ before they are completely
> constructed. If auomatic connection is done in the constructor,
> it's done too early. If connection is done with an explicit
> member call (i.e. not automatic), then it's error prone
> (you may forget it).
What about post-post-constructors -- just in case some objects
should be automatically connected to a low level environment,
and then need to be connected to a high level environment.
And how about post-post-post constructors?
--
Andy V (OpenGL Alpha Geek)
"In order to make progress, one must leave the door to the unknown ajar."
Richard P. Feynman, quoted by Jagdish Mehra in _The Beat of a Different Drum_.
---
[ 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://www.research.att.com/~austern/csc/faq.html ]
Author: "Andrei Alexandrescu" <andrewalex@hotmail.com>
Date: Thu, 24 May 2001 12:42:50 GMT Raw View
"Andrew F. Vesper" <andy.vesper@acm.org> wrote in message
news:3B0C5D9F.E0A6E170@acm.org...
> What about post-post-constructors -- just in case some objects
> should be automatically connected to a low level environment,
> and then need to be connected to a high level environment.
>
> And how about post-post-post constructors?
I repeat, this argument is hogwash. Post-constructors and pre-destructors
are all about invoking ONE function after construction and ONE function
before destruction. There's no need, express or implied, for infinite levels
of post-construction (or pre-destruction).
Andrei
--
Check out THE C++ Seminar: 3 Days with 5 Experts
http://www.gotw.ca/cpp_seminar
---
[ 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://www.research.att.com/~austern/csc/faq.html ]
Author: Michiel Salters<Michiel.Salters@cmg.nl>
Date: Tue, 22 May 2001 20:30:17 GMT Raw View
In article <9eaflh$1ntmk$1@ID-14036.news.dfncis.de>, Andrei Alexandrescu says...
>
>"Michiel Salters" <Michiel.Salters@cmg.nl> wrote in message
>> >I've got two on my list:
>> >
>> > 1. "post constructors" - a new kind of constructor that gets called
>> > following the final constructor for the whole object. Virtual
>> > functions would work as expected in the post constructors and you
>> > wouldn't have to remember to use whatever convention you've adopted
>to
>> > get aound not having post constructors.
>>
>> I believe Valentin Bonnard once pointed out that this area contains
>> the largest number of features which could be trivially added, namely
>> post-constructros, post-post-constructors, post-post-post-constructors,
>> etc.
>
>But that's wrong. The request is legit and does not go ad infinitum. It's
>about invoking a virtual function after the full object was created. There's
>not going to be a supplemental need after that.
>
>Andrei
I'm not sure. Why are post-constructors needed? Because the object wasn't
finished after the (most-derived) constructors have run. Is it finished
when the (most-derived) post-constructors have run?
About the need to invoke a virtual function: when we have a deep hierarchy,
should the base be able to call all virtual functions that become available?
I.e
class B {
virtual void f();
};
class D1 : B {
virtual void f();
}
class D2 : D1 {
virtual void f();
}
Should B have the ability to call D1::f() virtually after D1::D1 has
run, but before D2::D2 runs? I personally don't think there is anything
special with the most derived class that warrants giving it privileges
here. This scheme is fragile if B assumes it calls Dn, and somebody
derives Dn+1 from Dn. So you would have to mandate that D[latest]
provides a proper f(). But if you start imposing requirements on the
most derived class, why not impose the requirement that it calls f()?
I don't think one requirement is more likely to be forgotten than the
other.
Regards,
Michiel Salters
--
Michiel Salters
Consultant Technical Software Engineering
CMG Trade, Transport & Industry
Michiel.Salters@cmg.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://www.research.att.com/~austern/csc/faq.html ]
Author: Christopher Eltschka <celtschk@dollywood.itp.tuwien.ac.at>
Date: Tue, 22 May 2001 21:31:53 GMT Raw View
Michiel Salters wrote:
>
> In article <9eaflh$1ntmk$1@ID-14036.news.dfncis.de>, Andrei Alexandrescu says...
> >
> >"Michiel Salters" <Michiel.Salters@cmg.nl> wrote in message
>
> >> >I've got two on my list:
> >> >
> >> > 1. "post constructors" - a new kind of constructor that gets called
> >> > following the final constructor for the whole object. Virtual
> >> > functions would work as expected in the post constructors and you
> >> > wouldn't have to remember to use whatever convention you've adopted
> >to
> >> > get aound not having post constructors.
> >>
> >> I believe Valentin Bonnard once pointed out that this area contains
> >> the largest number of features which could be trivially added, namely
> >> post-constructros, post-post-constructors, post-post-post-constructors,
> >> etc.
> >
> >But that's wrong. The request is legit and does not go ad infinitum. It's
> >about invoking a virtual function after the full object was created. There's
> >not going to be a supplemental need after that.
> >
> >Andrei
>
> I'm not sure. Why are post-constructors needed? Because the object wasn't
> finished after the (most-derived) constructors have run.
Wrong. Did you read my posting about that subject?
Post-constructors are needed because some objects should be
automatically connected with the environment (entered in
registries, f.ex.), but _not_ before they are completely
constructed. If auomatic connection is done in the constructor,
it's done too early. If connection is done with an explicit
member call (i.e. not automatic), then it's error prone
(you may forget it).
> Is it finished
> when the (most-derived) post-constructors have run?
Construction has finished when the (most-derived) constructor has
finished.
Connecting has finished when the (most-derived) post-constructor has
finished.
Disconnecting has finished when the (last) pre-destructor finished.
Destruction has finished when the last destructor has finished.
>
> About the need to invoke a virtual function: when we have a deep hierarchy,
> should the base be able to call all virtual functions that become available?
Of course: When the post-constructor runs, the object is completely
constructed, therefore it should behave like a completely destructed
object.
>
> I.e
> class B {
> virtual void f();
> };
> class D1 : B {
> virtual void f();
> }
> class D2 : D1 {
> virtual void f();
> }
>
> Should B have the ability to call D1::f() virtually after D1::D1 has
> run, but before D2::D2 runs?
How could it? D1::f() gets available *after* B's constructor runs,
but gets replaced by D2::f() *before* any post-constructor runs.
> I personally don't think there is anything
> special with the most derived class that warrants giving it privileges
> here.
There are no privileges.
It's just that after each construction of an object the compiler
inserts an automatic call to the post-constructor of the object
(i.e. the same thing which currently is sometimes done with init
functions, except that it's automatically inserted by the compiler,
instead of manually by the user, and also in situations where
the user could not do it, like at the definition of global variables,
and it may include automatic calls to base post-constructors, similar
to constructor logic).
> This scheme is fragile if B assumes it calls Dn, and somebody
> derives Dn+1 from Dn.
Since
D2 d; d.post_construct();
isn't fragile, the post-constructor cannot be fragile, since it's
basically the same, only automatic (you cannot forget it).
> So you would have to mandate that D[latest]
> provides a proper f().
Why? If the most derivde class doesn't provide an f(), the
inherited f() is used, just as with any other virtual function.
Remember: *The* *object* *is* *already* *completely* *constructed*.
This sentence cannot be emphasized too much.
> But if you start imposing requirements on the
> most derived class, why not impose the requirement that it calls f()?
There are no requirements on the most-derived class.
> I don't think one requirement is more likely to be forgotten than the
> other.
There's no requirement therefore there's nothing to forget.
---
[ 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://www.research.att.com/~austern/csc/faq.html ]
Author: "Andrei Alexandrescu" <andrewalex@hotmail.com>
Date: Tue, 22 May 2001 23:02:39 GMT Raw View
"Michiel Salters" <Michiel.Salters@cmg.nl> wrote in message
> In article <9eaflh$1ntmk$1@ID-14036.news.dfncis.de>, Andrei Alexandrescu
says...
> >But that's wrong. The request is legit and does not go ad infinitum. It's
> >about invoking a virtual function after the full object was created.
There's
> >not going to be a supplemental need after that.
>
> I'm not sure. Why are post-constructors needed? Because the object wasn't
> finished after the (most-derived) constructors have run. Is it finished
> when the (most-derived) post-constructors have run?
The object is completely constructed *before* the post-constructor is
invoked. By definition. That's because of the meaning of "post" :o).
> About the need to invoke a virtual function: when we have a deep
hierarchy,
> should the base be able to call all virtual functions that become
available?
It's much simpler than you say. Basically post-constructors imply calling
this->virtual_fn right after fully constructing an object. It's that simple,
there is nothing fragile or anything like that.
I found post-constructors and pre-destructors useful in connecting observers
and subjects (ha what a pain without'em) and in starting and stopping
threads. Cristopher meant object registration, and I can imagine that's
another realistic case.
By the way, in Java constructors are a kind of post-constructors - after the
object has been zero-initialized :o).
Personally I consider the absence of post-constructors and pre-destructors a
minor annoyance and I can live without'em. I just wanted to point out that
the argument that they don't make conceptual sense and that they go ad
infinitum, is complete bogus.
Andrei
---
[ 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://www.research.att.com/~austern/csc/faq.html ]
Author: Tom.Horsley@worldnet.att.net (Thomas A. Horsley)
Date: Wed, 23 May 2001 09:31:51 GMT Raw View
>Should B have the ability to call D1::f() virtually after D1::D1 has
>run, but before D2::D2 runs?
You seem to have the impression that the post constructor for D1 will
be called immediately following the constructor to D1. That would indeed
be pointless, but that isn't the idea.
The idea is that post constructors, no matter which class they are defined
in, no matter where they are in the heirarchy don't get called until *the
whole* heirarchy is constructed. Every single constructor for every single
class has finished running before the first post constructor is called. They
don't impose any special requirements on any class anywhere in the
heirarchy (any more than any other function that calls virtual functions
imposes).
--
>>==>> The *Best* political site <URL:http://www.vote-smart.org/> >>==+
email: Tom.Horsley@worldnet.att.net icbm: Delray Beach, FL |
<URL:http://home.att.net/~Tom.Horsley> Free Software and Politics <<==+
---
[ 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://www.research.att.com/~austern/csc/faq.html ]
Author: "Andrei Alexandrescu" <andrewalex@hotmail.com>
Date: Mon, 21 May 2001 18:42:30 GMT Raw View
"Michiel Salters" <Michiel.Salters@cmg.nl> wrote in message
news:OsvJ6.4244$vg1.327313@www.newsranger.com...
> In article <ur8y2tae0.fsf@worldnet.att.net>, Thomas A. Horsley says...
> >
> >I've got two on my list:
> >
> > 1. "post constructors" - a new kind of constructor that gets called
> > following the final constructor for the whole object. Virtual
> > functions would work as expected in the post constructors and you
> > wouldn't have to remember to use whatever convention you've adopted
to
> > get aound not having post constructors.
>
> I believe Valentin Bonnard once pointed out that this area contains
> the largest number of features which could be trivially added, namely
> post-constructros, post-post-constructors, post-post-post-constructors,
> etc.
But that's wrong. The request is legit and does not go ad infinitum. It's
about invoking a virtual function after the full object was created. There's
not going to be a supplemental need after that.
Andrei
---
[ 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://www.research.att.com/~austern/csc/faq.html ]
Author: "Tomas Rylek" <rylek@volny.cz>
Date: Sat, 12 May 2001 20:18:01 GMT Raw View
Andr P nitz <poenitz@htwm.de>:
> What about a feature that makes ordinary member functions behave similarly
> to constructors, i.e. run all equally named functions in the object's
> bases in the same order as the constructors?
>
> Given this feature, a "post constructor" in the most derived object could
> be implemented in this object's constructor as a call to such a function.
>
> I think this is more general.
>
> Andre'
I don't think so. In fact the main reason why some people here are
suggesting
post-construction / pre-destruction logic is that, upon object declaration
you
don't know 'yet' whether this is the final object or just a base for a class
you
or someone else will implement a year later. Still, in certains situations
you need
some work to be done after the whole object has been constructed (all
virtual
table pointers correctly updated to point to those of the object being
instantiated
etc.). Another thing which might actually speak for the 'post-constructors'
is that
when an exception is thrown out of one, all the destructors can be safely
called
(though perhaps not the pre-destructor so that the post-construction
/ pre-destruction matches constructor / destructor pairing). So the
post-constructor
might be a more handy place to implement 'fatter' construction logic than
an ordinary constructor.
If we didn't care about constructor arguments, the post-construction
/ pre-destruction logic could be carried out by a template:
template <class T>
class FinalClassLogic : public T
{
public:
FinalClassLogic() { T::PostConstruct(); }
~FinalClassLogic() { T::PreDestruct(); }
};
However, this approach has 3 main disadvantages:
1/ Is is more error-prone because you have to remember that you have to
declare some object indirectly via the above template, like:
FinalClassLogic<AClass> variable;
instead of simple
AClass variable;
2/ You cannot generally pass parameters to constructors in this way.
3/ Either you have to equip all classes with the 'final object logic'
with both PostConstruct and PreDestruct, or three versions of the
template are necessary to cover all the possible combinations.
Regards
Tomas Rylek
---
[ 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://www.research.att.com/~austern/csc/faq.html ]
Author: Tom.Horsley@worldnet.att.net (Thomas A. Horsley)
Date: Thu, 10 May 2001 06:24:25 GMT Raw View
>IMHO a post-constructor should act just like a normal member function,
>except that it is called automatically after construction. Therefore
>the post-constructor of the most-derived clas is called, and if base
>versions exist which should be called, it's the derived function's
>job to do this.
I gotta disagree here. The main reason I want post constructors is so stuff
that needs to happen following construction of the full object can *always*
happen and there isn't any way to accidentally forget to make it happen. I
think *all* post constructors should be called in the same order the
constructors were called (just to pick the simplest definition to remember).
This is much like virtual destructors - they all get called so each derived
class can clean up its own mess. Post constructors should be the same way.
On the other hand, I haven't formulated an opinion on arguments :-). I
always sort of envisioned them having no arguments, but I can see some
appeal for having matching constructor args (on the gripping hand, that
might just mean you are forced to define 10 separate post constructors to go
with your 10 constructors even though they all do the same thing - no
arguments might be better after all). Of course there is always the
idea of introducing weird syntax to provide two separate arg lists
at the point the object is constructed - one goes to the constructor,
and the other to the post constructor, but its probably better not to
venture down that path :-).
--
>>==>> The *Best* political site <URL:http://www.vote-smart.org/> >>==+
email: Tom.Horsley@worldnet.att.net icbm: Delray Beach, FL |
<URL:http://home.att.net/~Tom.Horsley> Free Software and Politics <<==+
---
[ 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://www.research.att.com/~austern/csc/faq.html ]
Author: Christopher Eltschka <celtschk@dollywood.itp.tuwien.ac.at>
Date: Thu, 10 May 2001 17:28:18 GMT Raw View
"Thomas A. Horsley" wrote:
>
> >IMHO a post-constructor should act just like a normal member function,
> >except that it is called automatically after construction. Therefore
> >the post-constructor of the most-derived clas is called, and if base
> >versions exist which should be called, it's the derived function's
> >job to do this.
>
> I gotta disagree here. The main reason I want post constructors is so stuff
> that needs to happen following construction of the full object can *always*
> happen and there isn't any way to accidentally forget to make it happen. I
> think *all* post constructors should be called in the same order the
> constructors were called (just to pick the simplest definition to remember).
This might get problematic if you allow arguments: You have to
specify which ones to call (or should the compiler remember which
constructors it called, and then call the appropriate
post-constructors?)
>
> This is much like virtual destructors - they all get called so each derived
> class can clean up its own mess. Post constructors should be the same way.
>
> On the other hand, I haven't formulated an opinion on arguments :-). I
> always sort of envisioned them having no arguments, but I can see some
> appeal for having matching constructor args (on the gripping hand, that
> might just mean you are forced to define 10 separate post constructors to go
> with your 10 constructors even though they all do the same thing - no
> arguments might be better after all). Of course there is always the
> idea of introducing weird syntax to provide two separate arg lists
> at the point the object is constructed - one goes to the constructor,
> and the other to the post constructor, but its probably better not to
> venture down that path :-).
Another option would be to make a special rule, that the
post-constructor with the longest initial sequence of parameters
of hte constructor is chosen. Then you could have
class X
{
X();
X(int);
X(double);
X(int, double);
X(double, int);
// made-up syntax for post-constructor:
+X();
+X(int);
+X(double, int);
};
X x1; // calls +X()
X x2(5); // calls +X(int)
X x3(5.0); // calls +X() because no +X(double) exists.
X x4(2, 1.2); // calls +X(int)
// (no +X(int, double), but (int) is longer than ())
X x5(1.2, 2); // calls +X(double, int);
If no suitable post-constructor is available, one has two options:
- Either just call none
- Or do it similar to constructors: Generate an error if no suitable
post-constructor exists, but implicitly define a trivial
post-constructor if no explicit definition is given. The trivial
post-constructor takes no arguments and does nothing, so the
error doesn't occur for classes which don't define *any*
post-constructors.
Both solutions are compatible with current C++ (which doesn't have
post-constructors, which is the same as having trivial
post-constructors). Note that with the "initial match" rule above,
the trivial post-constructor works for all constructors.
The second solution would catch more errors.
According to the syntax: I like +X() for post-constructor
("Add to environment") and -X() for pre-destructor ("Remove
[subtract] from environment"). Also, it's in line with the
pseudo-operator notation of the destructor ~X().
---
[ 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://www.research.att.com/~austern/csc/faq.html ]
Author: =?iso-8859-1?Q?Andr=E9_P=F6nitz?= <poenitz@htwm.de>
Date: Thu, 10 May 2001 17:29:06 GMT Raw View
Thomas A. Horsley <Tom.Horsley@worldnet.att.net> wrote:
>>IMHO a post-constructor should act just like a normal member function,
>>except that it is called automatically after construction. Therefore
>>the post-constructor of the most-derived clas is called, and if base
>>versions exist which should be called, it's the derived function's
>>job to do this.
>=20
> I gotta disagree here. The main reason I want post constructors is so s=
tuff
> that needs to happen following construction of the full object can *alw=
ays*
> happen and there isn't any way to accidentally forget to make it happen=
. I
> think *all* post constructors should be called in the same order the
> constructors were called (just to pick the simplest definition to remem=
ber).
What about a feature that makes ordinary member functions behave similarl=
y
to constructors, i.e. run all equally named functions in the object's
bases in the same order as the constructors?
Given this feature, a "post constructor" in the most derived object could
be implemented in this object's constructor as a call to such a function.
I think this is more general.
Andre'
--=20
Andr=E9 P=F6nitz ............................................. poenitz@ht=
wm.de
---
[ 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://www.research.att.com/~austern/csc/faq.html ]
Author: "Sebastian Moleski" <smoleski@surakware.com>
Date: Thu, 10 May 2001 17:29:56 GMT Raw View
"Thomas A. Horsley":
> I've got two on my list:
>
> 1. "post constructors" - a new kind of constructor that gets called
> following the final constructor for the whole object. Virtual
> functions would work as expected in the post constructors and you
> wouldn't have to remember to use whatever convention you've adopted
to
> get aound not having post constructors.
I'd like to see that, too. Borland has implemented something like that in
Object Pascal. They have two virtual functions taking no arguments called
AfterConstruction and BeforeDestruction, which are automatically called
right after construction and right before destruction. Since they are
virtual, you can override them whereever you need them.
sm
---
[ 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://www.research.att.com/~austern/csc/faq.html ]
Author: "Anthony Williams" <anthwil@nortelnetworks.com>
Date: Wed, 9 May 2001 12:20:26 GMT Raw View
"Christopher Eltschka" <celtschk@dollywood.itp.tuwien.ac.at> wrote in
message news:3AF7C2AD.EDFF77EA@dollywood.itp.tuwien.ac.at...
> Michiel Salters wrote:
> >
> > In article <ur8y2tae0.fsf@worldnet.att.net>, Thomas A. Horsley says...
> > >
> > >I've got two on my list:
> > >
> > > 1. "post constructors" - a new kind of constructor that gets called
> > > following the final constructor for the whole object. Virtual
> > > functions would work as expected in the post constructors and you
> > > wouldn't have to remember to use whatever convention you've
adopted to
> > > get aound not having post constructors.
> >
> > I believe Valentin Bonnard once pointed out that this area contains
> > the largest number of features which could be trivially added, namely
> > post-constructros, post-post-constructors, post-post-post-constructors,
> > etc. In general, when two classed are related by inheritance, there must
> > be a single class who gets the last word as to whether the full object
> > is created. By design, in C++ that is the constructor of the derived
> > class.
>
> As I see post constructors, the object would still be fully constructed
> after the most derived constructor finishes. The post-constructor would
> run on the _fully constructed_ object, and it's purpose would be to
> "couple the object to it's environment": After the object is
> constructed,
> it already is fully functional, but it is not yet coupled with it's
> environment (registry entries, associated threads, etc.). Currently
> C++ provides only two ways to couple the object to the environment:
>
> 1. You can do so in the constructor _before_ it is fully constructed.
> Of course, this includes the risk that it is also used before it's
> fully constructed.
>
> 2. You can "manually" couple it from the caller's side (f.ex., call
> a special init function, or do the coupling directly there). This
> has the disadvantage that it can be forgotten.
>
> Post-constructors would be the solution to this: They run after the
> constructor (therefore the object is completely constructed,
> therefore fully functional, and therefore no unwanted premature
> access can happen), and htey run automatically (no way to forget
> them).
>
> Post-post-constructors would not make sense, since after you coupled
> the object to it's environment, there's no need to do the same again
> (just as there is no need to run another constructor as soon as the
> constructor has run).
>
> Pre-destructors would make sense, however, to undo the work of the
> post-constructor.
>
Assuming each class can define a post-constructor, in what order do they get
called in an inheritance hierarchy, or is only one called (which one?)?
Anthony
--
Anthony Williams
Software Engineer, Nortel Networks Optoelectronics
The opinions expressed in this message are not necessarily those of my
employer
---
[ 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://www.research.att.com/~austern/csc/faq.html ]
Author: Christopher Eltschka <celtschk@dollywood.itp.tuwien.ac.at>
Date: Wed, 9 May 2001 20:45:08 GMT Raw View
Anthony Williams wrote:
>
> "Christopher Eltschka" <celtschk@dollywood.itp.tuwien.ac.at> wrote in
> message news:3AF7C2AD.EDFF77EA@dollywood.itp.tuwien.ac.at...
> > Michiel Salters wrote:
> > >
> > > In article <ur8y2tae0.fsf@worldnet.att.net>, Thomas A. Horsley says...
> > > >
> > > >I've got two on my list:
> > > >
> > > > 1. "post constructors" - a new kind of constructor that gets called
> > > > following the final constructor for the whole object. Virtual
> > > > functions would work as expected in the post constructors and you
> > > > wouldn't have to remember to use whatever convention you've
> adopted to
> > > > get aound not having post constructors.
> > >
> > > I believe Valentin Bonnard once pointed out that this area contains
> > > the largest number of features which could be trivially added, namely
> > > post-constructros, post-post-constructors, post-post-post-constructors,
> > > etc. In general, when two classed are related by inheritance, there must
> > > be a single class who gets the last word as to whether the full object
> > > is created. By design, in C++ that is the constructor of the derived
> > > class.
> >
> > As I see post constructors, the object would still be fully constructed
> > after the most derived constructor finishes. The post-constructor would
> > run on the _fully constructed_ object, and it's purpose would be to
> > "couple the object to it's environment": After the object is
> > constructed,
> > it already is fully functional, but it is not yet coupled with it's
> > environment (registry entries, associated threads, etc.). Currently
> > C++ provides only two ways to couple the object to the environment:
> >
> > 1. You can do so in the constructor _before_ it is fully constructed.
> > Of course, this includes the risk that it is also used before it's
> > fully constructed.
> >
> > 2. You can "manually" couple it from the caller's side (f.ex., call
> > a special init function, or do the coupling directly there). This
> > has the disadvantage that it can be forgotten.
> >
> > Post-constructors would be the solution to this: They run after the
> > constructor (therefore the object is completely constructed,
> > therefore fully functional, and therefore no unwanted premature
> > access can happen), and htey run automatically (no way to forget
> > them).
> >
> > Post-post-constructors would not make sense, since after you coupled
> > the object to it's environment, there's no need to do the same again
> > (just as there is no need to run another constructor as soon as the
> > constructor has run).
> >
> > Pre-destructors would make sense, however, to undo the work of the
> > post-constructor.
> >
>
> Assuming each class can define a post-constructor, in what order do they get
> called in an inheritance hierarchy, or is only one called (which one?)?
IMHO a post-constructor should act just like a normal member function,
except that it is called automatically after construction. Therefore
the post-constructor of the most-derived clas is called, and if base
versions exist which should be called, it's the derived function's
job to do this. If the post-constructor to call is ambiguous (because
of MI of at least two classes with PCs without overriding or hiding
them), the program is ill-formed.
Another interesting question is the parameter question.
I can think of two possibilities:
a) The post-constructor gets no parameters; if it needs access to
parameters, the constructor has to store them somewhere in the
class.
b) The post-constructor gets the same parameters as the constructor;
if for a given constructor there is no post-constructor with
an appropriate parameter list, no post-constructor is run.
Both have advantages and disadvantages. b is more flexible, but
also more error prone.
For pre-destructors, this question is void, since there are no
parameters.
---
[ 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://www.research.att.com/~austern/csc/faq.html ]
Author: Tom.Horsley@worldnet.att.net (Thomas A. Horsley)
Date: Mon, 7 May 2001 23:20:19 GMT Raw View
>In general, when two classed are related by inheritance, there must
>be a single class who gets the last word as to whether the full object
>is created. By design, in C++ that is the constructor of the derived
>class.
Right. That's the problem. I don't know who may have derived how many
classes from me, but the compiler does know who did a "new" or a declaration
of an instance of what class, and it could arrange to call the post
constructors after all the constructors are called. I don't see why
post-post or post-post-post constructors would enter into things at all.
(Now pre-destructors are a different matter - they could be useful
as well, though post-constructors are the most frequent idiom I need
to code around).
>This is much more likely to get in. Bjarne's talk actually covered this
>topic, for exact the reason you gave (RPC). But since this is all about
>the future C++, input is welcome about what you'd like to do with it.
>After all, in a way C++ already has marshalling and unmarshalling via
>operator<<(ostream&) and operator>>(istream&). What more would you like?
>That's not meant as a put-down, but as an invitation to explore.
>E.g. personally I think a more efficient form would be quite useful, but
>"pure binary" isn't the answer.
I don't know all that much about streams I/O, but I wouldn't think
operator>> would know what to do with a class object simply
because I once told it what to do with all the types that happen
to be members of that class. Automatically composing an aggregate
marshalling routine from the marshalling routines of the elements
of that aggregate is part of the compiler support I'm looking for.
(Kind of like the way a copy constructor gets automatically created
which does element by element copies).
Then there is polymorphism and un-marshalling which gets even tricker.
You need a way to identify which type of object is incoming so you
can un-marshall the data into a new instance that specific type.
I don't have any terrific suggestions for exactly how to achieve all this,
but I do know that in the spirit of C and C++ past, I'd like to be able to
control exactly what goes on if I feel like it (maybe I want to generate a
text format like operator>>, maybe I want to generate a endian neutral
binary format, maybe I want to dump it through a gzip filter to save space,
maybe I want to override the automatically generated routine for some struct
because I don't need to dump half the members, etc).
--
>>==>> The *Best* political site <URL:http://www.vote-smart.org/> >>==+
email: Tom.Horsley@worldnet.att.net icbm: Delray Beach, FL |
<URL:http://home.att.net/~Tom.Horsley> Free Software and Politics <<==+
---
[ 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://www.research.att.com/~austern/csc/faq.html ]
Author: Christopher Eltschka <celtschk@dollywood.itp.tuwien.ac.at>
Date: Tue, 8 May 2001 13:03:41 GMT Raw View
Michiel Salters wrote:
>
> In article <ur8y2tae0.fsf@worldnet.att.net>, Thomas A. Horsley says...
> >
> >I've got two on my list:
> >
> > 1. "post constructors" - a new kind of constructor that gets called
> > following the final constructor for the whole object. Virtual
> > functions would work as expected in the post constructors and you
> > wouldn't have to remember to use whatever convention you've adopted to
> > get aound not having post constructors.
>
> I believe Valentin Bonnard once pointed out that this area contains
> the largest number of features which could be trivially added, namely
> post-constructros, post-post-constructors, post-post-post-constructors,
> etc. In general, when two classed are related by inheritance, there must
> be a single class who gets the last word as to whether the full object
> is created. By design, in C++ that is the constructor of the derived
> class.
As I see post constructors, the object would still be fully constructed
after the most derived constructor finishes. The post-constructor would
run on the _fully constructed_ object, and it's purpose would be to
"couple the object to it's environment": After the object is
constructed,
it already is fully functional, but it is not yet coupled with it's
environment (registry entries, associated threads, etc.). Currently
C++ provides only two ways to couple the object to the environment:
1. You can do so in the constructor _before_ it is fully constructed.
Of course, this includes the risk that it is also used before it's
fully constructed.
2. You can "manually" couple it from the caller's side (f.ex., call
a special init function, or do the coupling directly there). This
has the disadvantage that it can be forgotten.
Post-constructors would be the solution to this: They run after the
constructor (therefore the object is completely constructed,
therefore fully functional, and therefore no unwanted premature
access can happen), and htey run automatically (no way to forget
them).
Post-post-constructors would not make sense, since after you coupled
the object to it's environment, there's no need to do the same again
(just as there is no need to run another constructor as soon as the
constructor has run).
Pre-destructors would make sense, however, to undo the work of the
post-constructor.
---
[ 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://www.research.att.com/~austern/csc/faq.html ]
Author: Tom.Horsley@worldnet.att.net (Thomas A. Horsley)
Date: Mon, 7 May 2001 01:33:53 GMT Raw View
I've got two on my list:
1. "post constructors" - a new kind of constructor that gets called
following the final constructor for the whole object. Virtual
functions would work as expected in the post constructors and you
wouldn't have to remember to use whatever convention you've adopted to
get aound not having post constructors.
2. some sort of "marshalling" and "un-marshalling" capability native in
the language instead of the klunky add-ons we have today with
semi-portable pre and/or post processors to support them. There are
lots of applications that need this sort of thing (object oriented
databases, remote procedure calls, etc) and having support in the
language would go a long way towards making them more portable.
I know #2 is rather vague, but it certainly seems like something ought to be
possible. Perhaps having some way to specify marshalling and unmarshalling
routines for individual types, then (if you didn't define an explicit one)
the compiler could automagically generate the marshalling and unmarshalling
routines for aggregate types by combining the routines for the individual
aggregate elements.
---
[ 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://www.research.att.com/~austern/csc/faq.html ]
Author: Michiel Salters<Michiel.Salters@cmg.nl>
Date: Mon, 7 May 2001 11:24:51 GMT Raw View
In article <ur8y2tae0.fsf@worldnet.att.net>, Thomas A. Horsley says...
>
>I've got two on my list:
>
> 1. "post constructors" - a new kind of constructor that gets called
> following the final constructor for the whole object. Virtual
> functions would work as expected in the post constructors and you
> wouldn't have to remember to use whatever convention you've adopted to
> get aound not having post constructors.
I believe Valentin Bonnard once pointed out that this area contains
the largest number of features which could be trivially added, namely
post-constructros, post-post-constructors, post-post-post-constructors,
etc. In general, when two classed are related by inheritance, there must
be a single class who gets the last word as to whether the full object
is created. By design, in C++ that is the constructor of the derived
class.
> 2. some sort of "marshalling" and "un-marshalling" capability native in
> the language instead of the klunky add-ons we have today with
> semi-portable pre and/or post processors to support them. There are
> lots of applications that need this sort of thing (object oriented
> databases, remote procedure calls, etc) and having support in the
> language would go a long way towards making them more portable.
>I know #2 is rather vague, but it certainly seems like something ought to be
>possible. Perhaps having some way to specify marshalling and unmarshalling
>routines for individual types, then (if you didn't define an explicit one)
>the compiler could automagically generate the marshalling and unmarshalling
>routines for aggregate types by combining the routines for the individual
>aggregate elements.
This is much more likely to get in. Bjarne's talk actually covered this
topic, for exact the reason you gave (RPC). But since this is all about
the future C++, input is welcome about what you'd like to do with it.
After all, in a way C++ already has marshalling and unmarshalling via
operator<<(ostream&) and operator>>(istream&). What more would you like?
That's not meant as a put-down, but as an invitation to explore.
E.g. personally I think a more efficient form would be quite useful, but
"pure binary" isn't the answer.
Regards,
Michiel Salters
--
Michiel Salters
Consultant Technical Software Engineering
CMG Trade, Transport & Industry
Michiel.Salters@cmg.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://www.research.att.com/~austern/csc/faq.html ]