c++ multiple inheritance casting
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
to Interface
? (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 of Object
:
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_;
};
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;
If you know for sure that the object is of Derived
class - use static_cast
, otherwise use dynamic_cast
and check the result.
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.
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.
精彩评论