dynamic_cast is only casting right?

A

A

in a function:

void Image_AssignImage(TObject *Sender)
{
dynamic_cast<TObjectDescendant *>(Sender)->DoWhatever();
}

in above function dynamic_cast is simply casting Tobject into compatible
TObjectDescendant and then calls function DoWhatever contained in
TObjectDescendant (and not in Tobject)?

The above does not need any kind of delete or something like that right? I
suppose it does not but would like to verify this.
(note: Sender always points to existing object that is deleted on program
exit so does not need deleting itself in above example)
 
V

Victor Bazarov

in a function:

void Image_AssignImage(TObject *Sender)
{
dynamic_cast<TObjectDescendant *>(Sender)->DoWhatever();
}

in above function dynamic_cast is simply casting Tobject into compatible
TObjectDescendant and then calls function DoWhatever contained in
TObjectDescendant (and not in Tobject)?

The above does not need any kind of delete or something like that right? I
suppose it does not but would like to verify this.
(note: Sender always points to existing object that is deleted on program
exit so does not need deleting itself in above example)

The cast can fail. A failed pointer cast yields a null pointer and as
such will make the behaviour of your program undefined. A failed
reference cast throws 'std::bad_cast' exception. It's better to do


void Image_Asssign...
{
if (TObjectDescendant* pD = dynamic_cast<...>(Sender))
pD->DoWhatever();
else
// report the error somehow
}

(ellipsis not syntactical)

V
 
S

Stuart Redmann

in a function:

void Image_AssignImage(TObject *Sender)
{
dynamic_cast<TObjectDescendant *>(Sender)->DoWhatever();

}

in above function dynamic_cast is simply casting Tobject into compatible
TObjectDescendant and then calls function DoWhatever contained in
TObjectDescendant (and not in Tobject)?

To put it more clearly: It _tries_ to cast the _pointer_ to TObject
into a pointer to TObjectDescendant based on type information that is
attached to the TObject instance (note that you have to enable RTTI in
your compiler to make dynamic_cast work).
The above does not need any kind of delete or something like that right? I
suppose it does not but would like to verify this.

Ownership of the pointer (IOW, which part of the code should delete
it) is completely unrelated to dynamic_cast. Dynamic_cast just casts
the pointer, there is no copy of the underlying object made (which
would have to be deleted by someone).
(note: Sender always points to existing object that is deleted on program
exit so does not need deleting itself in above example)

Nope.

Regards,
Stuart
 
N

Nick Keighley

I'm not sure what "simply casting" means. Is it possible the actual
bit pattern may not chnage at all?

To put it more clearly: It _tries_ to cast the _pointer_ to TObject
into a pointer to TObjectDescendant based on type information that is
attached to the TObject instance (note that you have to enable RTTI in
your compiler to make dynamic_cast work).

is it a valid implementation of C++ if it doesn't support RTTI?


<snip>
 
G

Goran

(note: Sender always points to existing object that is deleted on program
exit so does not need deleting itself in above example)

That's code based of VCL of borland, right? If so, last sentence is
horribly wrong in general case. Sender is valid when you are inside
event handler, that's fine, but you should not e.g. store it for later
use thinking that it will be deleted much later. What you must not do,
however, is try to delete Sender yourself - that might break in
unpredictable ways.

Do you think that, when a function you receives a pointer, it should
always delete the received object? That's actually almost always
__not__ the case.

It's a pity that Sender is not a reference, but VCL is all based on
Object Pascal of Delphi, and Object Pascal knows no references.

As for your question, +1 for e.g. Victor. Are you sure that Sender
IS_A TObjectDescendant? If not, use if.

Goran.
 
B

Bart van Ingen Schenau

I'm not sure what "simply casting" means. Is it possible the actual
bit pattern may not chnage at all?

Yes, it is possible that the bit-pattern does not change when you do a
dynamic cast. It depends on the class hierarchy that the source object
is in.
For example, if there is only single inheritance, then chances are
that the bit pattern does not change in a dynamic_cast
is it a valid implementation of C++ if it doesn't support RTTI?

No, but very few compilers are conforming in their default mode.

Bart v Ingen Schenau
 
A

A

wow it's amazing how a bit different word choice can make all the difference
in clarity. even though i read about it on the web and so on, now i know
exactly now how to use dynamic_cast and in which situation it is more
appropriate. thanks everyone!
 
A

A

That's code based of VCL of borland, right? If so, last sentence is
horribly wrong in general case. Sender is valid when you are inside
event handler, that's fine, but you should not e.g. store it for later
use thinking that it will be deleted much later. What you must not do,
however, is try to delete Sender yourself - that might break in
unpredictable ways.

yes, c++ builder.

what i meant to say is that i don't have to care about *Sender and mainly my
question was about the exact meaning and operation of dynamic cast which
everyone that answered here greatly simplified the meaning of what it does.
and you of course.
It's a pity that Sender is not a reference, but VCL is all based on
Object Pascal of Delphi, and Object Pascal knows no references.
As for your question, +1 for e.g. Victor. Are you sure that Sender
IS_A TObjectDescendant? If not, use if.

Well, even though there is a chance that dynamic cast can fail in this
example chance is probably next to none.
I will of course handle exception but in more complete version I use it to
cast TObject *Sender into TEdit * so I can use same event for all Edit boxes
to handle the same thing based on *Sender. In particular checking if any of
Edit boxes changed so that Apply button is enabled. So TEdit is descendant
of TObject.

So for example:

void Image_AssignImage(TObject *Sender)
{
try
{
TEdit *dEdit = dynamic_cast<TEdit *>(Sender);
if (dEdit->Modified) ButtonApply->Enabled=true;
}
catch (Exception &e)
{
// do something with exception
}
}
 
G

Goran

Well, even though there is a chance that dynamic cast can fail in this
example chance is probably next to none.
I will of course handle exception but in more complete version I use it to
cast TObject *Sender into TEdit * so I can use same event for all Edit boxes
to handle the same thing based on *Sender. In particular checking if any of
Edit boxes changed so that Apply button is enabled. So TEdit is descendant
of TObject.

It's not a question of TEdit being descendant of TObject, it's whether
Sender IS_A TEdit.

But anyway, if that's your use case, it's just fine not to check for
NULL from dynamic_cast, because you are in some "changed" event that
was wired to said TEdit (through the IDE, right?). If dynamic_cast
somehow goes wrong in __that__ situation, I personally would prefer
the code to just crash at the spot (but VCL is stubborn and it always
throws VCL exceptions, even if there's an actual crash, see below).

You could also put in an assert:

So for example:

void Image_AssignImage(TObject *Sender)
{
try
    {
    TEdit *dEdit = dynamic_cast<TEdit *>(Sender);
    if (dEdit->Modified) ButtonApply->Enabled=true;
    }
catch (Exception &e)
    {
    // do something with exception
    }
}

Just a comment: yeah, you could catch, and if things still are the way
they were when I was doing Delphi/C++ builder, you will catch
EAccessViolation ( which is equivalent to a crash, but VCL refuses to
die and stumbles on ;-) ).

EAccessViolation is not an exception one wants to catch. Rather, it's
a bug to be fixed. (If it indeed happen, but again, chances of that
are way too close to 0 to matter).

Goran.
 
A

A

If you don't check 'dEdit' on being null, the program has undefined
behavior when you use (dereference) dEdit, and in Windows a special system
exception is thrown, not a standard C++ one. Is that what you're trying
to handle? Probably easier and faster without 'try' in your case here.

Actually, I looked at documentation of c builder and it seems I have to
check for both - exception and NULL.
Here is what it says:

"If successful, dynamic_cast< T > (ptr) converts ptr to the desired type. If
a pointer cast fails, the returned pointer is valued 0. If a cast to a
reference type fails, the Bad_cast exception is thrown."

So exception is possible on reference type fail as well.
 
A

A

It's not a question of TEdit being descendant of TObject, it's whether
Sender IS_A TEdit.

OK when you want me to paste full code I also did:

if (Sender->ClassNameIs("TEdit"))
{
try {
TEdit *dEdit = dynamic_cast<TEdit *>(Sender);
if (dEdit) if (dEdit->Modified) Button_Apply->Enabled = true;
}
catch (...) {
//whatever
}
}

So there... checks if it is TEdit, catches exception (bad_cast) and NULL :)
All handled :)

The event may come from TEdit, TCheckBox and TComboBox (and nothing else) so
ClassName must be checked to determine where it came from.
You could also put in an assert:
assert(dynamic_cast<TEdit*>(Sender));
(then, you do as usual)

Yes, but no need in above case.
Just a comment: yeah, you could catch, and if things still are the way
they were when I was doing Delphi/C++ builder, you will catch
EAccessViolation ( which is equivalent to a crash, but VCL refuses to
die and stumbles on ;-) ).

Yes in this code but not in the above "complete" version I pasted. That one
will catch only bad_cast exception as this is the only exception that may
happen at that moment due to additional NULL check. I could probably also
check if exception type is std::bad_cast but I guess no need just more to
type :)
 
T

Thomas J. Gritzan

Am 04.06.2010 18:17, schrieb A:
OK when you want me to paste full code I also did:

if (Sender->ClassNameIs("TEdit"))
{
try {
TEdit *dEdit = dynamic_cast<TEdit *>(Sender);
if (dEdit) if (dEdit->Modified) Button_Apply->Enabled = true;
}
catch (...) {
//whatever
}
}

So there... checks if it is TEdit, catches exception (bad_cast) and NULL :)
All handled :)

This doesn't throw an exception but evaluates to NULL if Sender isn't a
TEdit:

TEdit* edit = dynamic_cast<TEdit*>(Sender);

This will throw an exception in that case:

TEdit& edit = dynamic_cast<TEdit&>(*Sender);

So depending on usage, you either have to check for NULL or catch the
exception, but not both.
 
A

A

This will throw an exception in that case:
TEdit& edit = dynamic_cast<TEdit&>(*Sender);

So depending on usage, you either have to check for NULL or catch the
exception, but not both.

what about: " If a cast to a reference type fails, the Bad_cast exception is
thrown."

"If successful, dynamic_cast< T > (ptr) converts ptr to the desired type. If
a pointer cast fails, the returned pointer is valued 0. If a cast to a
reference type fails, the Bad_cast exception is thrown."

Is that this case?

TEdit& edit = dynamic_cast<TEdit&>(*Sender);
 
A

A

To rephrase (if I understood correcly):

TEdit* edit = dynamic_cast<TEdit*>(Sender);

is called "pointer cast"

and...

TEdit& edit = dynamic_cast<TEdit&>(*Sender);

is called "cast to a reference type"?
I know "&" is "by reference" so I'm guessing this is ok...

right?
 
V

Victor Bazarov

Actually, I looked at documentation of c builder and it seems I have to
check for both - exception and NULL.
Here is what it says:

"If successful, dynamic_cast< T> (ptr) converts ptr to the desired type. If
a pointer cast fails, the returned pointer is valued 0. If a cast to a
reference type fails, the Bad_cast exception is thrown."

So exception is possible on reference type fail as well.

Yes. Wasn't that what I said before? Quoting my post from 6/2/2010: ^^^^^^^^^^^^^^

It's good that you found an independent confirmation of that...

V
 
V

Victor Bazarov

To rephrase (if I understood correcly):

TEdit* edit = dynamic_cast<TEdit*>(Sender);

is called "pointer cast"

and...

TEdit& edit = dynamic_cast<TEdit&>(*Sender);

is called "cast to a reference type"?
I know "&" is "by reference" so I'm guessing this is ok...

right?

'T&' is a reference type. 'T*' is a pointer type. So, yes.

V
 
M

Mark Jones

Victor said:
The cast can fail. A failed pointer cast yields a null pointer and as
such will make the behaviour of your program undefined. A failed
reference cast throws 'std::bad_cast' exception. It's better to do


void Image_Asssign...
{
if (TObjectDescendant* pD = dynamic_cast<...>(Sender))
pD->DoWhatever();
else
// report the error somehow
}

Also, consider looking at boost::polymorphic_cast for even better casting:

http://www.boost.org/doc/libs/1_43_0/libs/conversion/cast.htm#Polymorphic_cast

It isn't really any better than the code above, but getting into the
habit of using it instead of dynamic_cast, you have a more predictable
error when you forget to do the error check. In other words, if you do
this:

dynamic_cast<...>(Sender)->DoWhatever();

and forget to do what was above (with the check for a failed cast by
checking for NULL) and the cast fails, the behavior is undefined,
whereas if you use boost::polymorphic_cast:

try {
boost::polymorphic_cast<...>(Sender)->DoWhatever();
} catch (const std::bad_cast &) {
// deal with the fact that it didn't cast
}

and instead forget to do the try/catch:

boost::polymorphic_cast<...>(Sender)->DoWhatever();

at least now you will have predictable behavior of an uncaught exception.

Both dynamic_cast and boost::polymorphic_cast need supporting cast
checking, but by getting into the habit of using boost::polymorphic_cast
(if boost is available to you), if/when you forget to do the cast check,
the bug will produce predictable results.

Adding the try/catch might have a performance impact, but to choose
dynamic_cast instead for that reason without just-cause would probably
be a premature optimization.

Also, if you know that it will be a cast that always succeeds and need
higher performance, consider using boost::polymorphic_downcast which
will use a dynamic_cast and assert in debug builds, but use a
static_cast in release builds for performance.

Mark
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

Forum statistics

Threads
473,770
Messages
2,569,584
Members
45,075
Latest member
MakersCBDBloodSupport

Latest Threads

Top