I read many articles on Web regarding this. I am able to understand what static_cast does. I am not to properly understand why, and when we have to dynamic cast. There is
something "we can downcast the pointer when it is polymorphic". I am not able to understand what they meant by this. Can anyone please explain with one good example?

In short, Use of static cast and dynamic cast? Any help would be appreciated. Thanks in advance.

Recommended Answers

All 7 Replies

I am not to properly understand why, and when we have to dynamic cast.

Strictly speaking, you don't ever have to use dynamic_cast. You can use dynamic_cast when the castee is a pointer or reference to a class that contains at least one virtual member (that's what's meant by the pointer being polymorphic).

The reason that you should use dynamic_cast over static_cast (when downcasting) is that dynamic_cast will throw an exception when the pointed-to object does not actually have the correct type, whereas static_cast would invoke undefined behavior in that case.

@sepp2k

Class A is a base class. Class B is derived.

Base b;
    Derived d;

    Base *pb = dynamic_cast<Base*>(&d);          
    Derived *pd = dynamic_cast<Derived*>(&b); 

And, this one. Employee is base class.

Employee employee;
    Programmer programmer;

    // upcast - implicit upcast allowed
    Employee *pEmp = &programmer;

    // downcast - explicit type cast required
    Programmer *pProg = (Programmer *)&employee;

What is the difference between this thing now?

Please explain: why do we need to have base class' at least one virtual function? Why is it so?

Thanks.

Base *pb = dynamic_cast<Base*>(&d);

This is an upcast. Using dynamic_cast here is pointless as the cast is always valid. You can and should just write it as Base *pb = &d.

Derived *pd = dynamic_cast<Derived*>(&b);

Since b is an actual Base object, not a Derived object, this downcast is invalid and will throw an exception.

Programmer *pProg = (Programmer *)&employee;

This is the same invalid downcast, but since you're not using dynamic_cast, it invokes undefined behavior rather than throwing an exception.

Thanks Sepp2k. But what is valid dynamic_cast then in case of downcast? Can you tell this thing?

Secondly, Can you explain this line?

You can use dynamic_cast when the castee is a pointer or reference to a class that contains at least one virtual member (that's what's meant by the pointer being polymorphic)

Programmer *pProg = (Programmer *)&employee;

A downcast is valid if the object to which the pointer points actually is of the type to which you cast.

Secondly, Can you explain this line?

What did you not understand about that line?

Oh, I seem to have missed a question earlier:

Please explain: why do we need to have base class' at least one virtual function? Why is it so?

Technical reasons. Namely to implement dynamic_cast, you need some kind of metadata associated with an object in order to tell whether the object has the correct type. Classes without virtual functions are not supposed to have any overhead like metadata (both for C compatibility and performance reasons), so they don't have the necessary metadata. Classes with virtual functions need metadata anyway (namely the vtable), so adding the information for the type check makes little difference (if it even needs anything besides the vtable - I'm not sure on that one).

this downcast is invalid and will throw an exception.

Actually, it won't. Invalid downcasts only throw a std::bad_cast if you use references (because you can't have a null reference). If you are casting to a pointer type, such as Derived*, the resulting pointer will be null (nullptr) and no exception is thrown.

But what is valid dynamic_cast then in case of downcast? Can you tell this thing?

This would be a simple example of a valid dynamic-cast, if you assume that Base is a base-class of Derived, and that Base has at least one virtual member function:

Derived d;      // 'd' is a 'Derived' object

Base* pb = &d;  // 'pb' points to 'd', but thinks it's of type `Base`

Derived* pd = dynamic_cast<Derived*>(pb);

where the dynamic-cast is valid because even though pb thinks it's pointing to a Base object, it is actually pointing to a Derived object, and therefore, casting that pointer down to a Derived pointer is valid.

In more complicated cases, you might not actually be sure whether a Base* pointer actually points to a Derived object, and using dynamic_cast allows you to check that before the cast is performed. Normally, after a dynamic_cast, you should always have an if-statement (or some other check) to see if the resulting pointer is null or not (or, if you are using references, then you need a try-catch block to catch the std::bad_cast exception). Basically, if you don't need to check that the dynamic-cast succeeded, then you don't need a dynamic-cast at all, you can just use static_cast instead, but if you do use dynamic_cast, then there should be a check immediately following it. This is actually a classic "red flag" in code reviews, i.e., if you see a dynamic_cast without a check for null pointer or a try-catch block, it is a mistake, one way or another.

What is the difference between this thing now?

Base *pb = dynamic_cast<Base*>(&d);

This is an "up-cast" (from derived to base). This happens implicitely, and should not require any special casting syntax. It would work with Base* pb = &d;. When using a dynamic_cast here, the compiler will "degenerate it" to the same behavior as the implicit cast. By "degenerate", I just mean that dynamic_cast is generally a complicated cast (as it checks the types of the object pointed to), but those complications are useless when doing an up-cast, because it's guaranteed to work and can be worked out by the compiler, so, the "complicated" dynamic-cast down-grades to a very trivial static-cast.

Derived *pd = dynamic_cast<Derived*>(&b); 

This attempts to cast a pointer to b (which is a Base object) to a Derived* pointer. When the dynamic_cast checks that the object pointed to by &b is actually of type Derived (or an even more derived type thereof), that check will fail and the pointer that is returned will be nullptr.

Employee *pEmp = &programmer;

This is an implicit up-cast. This is the normal way to do up-casts.

Programmer *pProg = (Programmer *)&employee;

This is a "C-style cast" that will cast a pointer to the employee object to a pointer to a Programmer object. A "C-style cast" should be avoided in C++ because it can sometimes be ambiguous about what C++ cast it corresponds to (and thus, how it will behave in certain special cases). Most compilers will warn you about using C-style casts. In this case, the cast will be equivalent to a static_cast, which means that the down-cast is performed without any check that the pointed to object can actually be cast to that derived type. Any use of the pProg pointer after this line will be undefined behavior (meaning, anything can happen, i.e., the code is completely invalid). This is why you never use static_cast for a down-cast unless you are 100% sure that doing a dynamic_cast will always work.

why do we need to have base class' at least one virtual function? Why is it so?

Like sepp2k explained, it's because the general ideology of C++ is that you only pay for what you use. When you create simpler and leaner classes that don't have virtual functions, which is generally done for performance reasons, then you should not have to pay a tax for a feature you will never use (you would never need to use dynamic_cast on such classes). But when you create a "polymorphic" class with virtual functions, you are already paying a price for that, usually in the form of an additional hidden pointer in the objects that point to a class' virtual table. In that case, adding the information necessary to be able to use dynamic_cast is not a significant additional overhead.

if it even needs anything besides the vtable - I'm not sure on that one

As far as I know, the dynamic-cast checks are usually implemented through the RTTI (run-time type identification), which is the same as what you get with the typeid / type_info stuff. Unless compiler vendors are out of their minds, this is usually implemented with an additional entry in the virtual table that points to a function that is basically equivalent to typeid (returns the type_info object for the most derived type of the object) or that points directly to the relevant type_info object. There is basically one global (singleton) type_info object for each polymorphic class.

All of this overhead is the reason why RTTI is often disabled in some projects, which means that you cannot use dynamic_cast or typeid or any other mechanism that relies on the RTTI. In a typical project, the RTTI adds between 5% to 15% to the size of your executables or libraries. People either disable it because (1) it's too much overhead and can be avoided (e.g., embedded code), (2) it can be replaced by something simpler or more efficient (e.g., LLVM), or (3) it can be replaced by something more feature-rich (e.g., my library uses a custom RTTI to provide some limited run-time reflection capabilities).

commented: Thanks for filling in the blanks and the correction. +8
Be a part of the DaniWeb community

We're a friendly, industry-focused community of developers, IT pros, digital marketers, and technology enthusiasts meeting, networking, learning, and sharing knowledge.