Russell
Russell

Reputation: 4085

Real world example of dynamic_cast in C++

Can anybody give me a real world example of a case when dynamic_cast is needed and can't be worked around at all? Examples I can think of can generally be worked around with double dispatch.

If the constraint is too strong, an example where dynamic_cast is generally the way to go would also be nice.

I'd like to see real examples instead of "it's normally used to cast between types up and down a type tree".

Upvotes: 13

Views: 4500

Answers (5)

Bjarke H. Roune
Bjarke H. Roune

Reputation: 3727

You can often replace dynamic_cast<A*>(...) by adding a virtual function to A. However, if A is a class from a third party library then you can't change it so you can't add a virtual function to it. So you may have to use dynamic_cast.

Upvotes: 0

Chad
Chad

Reputation: 19032

Let's say we have a library that we're using that is meant for us to derive some types from:

class A {};
class B : public A {};
class C : public B {};

And when we're deriving our types, we have some things that are common to all of our cases:

class CommonStuff {};
class D : public CommonStuff, public C {};

Now, as we're working with our library, and there is a callback that takes type A& (or B& or C&)

void some_func(A& obj);

And assume in that function it expects polymorhpic behavior, but we need to access some of our CommonStuff:

void some_func(A& obj)
{
    CommonStuff& comn = dynamic_cast<CommonStuff&>(obj);
}

Since there's no direct correlation between A and CommonStuff, we cannot use static_cast, reinterpret_cast is obviously not the right choice as it will introduce slicing. The only option here is dyanmic_cast.

Now, take this with a grain of salt, because this could be worked around.

Upvotes: 0

Cheers and hth. - Alf
Cheers and hth. - Alf

Reputation: 145224

The constraint "can't be worked around at all" is too strong. Any C++ feature can be emulated in C. All you have to do to work around the feature, so to speak, is to use that C code in C++. For example, MFC, a library originating from the depths of time before the 1998 language standardization, offered and still offers its own kind of dynamic cast.

One example where you generally need dynamic casting is the visitor pattern, e.g. as used for event handling. The idea of visitation is to centralize the dynamic casting, so that instead of a zillion dynamic casts peppered throughout the code, there is a single one:

#include <stdio.h>

void say( char const s[] ) { printf( "%s\n", s ); }

struct Event
{
    struct Handler
    {
        virtual void onEvent( Event& ) = 0;
    };

    virtual void dispatchTo( Handler& aHandler )
    {
        aHandler.onEvent( *this );
    }

    template< class SpecificEvent >
    static void dispatch( SpecificEvent& e, Handler& aHandler )
    {
        typedef typename SpecificEvent::Handler SpecificHandler;

        // The single dynamic cast:
        if( SpecificHandler* p = dynamic_cast<SpecificHandler*>( &aHandler ) )
        {
            p->onEvent( e );
        }
        else
        {
            e.Event::dispatchTo( aHandler );
        }
    }
};

struct FooEvent
    : Event
{
    struct Handler
    {
        virtual void onEvent( FooEvent& ) = 0;
    };

    virtual void dispatchTo( Event::Handler& aHandler )
    {
        dispatch( *this, aHandler );
    }
};

struct Plane
    : Event::Handler
{
    virtual void onEvent( Event& ) { say( "An event!" ); }
};

struct Fighter
    : Plane
    , FooEvent::Handler // Comment out this line to get "An event!".
{
    virtual void onEvent( FooEvent& ) { say( "Foo Fighter!" ); }
};

void doThingsTo( Plane& aPlane )
{
    FooEvent().dispatchTo( aPlane );
}

int main()
{
    Fighter plane;

    doThingsTo( plane );
}

The output of this program is Foo Fighter!.

As mentioned, this is simplified. Reality has a tendency to be a bit more messy. And with far more code.

Cheers & hth.

Upvotes: 1

MGZero
MGZero

Reputation: 5963

I personally use it for working through certain parts of my game engine. I have a base entity class from which I derive various other entities from. I cast them to the base class type so I can store them easily into a linked list. When I want to check to see if a particular entry in my list is of a certain entity, I dynamic_cast it to that type. If it returns null, then I know it's not.

Upvotes: 0

Billy ONeal
Billy ONeal

Reputation: 106530

Double dispatch requires that the types that are interacting have intimate knowledge of each other's innards, as it requires that one class call methods on the other class. dynamic_cast works when you cannot modify the innards of a class, or do not wish to break encapsulation of the classes in question.

That is, double dispatch is invasive on the classes involved, while dynamic_cast works without knowledge of the cast in the classes.

You can also use dynamic_cast if you don't know the target method overload which will be invoked. For an example, see this question I posted yesterday.

Finally, double dispatch does not come without it's own headaches

The base class Shape must know about all the derived classes, resulting in circular dependencies. If you derive a new class from Shape (say Triangle), you must update the interface of Shape and the interface/implementation of all the other derived classes. In some cases this is not even an option: you may not have the source code for Shape, or not be willing or permitted to modify it.

Upvotes: 6

Related Questions