What the hell is dynamic_cast for?

L

lovecreatesbea...

Suppose I have the following three classes,

GrandBase <-- Base <-- Child <-- GrandChild

The following cast expression holds true only if pBase points object
of type of ``Child'' or ``GrandChild'', i.e. types not upper than
Child in the above class hierarchy,

dynamic_cast<Child*>pBase

Do I draw this correctly?

Up-casting is safe while down-casting is not. dynamic_cast seems to do
down-casting, so why is dynamic_cast intenting to do the dangerous
work?
 
J

Juha Nieminen

Up-casting is safe while down-casting is not. dynamic_cast seems to do
down-casting, so why is dynamic_cast intenting to do the dangerous
work?

Dynamic casting is intended to do the "dangerous work" more safely.
While a static_cast will simply cast to the derived type regardless of
whether the object is of that type, dynamic cast actually checks that
the object is of that type, and if it isn't, it returns a null pointer.
You can check the returned pointer to see if the cast was successful.
(With static_cast you probably just get a segmentation fault.)

There are situation where downcasting may be unavoidable or the path
of least resistance. Thus it's good to have a tool to make it safer.
 
F

Fernando Gómez

You missed the parentheses and your class has to be polymorphic (have at
least one virtual function).

Wouldn't that be: "have a vritual destructor"?
 
M

Marcel Müller

Suppose I have the following three classes,

GrandBase <-- Base <-- Child <-- GrandChild

The following cast expression holds true only if pBase points object
of type of ``Child'' or ``GrandChild'', i.e. types not upper than
Child in the above class hierarchy,

In case of multiple inheritance it becomes a bit more complicated. In
fact it returns a non-null pointer to Child if and only if the cast to
Child* is valid. But it may also be a cross cast where Child is neither
derived from Base nor a superclass of it.
dynamic_cast<Child*>pBase

Do I draw this correctly?

Up-casting is safe while down-casting is not. dynamic_cast seems to do
down-casting, so why is dynamic_cast intenting to do the dangerous
work?

dynamic_cast is the C++ way of checking whether a polymorphic object is
of a certain type at runtime. You need this e.g. for type specific
dispatching. I would not call this 'dangerous work'.


Marcel
 
L

lovecreatesbea...

Dynamic casting is intended to do the "dangerous work" more safely.
While a static_cast will simply cast to the derived type regardless of
whether the object is of that type,

Hi, thank you.

dynamic_cast<T>(pointer) is used with an object pointer, while
dynamic cast actually checks that
the object is of that type, and if it isn't, it returns a null pointer.
You can check the returned pointer to see if the cast was successful.
(With static_cast you probably just get a segmentation fault.)

``is of that type'' means that

dynamic_cast<T>(pointer);

(*pointer) is declared as T or T's derived classes, right?

This cast fails if (*pointer) is declared as T's parent classes or
other un-related classes. Am I right?
There are situation where downcasting may be unavoidable or the path
of least resistance. Thus it's good to have a tool to make it safer.

I read some past posts, some said dynamic_cast indicated flaw in
design :)
 
L

lovecreatesbea...

That should be four :) , I added GrandBase but forgot to change the
number.
You missed the parentheses and your class has to be polymorphic (have at
least one virtual function). That's first. And second, the expression

dynamic_cast<Child*>(pBase)

has the type 'Child*', and not "holds true", although it will evaluate
to (Child*)0 if the cast fails.

Yes, thank you for correcting me.
 
J

James Kanze

Dynamic casting is intended to do the "dangerous work" more
safely. While a static_cast will simply cast to the derived
type regardless of whether the object is of that type,
[/QUOTE]
dynamic_cast<T>(pointer) is used with an object pointer, while
static_cast<T>(object) is the implicitly compatible conversion
and works with objects also. Am I right?

Both dynamic_cast and static_cast can be used on pointers and
references. (static_cast can also be used in a lot of other
cases.) When used on pointers or references:

-- static_cast allows moving up or down in the hierarchy (but
not sideways); it also allows converting to or from void*.
When moving down (Base* to Derived*), it makes no
verifications; if the object actually pointed to isn't a
Derived, anything can happen, so it is extremely dangerous
for this sort of casting. Note too that there are some
restrictions on static_cast when virtual base classes are
involved.

-- dynamic_cast only makes sense on pointers or references to
polymorphic types---otherwise, it only allows casting up
(Derived* to Base*), where it has exactly the same semantics
as static_cast. On pointers to polymorphic types, it allows
arbitrary navigation within the hierarchy, including
sideways. It verifies the type: if you dynamic_cast to
Derived*, and the pointer doesn't actually point to a
Derived*, it returns a null pointer (or raises an exception
if it is a reference cast). Except in very exceptional
cases (when the profiler says you must), you should use it
exclusively for down casting.
``is of that type'' means that

(*pointer) is declared as T or T's derived classes, right?
This cast fails if (*pointer) is declared as T's parent
classes or other un-related classes. Am I right?

I'm not too sure I understand. If pointer is of type Derived*,
dynamic_cast< Base* >( pointer ) always succeeds, of course,
returning a pointer to the Base sub-object of the Derived. If
pointer is of type Base*, dynamic_cast< Derived* >( pointer )
will return a null pointer if the actual object doesn't contain
an unambiguous Derived in its inheritance hierarchy, and a
pointer to the Derived if it does.
I read some past posts, some said dynamic_cast indicated flaw
in design :)

There is no requirement here for someone to be competent before
posting. dynamic_cast is easily abused, but there are cases
where it corresponds to the best design, and there are cases
where it represents the best engineering compromize.

Having a string of dynamic_cast usually is a sign of poor
design.
 
L

lovecreatesbea...

I'm not too sure I understand. If pointer is of type Derived*,
dynamic_cast< Base* >( pointer ) always succeeds, of course,
returning a pointer to the Base sub-object of the Derived. If
pointer is of type Base*, dynamic_cast< Derived* >( pointer )
will return a null pointer if the actual object doesn't contain
an unambiguous Derived in its inheritance hierarchy, and a
pointer to the Derived if it does.

Thank you,

I am sorry I didn't express myself clearly.

Suppose there are three classes: Base, Child, GrandChild are
polymorphic classes. Child is derived from Base, and GrandChild from
Child.

I think only the dynamic_cast in ``Case 1'' fails, am I right?

Base *pB, *p;
Child *pC;
GrandChild *pG;

/* pB, pC, pG, proper initialization .. */

// Case 1
p = pB; // legal up-cast
pC = dynamic_cast<Child*>(p); // illegal dynamic-cast

// Case 2
p = pC; // legal up-cast
pC = dynamic_cast<Child*>(p); // legal dynamic-cast

// Case 3
p = pG; // legal up-cast
pC = dynamic_cast<Child*>(p); // legal dynamic-cast
 
L

lovecreatesbea...

Thank you,

I am sorry I didn't express myself clearly.

Suppose there are three classes: Base, Child, GrandChild are
polymorphic classes. Child is derived from Base, and GrandChild from
Child.

I think only the dynamic_cast in ``Case 1'' fails, am I right?

    Base       *pB, *p;
    Child      *pC;
    GrandChild *pG;

    /* pB, pC, pG, proper initialization .. */

or be more specific, here, I exactly menat:

pB = new Base;
pC = new Child;
pG = new GrandChild;
    // Case 1
    p = pB;                       // legal up-cast

and of course, no up-cast here
 
J

James Kanze

That was probably me and I stand by it. It's a smell. That
doesn't mean it isn't sometimes necessary.

I think others have been more dogmatic about it than you. It's
potentially a smell, and if I see it being used a lot, I become
suspicious. But there are specific idioms where it is more than
justified; where the alternatives are less clean. And if I see
it in the implementation of one of those idioms, it doesn't
cause me any problems.
 
J

James Kanze

Suppose there are three classes: Base, Child, GrandChild are
polymorphic classes. Child is derived from Base, and
GrandChild from Child.

Public derivation, or private? And does Base have at least one
virtual function?
I think only the dynamic_cast in ``Case 1'' fails, am I right?
Base *pB, *p;
Child *pC;
GrandChild *pG;
/* pB, pC, pG, proper initialization .. */
// Case 1
p = pB; // legal up-cast
pC = dynamic_cast<Child*>(p); // illegal dynamic-cast
// Case 2
p = pC; // legal up-cast
pC = dynamic_cast<Child*>(p); // legal dynamic-cast
// Case 3
p = pG; // legal up-cast
pC = dynamic_cast<Child*>(p); // legal dynamic-cast

If I suppose public derivation in all cases, and that Base has
at least one virtual function, all of the casts are "legal".
The first will result in a null pointer, and the others to a
pointer to the correct (sub-)object.
 
L

lovecreatesbea...

Public derivation, or private?  And does Base have at least one
virtual function?

Yes, I assumed that the Base had a virtual function.

Private derivation doesn't prevent dynamic_cast, am I right?
If I suppose public derivation in all cases, and that Base has
at least one virtual function, all of the casts are "legal".

``C++ Primer, 4th'' says in $18.2.1, ``If a dynamic_cast to a pointer
type fails, the result of the dynamic_cast is the value 0.'' If the
dynamic_cast expression evaluates zero, can I regard it as failed?
The first will result in a null pointer, and the others to a
pointer to the correct (sub-)object.

Thanks for reply.
 
J

James Kanze

On May 30, 4:05 am, "(e-mail address removed)"

[...]
Private derivation doesn't prevent dynamic_cast, am I right?

dynamic_cast respects access control. Given something like:

class Base
{
public:
virtual ~Base() {}
} ;

class Derived : private Base
{
public:
Base* me() { return this ; }
} ;

Derived* pD = new Derived ;
Base* pB = pD->me() ;
Derived* p2 = dynamic_cast< Derived* >( pB ) ;

The dynamic_cast returns a null pointer. (Note that I've also
had to play games in order to get the Base* from the Derived*.)

In general, the only casts which ignore access are C style
casts: (Derived*)( pB ) works, but static_cast< Derived* > won't
compile, and dynamic_cast< Derived* > fails at runtime (and
reinterpret_cast< Derived* > compiles, but with significantly
different semantics---although there's a good chance that in
such simple cases, it will appear to work).
``C++ Primer, 4th'' says in $18.2.1, ``If a dynamic_cast to a
pointer type fails, the result of the dynamic_cast is the
value 0.'' If the dynamic_cast expression evaluates zero, can
I regard it as failed?

Yes. Don't confuse legal/illegal with succeeded/failed. An
illegal dynamic_cast won't compile. But a legal dynamic_cast
can fail at runtime, in which case, it either returns a null
pointer (pointer cast) or throws an exception (reference cast).
 
N

Noah Roberts

James said:
I think others have been more dogmatic about it than you. It's
potentially a smell, and if I see it being used a lot, I become
suspicious. But there are specific idioms where it is more than
justified; where the alternatives are less clean. And if I see
it in the implementation of one of those idioms, it doesn't
cause me any problems.

*shrug* if you say so...
 

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,962
Messages
2,570,134
Members
46,690
Latest member
MacGyver

Latest Threads

Top