c++ multiple inheritance casting
Solution 1
If Base
has virtual
function (even be it virtual
destructor), then:
Derived *pDerived = dynamic_cast<Derived *>(object);
Else, use
Derived *pDerived = static_cast<Derived *>(object);
Note that if Base
doesn't have virtual function, then dynamic_cast
will NOT compile. In dynamic_cast
, only the source has to be a polymorphic object, in order to compile, and if the destination isn't polymorphic, then dynamic_cast will return null pointer:
Suppose A
and B
are polymorphic type, and C
is non-polymorphic, then
A *pA = dynamic_cast<A*>(new C()); //error - source is not polymorphic!
A *pA = dynamic_cast<A*>(new B()); //ok
if ( pA == 0 )
cout << "pA will be null if B is not derived from A" << endl;
C *pC = dynamic_cast<C*>(new B()); //ok
if ( pC == 0 )
cout << "pC must be null" << endl;
Solution 2
If you know for sure that the object is of Derived
class - use static_cast
, otherwise use dynamic_cast
and check the result.
Solution 3
You can use dynamic_cast<Derived*>(object)
for that, and if the cast succeeds you'll get a Derived*
returned, else the cast will return NULL. You use this type of cast if Base is a polymorphic type, ie. contains a virtual function, and if this is not the case, you can use a static_cast<Derived*>
instead.
Your problem is that you have an Object
class that does not inherit from your interface ITouchResponder
and therefore your dynamic_cast
from Object
to your interface is invalid. You can only do a dynamic_cast on classes that inherit from one another, that's the whole purpose of polymorphism, so like you suggested in your example, your Object
class should inherit publicly from your interface.
Essentially, you're doing an upcast here, ITouchResponder *res = dynamic_cast<ITouchResponder*>(this);
from Derived to Base Interface, however your Derived doesn't really derive from your interface, so that's why it doesn't work.
Solution 4
There are several ways but they don't have the same impact :
Derived* derived = static_cast<Derived*>(object);
Use this one if you know at compile time that it should be of the correct type. It will not fail at runtime if it's not possible but will at compile time.
Derived* derived = dynamic_cast<Derived*>(object);
Use this if you're not sure and want the runtime to automatically check if it's possible. If it is you'll get a valid pointer, if not you'll get a nullptr. Know that dynamic_cast<> checks are costly in time performance so a lot of people sometimes use associative containers with type_info pointers as key, where possible, because the check is less costly, but really it depends on the context. To get more infos, look for the typeid keyword.
Now, there is also the C way of doing it but it's not recommanded because it's not clear what exactly will the compiler generated. At least with those previous ways you know exactly how the code should behave. So I'll not describe it.
Andrew
Software Development Engenier, Microsoft http://ru.linkedin.com/pub/andrew-vorobyev/48/2b2/bab
Updated on June 17, 2022Comments
-
Andrew about 2 years
I have a class:
class Base;
Also I have an interface
class Interface;
Next i'm creating a class
class Derived : public Base, public Interface;
If I have
Base *object = new Derived;
How can i cast
object
toInterface
? (of course if i know than object is actually a derived class)EDIT:
I've tried dynamic_cast and static_cast (not compiled). So let me explain the problem a bit more:
I have:
class Object {...} class ITouchResponder { public: virtual bool onTouchBegan(XTouch *touch) = 0; virtual void onTouchMoved(XTouch *touch) = 0; virtual void onTouchEnded(XTouch *touch) = 0; }; class Ball : public Object, public ITouchResponder {...}; class TentacleSensor : public Object, public ITouchResponder {...}
Object have a
bool touchable_
property. If it's true then object is implementing ITouchResponder interface.When I use it:
bool Level::onTouchBegan(XTouch *touch) { ... ITouchResponder *responder = callback.nearestTouchable(); if (responder) { if (responder->onTouchBegan(touch)) { if (responder != ball_) { touch->setUserData(responder); } } } return true; } ITouchResponder *QueryCallback::nearestTouchable() const { for (list<Object*>::const_iterator it = objects_.begin(); it != objects_.end(); ++it) { if ( (*it)->isTouchable() ) return (*it)->asTouchResponder(); } return 0; }
asTouchResponder
is a method ofObject
:ITouchResponder * Object::asTouchResponder() { assert(touchable_); ITouchResponder *res = dynamic_cast<ITouchResponder*>(this); assert(res); return res; }
I have bad excess error in xcode.
But if i make
Object : public ITouchResponder
everything works fine. What am i doing wrong ?Full object class:
class Object// : public ITouchResponder { public: struct Def { Def() { level = 0; world = 0; touchable = false; acceptsContacts = false; body = 0; node = 0; } Level *level; b2World *world; bool touchable; bool acceptsContacts; b2Body *body; XNode *node; }; Object(const Def &def); virtual ~Object(); virtual void update(float dt); bool isTouchable() const {return touchable_;} void addDependantObject(Object *object); void removeDependantObject(Object *object); virtual void objectWillBeRemoved(Object *object) {} //this function is automatically called to every dependant object when object is removed virtual XVec2 position() const; virtual float rotation() const; bool acceptsContacts() const {return acceptsContacts_;} b2Body *body() const {return body_;} Level *level() const {return level_;} b2World *world() const {return world_;} ITouchResponder *asTouchResponder(); /* virtual bool onTouchBegan(XTouch *touch) { return false; } virtual void onTouchMoved(XTouch *touch) { } virtual void onTouchEnded(XTouch *touch) { }*/ protected: Level *level_; b2World *world_; bool touchable_; bool acceptsContacts_; XNode *node_; b2Body *body_; list<Object*> dependantObjects_; };
-
PlasmaHH almost 13 yearsThat only works when the Base is polymorphic (e.g. by having a virtual function). When you are totally sure, a static_cast is ok, but then again you should wonder why your being sure is not expressed in the code as using the type right away. Or by using virtual functions or the visitor pattern.
-
RedX almost 13 yearsHe says he knows it's a Derived so he should use
static_cast<Derived>(object)
since it incurs in much less overhead. -
Nawaz almost 13 years
dynamic_cast
will not compile if the base has not virtual function. -
sharptooth almost 13 years@Nawaz: True, but the compiler will emit a nice error message, yet static_cast will lead to UB if the object if of the wrong type and the compiler won't say a word. So here the key is not having virtual functions but knowing the type of the object.
-
Matthieu M. almost 13 yearsIt would be even better if you precised that
dynamic_cast
may return a null pointer, also since the main improvement of your post is precising limitations, it may be worth noting that crossing virtual inheritance relationship requiresdynamic_cast
(static_cast
cannot). -
Tony The Lion almost 13 yearsShow us your 'Object' base class, does it have
virtual
functions inside? -
Andrew almost 13 years@Tony: Why can't i use Object obj = new Ball() and cast it to ITouchResponder? The Ball is ITouchResponder