C ++ dynamic_cast - 多态需求和向下转换

时间:2011-01-10 08:03:27

标签: c++ dynamic-cast downcast

在下面的代码中,在案例1中构造obj时,我们也构造了一个derived类对象,但它的成员函数对于obj是不可访问的。因此,在向下转换(即在案例2中)时,使用obj作为源,我们已经构建了derived。为什么obj需要多态?

如果我把我与上面的描述混淆了,为什么{$ 1}}在向上转换时不需要是多态的,但在向下转换时 在使用{{1}时需要是多态的}?

obj

4 个答案:

答案 0 :(得分:18)

为了使 dynamic_cast 工作,对象需要是多态的。这样做的原因是 dynamic_cast 需要某处存储将用于执行强制转换的类型信息,并且它通过将信息存储在类的vtable旁边来实现。为了有一个vtable,你需要至少有一个虚拟方法。

最简单的方法是将基类析构函数标记为虚拟。

Upcasting(即派生到base)不需要强制转换,因为编译器能够检查强制转换是否可以在编译时工作。然而,在向下转型时也是如此。

答案 1 :(得分:6)

来自5.2.7 / 1 [expr.dynamic.cast]:

  

表达式dynamic_cast<T>(v)的结果是将表达式v转换为type的结果   吨。

     

[...]

     

如果T是“指向 cv1 B的指针”并且v具有类型“指向 cv2 D的指针”,那么B是D的基类,结果是   指向v。

指向的D对象的唯一B子对象的指针      

[...]

     

否则,v应为多态类型的指针或左值。

该标准甚至提供了以下示例,该示例说明多态类型要求不代表派生到基本转换:

struct B {};
struct D : B {};
void foo(D* dp)
{
    B* bp = dynamic_cast<B*>(dp); // equivalent to B* bp = dp;
}

答案 2 :(得分:0)

的dynamic_cast

  • 用于投射基础指针 进入派生指针。如果基地 指针不指向对象 派生的类型,它返回
  • 用于投射基准参考 到派生的参考。如果 引用不指向对象 它的派生,它抛出 的std :: bad_cast。
  • 可以认为是经过检验的演员表 相当于static_cast,因为它 检查对象是否指向 真的是衍生类型。

您必须详细了解Dynamic_cast(示例)there

答案 3 :(得分:0)

class car
{
    public:
    virtual void drive()
    {
         std::cout <<"car"<<std::endl;
    }
};
class toyota: public car
{
    public:
    virtual void drive()
    {
        std::cout <<"toyota"<<std::endl;
    }
};

class honda: public car
{
    public:
        virtual void drive()
    {
        std::cout <<"honda"<<std::endl;
    }
};

template <typename Tderived>
Tderived* dynamicCast(void* pBase)
{
    //compare the vptr of the class pointed by pBase with a temporary Tderived class. 
    //If vptr of pBase and vptr of Tderived() are pointing to the same vtable 
    //then it can be safely deduced that pBase is indeed pointing to an instance of Tderived
    if (*(int**)pBase == *(int**)&Tderived())
    {
        return (Tderived*)pBase;
    }
    else
    {
        return nullptr;
    }
}


int main()
{
    car* pCar;
    honda hondaCar;
    toyota toyotaCar;

    pCar = &toyotaCar;

    honda* pHonda = dynamicCast<honda>(pCar);
    if (nullptr != pHonda)
    {
        pHonda->drive();
    }
    else
    {
        toyota* pToyota = dynamicCast<toyota>(pCar);
        if (nullptr != pToyota)
        {
            pToyota->drive();
        }
    }
}

在上面的例子中,大多数编译器会通过检查b的vtable指针是否指向派生类D的vtable来实现动态强制转换。 如果是,它只返回b的地址作为返回值,否则返回nullptr。 这是动态演员执行时幕后可能发生的事情: -

{{1}}

现在,如果该类不是多态的,那么编译器无法找到pCar是指向本田还是丰田汽车。请注意,这只是实现dynamic_cast的方法之一,因为C ++标准没有谈论任何关于vtable的内容。