Geo
Geo

Reputation: 96767

C++ casting programmatically : can it be done?

Let's say I have a Base class and several Derived classes. Is there any way to cast an object to one of the derived classes without the need to write something like this :


string typename = typeid(*object).name();
if(typename == "Derived1") {
   Derived1 *d1 = static_cast< Derived1*>(object);
}
else if(typename == "Derived2") {
   Derived2 *d2 = static_cast < Derived2*>(object);
}
...
else {
  ...
}

Upvotes: 5

Views: 1186

Answers (8)

S.Lott
S.Lott

Reputation: 391818

Don't.

Read up on polymorphism. Almost every "dynamic cast" situation is an example of polymorphism struggling to be implemented.

Whatever decision you're making in the dynamic cast has already been made. Just delegate the real work to the subclasses.

You left out the most important part of your example. The useful, polymorphic work.

string typename = typeid(*object).name();
if(typename == "Derived1") {
   Derived1 *d1 = static_cast< Derived1*>(object);
   d1->doSomethingUseful();
}
else if(typename == "Derived2") {
   Derived2 *d2 = static_cast < Derived2*>(object);
   d2->doSomethingUseful();
}
...
else {
  ...
}

If every subclass implements doSomethingUseful, this is all much simpler. And polymorphic.

object->doSomethingUseful();

Upvotes: 22

ChrisN
ChrisN

Reputation: 16933

You can do this using dynamic_cast, e.g:

if ( Derived1* d1 = dynamic_cast<Derived1*>(object) ) {
    // object points to a Derived1
    d1->foo();
}
else if ( Derived2* d2 = dynamic_cast<Derived2*>(object) ) {
    // object points to a Derived2
    d2->bar();
}
else {
    // etc.
}

But as others have said, code such as this can indicate a bad design, and you should generally use virtual functions to implement polymorphic behaviour.

Upvotes: 4

Malkocoglu
Malkocoglu

Reputation: 2601

I think dynamic_cast is the way to go, but I don't particularly think this is a bad design for all possible conditions because object to be casted may be something provided by some third-party module. Let's say object was created by a plug-in that the application author has no knowledge of. And that particular plug-in may create Derived1 (being the old version) type object or Derived2 (being the new version) type object. Maybe the plug-in interface was not designed to do version specific stuff, it just creates the object so the application must do this kind of checking to ensure proper casting/execution. After this, we can safely call object.doSomethingUsefulThatDoesNotExistInDerived1();

Upvotes: 1

marijne
marijne

Reputation: 3060

Derived1* d1 = dynamic_cast< Derived1* >(object);
if (d1 == NULL)
{
    Derived2* d2 = dynamic_cast< Derived2* >(object);
    //etc
}

I have the following methods on my smartpointer type, simulating C# 'is' and 'as':

template< class Y > bool is() const throw()
    {return !null() && dynamic_cast< Y* >(ptr) != NULL;}
template< class Y > Y* as() const throw()
    {return null() ? NULL : dynamic_cast< Y* >(ptr);}

Upvotes: 5

Rik
Rik

Reputation: 29243

What are you trying to accomplish, exactly? In my experience, things like this are a sign of bad design. Re-evaluate your class hierarchy, because the goal of object oriented design is make things like this unnecessary.

Upvotes: 2

fhe
fhe

Reputation: 6187

You can use dynamic_cast and test for NULL, but I'd strongly consider refactoring the code instead.

If you need subclass-specific handling, Template Method might be helpful, but without knowing what you're trying to achive, it's only a vague guess.

Upvotes: 9

fizzer
fizzer

Reputation: 13786

Your example won't port, because the exact format of name() isn't specified. You could try a succession of dynamic_casts. Dynamic_cast returns a null pointer if you cast to the wrong type. However, if you're doing a typeswitch like this one, there's something wrong with your design.

Upvotes: 1

moogs
moogs

Reputation: 8202

usually, this is a sign of a bad design. Why do you need to do this? It might be possible to redesign so that this is not needed.

Upvotes: 3

Related Questions