c++ 多重继承强制转换

Posted

技术标签:

【中文标题】c++ 多重继承强制转换【英文标题】:c++ multiple inheritance casting 【发布时间】:2011-11-17 01:07:52 【问题描述】:

我有一堂课:

class Base;

我还有一个界面

class Interface;

接下来我要创建一个类

class Derived : public Base, public Interface;

如果我有Base *object = new Derived;

如何将 object 转换为 Interface ? (当然,如果我知道 object 实际上是一个派生类)

编辑:

我尝试过 dynamic_cast 和 static_cast(未编译)。 所以让我再解释一下这个问题:

我有:

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 ...

对象有一个bool touchable_ 属性。如果为真,则对象正在实现 ITouchResponder 接口。

当我使用它时:

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;

asTouchResponderObject 的一个方法:

    ITouchResponder * Object::asTouchResponder()
    
        assert(touchable_);
        ITouchResponder *res = dynamic_cast<ITouchResponder*>(this);
        assert(res);
        return res;
    

我在 xcode 中有严重的过度错误。

但如果我让Object : public ITouchResponder 一切正常。我做错了什么?

完整的对象类:

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_;
;

【问题讨论】:

@vivek 不要在 C++ 代码中使用 c 类型转换。引入新语法是有原因的。 理想情况下,您可以使用纯虚拟公共接口,而无需通过调用接口指针上的方法进行转换,这些方法在派生类中被覆盖以执行适当的操作。 【参考方案1】:

您可以为此使用dynamic_cast&lt;Derived*&gt;(object),如果转换成功,您将返回Derived*,否则转换将返回NULL。如果 Base 是多态类型,则使用这种类型的转换,即。包含一个虚函数,如果不是这样,您可以使用static_cast&lt;Derived*&gt; 代替。

您的问题是您的Object 类没有从您的接口ITouchResponder 继承,因此您从Object 到您的接口的dynamic_cast 无效。您只能对相互继承的类进行 dynamic_cast,这就是多态性的全部目的,所以就像您在示例中建议的那样,您的 Object 类应该从您的接口公开继承。

基本上,您在这里进行了向上转换,ITouchResponder *res = dynamic_cast&lt;ITouchResponder*&gt;(this); 从 Derived 到 Base Interface,但是您的 Derived 并没有真正从您的接口派生,所以这就是它不起作用的原因。

【讨论】:

只有当 Base 是多态的时才有效(例如,通过具有虚函数)。当您完全确定时,一个 static_cast 是可以的,但是您应该再次想知道为什么您的确定没有在代码中表示为立即使用该类型。或者通过使用虚函数或访问者模式。 他说他知道这是派生的,所以他应该使用static_cast&lt;Derived&gt;(object),因为它产生的开销要少得多。 向我们展示你的'Object'基类,它里面有virtual函数吗? @Tony: 为什么我不能使用 Object obj = new Ball() 并将其转换为 ITouchResponder?球是 ITouchResponder【参考方案2】:

如果您确定该对象属于 Derived 类 - 使用 static_cast,否则使用 dynamic_cast 并检查结果。

【讨论】:

dynamic_cast 如果基础没有虚函数,则不会编译。 @Nawaz:是的,但是编译器会发出一个很好的错误消息,但是如果对象的类型错误并且编译器不会说一个字,static_cast 将导致 UB。所以这里的关键不是有虚函数而是知道对象的类型。【参考方案3】:

如果Basevirtual 函数(甚至是virtual 析构函数),那么:

Derived *pDerived = dynamic_cast<Derived *>(object);

否则,使用

Derived *pDerived = static_cast<Derived *>(object);

请注意,如果Base 没有虚函数,那么dynamic_cast 将不会编译。在dynamic_cast 中,只有源必须是多态对象才能编译,如果目标不是多态的,则 dynamic_cast 将返回空指针:

假设AB是多态类型,而C是非多态类型,那么

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;

【讨论】:

如果你明确dynamic_cast可能返回一个空指针会更好,而且由于你的帖子的主要改进是精确限制,可能值得注意的是跨越虚拟继承关系需要@ 987654334@(static_cast不能)。【参考方案4】:

有几种方法,但它们的影响不同:

Derived* derived = static_cast<Derived*>(object);

如果您在编译时知道它应该是正确的类型,请使用它。如果不可能,它不会在运行时失败,但会在编译时失败。

Derived* derived = dynamic_cast<Derived*>(object);

如果您不确定并希望运行时自动检查是否可行,请使用此选项。如果是,你会得到一个有效的指针,如果不是,你会得到一个 nullptr。知道 dynamic_cast 检查在时间性能上的成本很高,所以很多人有时会尽可能使用带有 type_info 指针作为键的关联容器,因为检查成本较低,但实际上它取决于上下文。要获取更多信息,请查找 typeid 关键字。

现在,也有 C 方式来执行此操作,但不推荐使用,因为尚不清楚编译器究竟会生成什么。至少通过这些以前的方式,您可以确切地知道代码应该如何表现。所以我就不赘述了。

【讨论】:

以上是关于c++ 多重继承强制转换的主要内容,如果未能解决你的问题,请参考以下文章

多重继承下的类型转换

C++ 子类化、继承和强制转换

C++ 继承和强制转换

基于继承的 C++ 强制转换

多重继承下的类型转换

C语言的多态是不是是类似于用结构指针的强制转换来实现的,具体实现方式类似于Linux万能链表???