Board index » cppbuilder » Re: ~mainform vs OnClose OnDestroy, - mainform vs OnCreate, OnActivate..

Re: ~mainform vs OnClose OnDestroy, - mainform vs OnCreate, OnActivate..


2005-07-29 08:55:01 PM
cppbuilder112
DKat wrote:
Quote
I was happliy using the Mainform Events in my program to do various
clean up tasks (delete and pop) and I was told by this group (or
probably Component use) NOT to do so. That I should use MainForm and
~MainForm. Now that my head is above water and I have some air to
breathe I would like to know why as do others in my department who
still use the other means. They seemed to work just fine where as I
have to be real careful when using either of the other two that I'm
not killing or creating something before it can exist or after it
should have been deleted.
'why?' is always a good question to ask <g>After all, if we do not
understand the rule, how do we know when to break it ;?)
The problem with the OnCreate and OnDestroy events is their Delphi
legacy. In most ways the languages are compatible, otherwise a C++
binding for VCL would not be possible. However, the way that C++
constructs objects is very different to the way Delphi constructs
objects, and this difference is most noticable in OnCreate/OnDestroy.
The part that causes the problem is:
OnCreate will be called *before* your constructor
OnDestroy will be called *after* your destructor
In theory, this should not be possible in C++ and it is a real problem
if any data members in your form are also of class-type, as their
constructors will not have run either (or their destructors will be
complete)
The reason is Delphi starts construction with the most-derived object,
and it is the responsibility of this constructor to call a base-class
constructor. In C++ construction is essentially the other way round,
starting with the most basic type and constructing layer by layer until
you finish constructing the actual type.
This is most noticable when you examine virtual functions. In Delphi,
a virtual function will use dynamic-dispatch to the most derived type,
even during construction/destruction. That is why it must start
constructing at the top - so that the top level class can make sure it
has constructed anything that might be needed during a virtual call.
In C++ the 'type' of your object during construction (for a virtual
function) is the (sub)type that is currently under construction, so you
do not get virtual overides called until after that class has started
construction. This is how C++ guarantees all objects are safely
constructed if a virtual function is called.
C++Builder is wierd. If Delphi construction is 'top-down' and C++ is
'bottom-up', then C++Builder is 'inside-out'. For a C++ class derived
from a VCL class, construction will start somewhere in the middle of
the hierarchy, with the most-derived Delphi class! From here you get
top-down construction, until that class finished constuction. This is
then the constructed base-class that allows C++ construction to finish
in a bottom-up manner.
But at all times, virtual functions are 'live' meaning your C++ code
can be called even though your object and members are not yet
constructed. The same can happen after destruction.
This means the problem is not only with OnCreate and OnDestroy, but
with any virtual method call that can happen when constructing Delphi
base classes (or any that you call yourself during construction) Other
good examples are OnShow and OnActivate, if the form has Visible=true
set in the designer. Note that these events are 'safe' if
Visible=false, and you explicitly call Show(), so the problem is indeed
subtle!
Also note that this only applies to VCL classes i.e. any class which
ultimately derives from TObject. 'pure' C++ classes are still handled
correctly in BCB [This will not be true for MS new C++/CLI binding for
.NET, where 'deep virtuals' become normal for native C++ classes too]
OK, that is quite a long explaination for a newsgroup posting, yet
barely scratches the surface! Hope it helps you understand this tricky
subject.
AlisdairM(TeamB)
 
 

Re:Re: ~mainform vs OnClose OnDestroy, - mainform vs OnCreate, OnActivate..

"Alisdair Meredith [TeamB]" < XXXX@XXXXX.COM >wrote:
Quote

[...] The part that causes the problem is:
OnCreate will be called *before* your constructor
OnDestroy will be called *after* your destructor
Whether or not they are called before or after the constructor
and destructor depends on what the CreationOrder is set to.
~ JD
 

Re:Re: ~mainform vs OnClose OnDestroy, - mainform vs OnCreate, OnActivate..

"JD" < XXXX@XXXXX.COM >writes:
Quote
"Alisdair Meredith [TeamB]" < XXXX@XXXXX.COM >wrote:
>
>[...] The part that causes the problem is:
>OnCreate will be called *before* your constructor
>OnDestroy will be called *after* your destructor

Whether or not they are called before or after the constructor
and destructor depends on what the CreationOrder is set to.
One problem with that simple dependency is that the IDE has been known
to change this design-time property without warning. I don't remember
what was the trigger, but that it has ever happened is concerning
enough.
I would recommend that regardless of the setting of that property, you
never under any circumstances use OnCreate or OnDestroy, and instead
use the constructor and destructor, respectively.
--
Chris (TeamB);
 

{smallsort}

Re:Re: ~mainform vs OnClose OnDestroy, - mainform vs OnCreate, OnActivate..

"Alisdair Meredith [TeamB]"
< XXXX@XXXXX.COM >wrote in message
Quote
'why?' is always a good question to ask <g>After all, if we do not
understand the rule, how do we know when to break it ;?)

The problem with the OnCreate and OnDestroy events is their Delphi
legacy. In most ways the languages are compatible, otherwise a C++
binding for VCL would not be possible. However, the way that C++
constructs objects is very different to the way Delphi constructs
objects, and this difference is most noticable in OnCreate/OnDestroy.


The part that causes the problem is:
OnCreate will be called *before* your constructor
OnDestroy will be called *after* your destructor

In theory, this should not be possible in C++ and it is a real problem
if any data members in your form are also of class-type, as their
constructors will not have run either (or their destructors will be
complete)


The reason is Delphi starts construction with the most-derived object,
and it is the responsibility of this constructor to call a base-class
constructor. In C++ construction is essentially the other way round,
starting with the most basic type and constructing layer by layer until
you finish constructing the actual type.

This is most noticable when you examine virtual functions. In Delphi,
a virtual function will use dynamic-dispatch to the most derived type,
even during construction/destruction. That is why it must start
constructing at the top - so that the top level class can make sure it
has constructed anything that might be needed during a virtual call.

In C++ the 'type' of your object during construction (for a virtual
function) is the (sub)type that is currently under construction, so you
do not get virtual overides called until after that class has started
construction. This is how C++ guarantees all objects are safely
constructed if a virtual function is called.


C++Builder is wierd. If Delphi construction is 'top-down' and C++ is
'bottom-up', then C++Builder is 'inside-out'. For a C++ class derived
from a VCL class, construction will start somewhere in the middle of
the hierarchy, with the most-derived Delphi class! From here you get
top-down construction, until that class finished constuction. This is
then the constructed base-class that allows C++ construction to finish
in a bottom-up manner.

But at all times, virtual functions are 'live' meaning your C++ code
can be called even though your object and members are not yet
constructed. The same can happen after destruction.


This means the problem is not only with OnCreate and OnDestroy, but
with any virtual method call that can happen when constructing Delphi
base classes (or any that you call yourself during construction) Other
good examples are OnShow and OnActivate, if the form has Visible=true
set in the designer. Note that these events are 'safe' if
Visible=false, and you explicitly call Show(), so the problem is indeed
subtle!


Also note that this only applies to VCL classes i.e. any class which
ultimately derives from TObject. 'pure' C++ classes are still handled
correctly in BCB [This will not be true for MS new C++/CLI binding for
.NET, where 'deep virtuals' become normal for native C++ classes too]


OK, that is quite a long explaination for a newsgroup posting, yet
barely scratches the surface! Hope it helps you understand this tricky
subject.

AlisdairM(TeamB)
Thank you so much! It is something easy to remember when you understand the
why and it also opens up so many more doors of now knowing what else I need
to know.... Donna
(I'm leaving the entire post in because I think it is well worth
repeating...)
 

Re:Re: ~mainform vs OnClose OnDestroy, - mainform vs OnCreate, OnActivate..

DKat wrote:
Quote
(I'm leaving the entire post in because I think it is well worth
repeating...)
Please don't!
It is a nice sentiment, but violates the newsgroup guidelines and I
would have to have to cancel my own post ;?)
Glad you found it helpful.
AlisdairM(TeamB)