dynamic_cast between unrelated types

  • Thread starter Alf P. Steinbach
  • Start date
A

Alf P. Steinbach

* Thomas Lorenz:
Hello,

first, I didn't find any reference to my question through googling.

dynamic_cast uses RTTI to determine if the cast expression is valid.
Invalid casts of pointers give a '0'-result. As it is the case in the
following example:

-----------------------------------------------------------
#include <iostream>

struct A {virtual void print() {std::cout << "A" << std::endl;}};
struct B {virtual void print() {std::cout << "B" << std::endl;}};
int main(int argc,char* argv[])
{
A* a = new A();
B* b = dynamic_cast<B*>(a);
if (b)
b->print();
else
std::cout << "b is 0" << std::endl;
return 0;
}
-------------------------------------------------------------

This compiles just fine with MS C++ 7, g++ 3.3.3. Running this tells me
(quite correctly) that "b is 0".

What I really don't get is - why isn't this detected at compile time?

It probably is.

And with non-polymorphic types you'd get a compile time error.

With polymorphic types, however, the language allows this because the
pointer 'a' might be a pointer to the 'A' subobject of an object of a
class that inherits from both 'A' and 'B':

#include <iostream>

struct A {virtual void print() {std::cout << "A" << std::endl;}};
struct B {virtual void print() {std::cout << "B" << std::endl;}};
struct C: A, B {};

int main()
{
A* a = new C();
B* b = dynamic_cast<B*>( a );
if (b)
b->print();
else
std::cout << "b is 0" << std::endl;
return 0;
}


OK,
that's what static_cast does (replacing the dynamic_cast with a
static_cast in the example gives a nice compiler error).

Scott Meyers advises to prefer compile time errors to run time errors. So
naive reasoning tells me to prefer static_cast, whenever possible.

That's not naive, that's very good.

So here's the question: Can anybody tell me when to prefer dynamic_cast
to static_cast? Are there any possible situations where static_cast
doesn't really work and you have to use dynamic_cast?

When you don't know the types at compile time, and a virtual function doesn't
solve the problem (virtual functions perform safe downcasts for you).

Perhaps the most typical example is to apply an event E to an object O, where
you don't know whether O supports event E or not.

In such cases it's preferable to centralize the dynamic casts instead of
having such casts scattered around the code, and one way of centralizing them
is to use the "visitor pattern" (google).
 
T

Thomas Lorenz

Hello,

first, I didn't find any reference to my question through googling.

dynamic_cast uses RTTI to determine if the cast expression is valid.
Invalid casts of pointers give a '0'-result. As it is the case in the
following example:

-----------------------------------------------------------
#include <iostream>

struct A {virtual void print() {std::cout << "A" << std::endl;}};
struct B {virtual void print() {std::cout << "B" << std::endl;}};
int main(int argc,char* argv[])
{
A* a = new A();
B* b = dynamic_cast<B*>(a);
if (b)
b->print();
else
std::cout << "b is 0" << std::endl;
return 0;
}
-------------------------------------------------------------

This compiles just fine with MS C++ 7, g++ 3.3.3. Running this tells me
(quite correctly) that "b is 0".

What I really don't get is - why isn't this detected at compile time? OK,
that's what static_cast does (replacing the dynamic_cast with a
static_cast in the example gives a nice compiler error).

Scott Meyers advises to prefer compile time errors to run time errors. So
naive reasoning tells me to prefer static_cast, whenever possible.

So here's the question: Can anybody tell me when to prefer dynamic_cast
to static_cast? Are there any possible situations where static_cast
doesn't really work and you have to use dynamic_cast?

Regards
Thomas
 
S

Saurabh Aggrawal

In general you use static_cast when you want to convert numeric data
types such as enums to ints or ints to floats, and you are certain of
the data types involved in the conversion. static_cast conversions are
not as safe as dynamic_cast conversions, because static_cast does no
run-time type check, while dynamic_cast does. A dynamic_cast to an
ambiguous pointer will fail, while a static_cast returns as if nothing
were wrong; this can be dangerous. Although dynamic_cast conversions
are safer, dynamic_cast only works on pointers or references, and the
run-time type check is an overhead.

Saurabh Aggrawal
 
M

Malte Starostik

Yes and no. There are situations when a static_cast on a class/struct
pointer or reference is needed and perfectly safe and so the overhead of
dynamic_cast is completely wasted. Limiting its use to basic types is a
little too strict.
OK, that's perfectly understandable. But why isn't dynamic_cast allowed
to do some type checking at compiletime, as static_cast does? My example
code provides the compiler with enough information to decide that the
cast won't work.
Have you read Alf's reply? It shows one such example. A compiler error
in your example case would be logical, but not really worth the effort
given that in almost no real world code, the assignment to the source
pointer/reference is made in a place visible to the compiler at the
point of the cast, so it cannot check whether the conversion might
possibly succeed or not.
And I really can't envision a commonplace scenario containing a line like
DestType* dest = dynaic_cast<DestType*>(src);
where the compiler doesn't know about DestType. OK, DestType could be
void, but those are scenarios I reallly don't want to think about :)
As Alf wrote, the dynamic type of src could be convertible to DestType*
even if src's static type doesn't suggest it is.

Cheers,
Malte
 
T

Thomas Lorenz

In general you use static_cast when you want to convert numeric data
types such as enums to ints or ints to floats, and you are certain of
the data types involved in the conversion. static_cast conversions are
not as safe as dynamic_cast conversions, because static_cast does no
run-time type check, while dynamic_cast does. A dynamic_cast to an
ambiguous pointer will fail, while a static_cast returns as if nothing
were wrong; this can be dangerous. Although dynamic_cast conversions
are safer, dynamic_cast only works on pointers or references, and the
run-time type check is an overhead.

OK, that's perfectly understandable. But why isn't dynamic_cast allowed
to do some type checking at compiletime, as static_cast does? My example
code provides the compiler with enough information to decide that the
cast won't work.

And I really can't envision a commonplace scenario containing a line like
DestType* dest = dynaic_cast<DestType*>(src);
where the compiler doesn't know about DestType. OK, DestType could be
void, but those are scenarios I reallly don't want to think about :)

Regards
Thomas
 
T

Thomas Lorenz

In general you use static_cast when you want to convert numeric data
types such as enums to ints or ints to floats, and you are certain of
the data types involved in the conversion. static_cast conversions are
not as safe as dynamic_cast conversions, because static_cast does no
run-time type check, while dynamic_cast does. A dynamic_cast to an
ambiguous pointer will fail, while a static_cast returns as if nothing
were wrong; this can be dangerous. Although dynamic_cast conversions
are safer, dynamic_cast only works on pointers or references, and the
run-time type check is an overhead.

Saurabh Aggrawal

OK, that's perfectly understandable. But why isn't dynamic_cast allowed
to do some type checking at compiletime, as static_cast does? My example
code provides the compiler with enough information to decide that the
cast won't work.

And I really can't envision a commonplace scenario containing a line like
DestType* dest = dynaic_cast<DestType*>(src);
where the compiler doesn't know about DestType. OK, DestType could be
void, but those are scenarios I reallly don't want to think about :)

Regards
Thomas
 
T

Thomas Lorenz

In general you use static_cast when you want to convert numeric data
types such as enums to ints or ints to floats, and you are certain of
the data types involved in the conversion. static_cast conversions are
not as safe as dynamic_cast conversions, because static_cast does no
run-time type check, while dynamic_cast does. A dynamic_cast to an
ambiguous pointer will fail, while a static_cast returns as if nothing
were wrong; this can be dangerous. Although dynamic_cast conversions
are safer, dynamic_cast only works on pointers or references, and the
run-time type check is an overhead.

Saurabh Aggrawal

OK, that's perfectly understandable. But why isn't dynamic_cast allowed
to do some type checking at compiletime, as static_cast does? My example
code provides the compiler with enough information to decide that the
cast won't work.

And I really can't envision a commonplace scenario containing a line like
DestType* dest = dynaic_cast<DestType*>(src);
where the compiler doesn't know about DestType. OK, DestType could be
void, but those are scenarios I reallly don't want to think about :)

Regards
Thomas
 
T

Thomas Lorenz

[snip]
There are situations when a static_cast on a class/struct
pointer or reference is needed and perfectly safe and so the overhead
of dynamic_cast is completely wasted. Limiting its use to basic types
is a little too strict.

Yes, that sounds very reasonable, and this is the path I've already
taken.

[snip]
Have you read Alf's reply? It shows one such example. A compiler
error in your example case would be logical, but not really worth the
effort given that in almost no real world code, the assignment to the
source pointer/reference is made in a place visible to the compiler at
the point of the cast, so it cannot check whether the conversion might
possibly succeed or not.
No, obviously not ;) His example makes the behaviour of dynamic_cast
perfectly clear.

Thanks for all the help!
Thomas
 
K

Karl Heinz Buchegger

Thomas said:
[snip]
There are situations when a static_cast on a class/struct
pointer or reference is needed and perfectly safe and so the overhead
of dynamic_cast is completely wasted. Limiting its use to basic types
is a little too strict.

Yes, that sounds very reasonable, and this is the path I've already
taken.

[snip]
Have you read Alf's reply? It shows one such example. A compiler
error in your example case would be logical, but not really worth the
effort given that in almost no real world code, the assignment to the
source pointer/reference is made in a place visible to the compiler at
the point of the cast, so it cannot check whether the conversion might
possibly succeed or not.
No, obviously not ;)

The problem is that the compiler can not *always* diagnose that.
Most compiler writers, and I am with them on that issue, think that
diagnosing a problem only *sometimes* creates a false sense of security.
Only if a potential problem can be analysed in each and every case, a
warning or an error is something to think about.
 

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,769
Messages
2,569,580
Members
45,054
Latest member
TrimKetoBoost

Latest Threads

Top