2011-09-14 170 views
14

我有一个类:C++多重继承铸造

class Base; 

另外我有一个接口

class Interface; 

接下来,我创建一个类

class Derived : public Base, public Interface; 

如果我有Base *object = new Derived;

我该如何投objectInterface? (当然,如果我知道的比对象实际上是一个派生类)

编辑:

我试过的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_; 
}; 
+0

(派生*)对象 – vivek

+2

@vivek不要在C++代码中使用c转换。为什么引入新的语法是有原因的。 – RedX

+0

理想情况下,您可以使用纯虚拟公共接口,而无需通过调用派生类中重写的接口指针上的方法进行投射,以执行适当的操作。 – AJG85

回答

8

如果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; 
+0

如果您精确地说'dynamic_cast'可能会返回空指针会更好,因为您的文章的主要改进是精确限制,可能值得注意的是跨越虚拟继承关系需要'dynamic_cast'('static_cast'不能)。 –

+0

@Matthieu:已经在编辑的答案中完成了。 – Nawaz

+0

@Nawaz:请参阅我的编辑 – Andrew

4

您可以使用dynamic_cast<Derived*>(object)为,如果转换成功,你会得到一个Derived*返回,否则投将返回NULL。如果Base是多态类型,则使用此类型转换。包含虚拟功能,如果不是这种情况,则可以使用static_cast<Derived*>代替。

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

本质上,你在这里做一个上传,ITouchResponder *res = dynamic_cast<ITouchResponder*>(this);从派生到基本接口,但是你的派生并不真正从你的接口派生,所以这就是为什么它不起作用。

+3

只有当基础是多态时(例如,通过具有虚拟功能)才能起作用。当你完全确定的时候,一个static_cast是可以的,但是你应该再次怀疑为什么你的代码没有在代码中表达为马上使用类型。或者通过使用虚拟功能或访问者模式。 – PlasmaHH

+1

他说他知道它是派生的,所以他应该使用'static_cast (object)',因为它的开销要小得多。 – RedX

+0

托尼:请参阅我的编辑 – Andrew

8

如果您确实知道对象是Derived class - 请使用static_cast,否则请使用dynamic_cast并检查结果。

+1

如果基地没有虚拟功能,'dynamic_cast'将不会编译。 – Nawaz

+2

@Nawaz:是的,但编译器会发出一个很好的错误信息,但如果对象是错误的类型和编译器不会说一个字,static_cast将导致UB。所以这里的关键是没有虚函数,但知道对象的类型。 – sharptooth

+0

@sharptooth:请参阅我的编辑 – Andrew

3

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

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

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

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

使用这个,如果你不知道,想在运行时自动检查是否有可能。如果是的话,你会得到一个有效的指针,如果没有,你会得到一个nullptr。知道dynamic_cast <>检查在时间表现上代价高昂,所以很多人有时会使用带有type_info指针的关联容器作为关键字,因为检查成本较低,但实际上取决于上下文。要获得更多信息,请查找typeid关键字。

现在,也有C的方式做到这一点,但它不被推荐,因为它不清楚编译器生成的究竟是什么。至少通过以前的方式,您可以确切知道代码的行为方式。所以我不会描述它。

+0

@请参阅我的编辑 – Andrew