开发者

c++ multiple inheritance casting

开发者 https://www.devze.com 2023-04-04 15:54 出处:网络
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;

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.

0

精彩评论

暂无评论...
验证码 换一张
取 消

关注公众号