type-id 必须是针对以前定义的类类型的指针或引用,或者是“指向 void 的指针”。 如果 type-id 是指针,则 expression 类型必须为指针,或者如果 type-id 是引用,则为左值。

请参阅 static_cast ,了解静态转换和动态强制转换转换之间的差异,以及何时适合使用每个转换转换。

托管代码中的 dynamic_cast 行为有两项中断性变更:

  • 对指向装箱枚举的基础类型的指针的 dynamic_cast 将在运行时失败,返回 0 而不是转换后的指针。

  • dynamic_cast 当 是指向值类型的内部指针时 type-id ,将不再引发异常;相反,强制转换在运行时会失败。 强制转换返回 0 指针值,而不是引发。

    如果 type-id 是指向 的明确可访问的直接或间接基类的 expression 指针,则指向 类型 type-id 的唯一子对象的指针是结果。 例如:

    // dynamic_cast_1.cpp
    // compile with: /c
    class B { };
    class C : public B { };
    class D : public C { };
    void f(D* pd) {
       C* pc = dynamic_cast<C*>(pd);   // ok: C is a direct base class
                                       // pc points to C subobject of pd
       B* pb = dynamic_cast<B*>(pd);   // ok: B is an indirect base class
                                       // pb points to B subobject of pd
    

    此类转换称为“向上转换”,因为它将指针从派生类向上移动至派生自的类。 向上转换是一种隐式转换。

    如果 type-id 是 void*,则进行运行时检查以确定 expression 的实际类型。 结果是指向由 expression 指向的完整对象的指针。 例如:

    // dynamic_cast_2.cpp
    // compile with: /c /GR
    class A {virtual void f();};
    class B {virtual void f();};
    void f() {
       A* pa = new A;
       B* pb = new B;
       void* pv = dynamic_cast<void*>(pa);
       // pv now points to an object of type A
       pv = dynamic_cast<void*>(pb);
       // pv now points to an object of type B
    

    如果 type-id 不是 void*,则进行运行时检查,以查看是否可以将 指向 expression 的对象转换为 由 type-id指向的类型。

    如果 expression 的类型是 type-id 类型的基类,则进行运行时检查,看看 expression 是否实际指向 type-id 类型的完整对象。 如果是,则结果是指向 type-id 类型的完整对象的指针。 例如:

    // dynamic_cast_3.cpp
    // compile with: /c /GR
    class B {virtual void f();};
    class D : public B {virtual void f();};
    void f() {
       B* pb = new D;   // unclear but ok
       B* pb2 = new B;
       D* pd = dynamic_cast<D*>(pb);   // ok: pb actually points to a D
       D* pd2 = dynamic_cast<D*>(pb2);   // pb2 points to a B not a D
    

    这种类型的转换称为“向下转换”,因为它将指针向下移动一个类层次结构,从给定类移至从中派生的类。

    如果有多重继承,可能会导致不明确。 来看看下图中显示的类层次结构。

    对于 CLR 类型,如果可以隐式执行转换,则 dynamic_cast 会导致无操作,或者执行 MSIL isinst 指令,该指令执行动态检查并在转换失败时返回 nullptr

    以下示例使用 dynamic_cast 来确定类是否是特定类型的实例:

    // dynamic_cast_clr.cpp
    // compile with: /clr
    using namespace System;
    void PrintObjectType( Object^o ) {
       if( dynamic_cast<String^>(o) )
          Console::WriteLine("Object is a String");
       else if( dynamic_cast<int^>(o) )
          Console::WriteLine("Object is an int");
    int main() {
       Object^o1 = "hello";
       Object^o2 = 10;
       PrintObjectType(o1);
       PrintObjectType(o2);
    此图显示了一个类层次结构,其中 A 作为 B 的基类,B 是 D 的基类。也是 C 的基类,C 是 D 的基类。类 D 继承自 B 和 C。

    指向 D 类型对象的指针可以安全地强制转换为 BC。 但是,如果 D 强制转换为指向 A 对象的指针,会产生 A 的哪个实例? 这将导致不明确的强制转换错误。 若要解决此问题,可以执行两个明确的强制转换。 例如:

    // dynamic_cast_4.cpp
    // compile with: /c /GR
    class A {virtual void f();};
    class B : public A {virtual void f();};
    class C : public A {virtual void f();};
    class D : public B, public C {virtual void f();};
    void f() {
       D* pd = new D;
       A* pa = dynamic_cast<A*>(pd);   // C4540, ambiguous cast fails at runtime
       B* pb = dynamic_cast<B*>(pd);   // first cast to B
       A* pa2 = dynamic_cast<A*>(pb);   // ok: unambiguous
    

    使用虚拟基类时,可能会导致更多不明确的情况。 来看看下图中显示的类层次结构。

    此图显示按如下方式排列的类 A、B、C、D 和 E 类:类 A 是 B 的基类。类 C 和 E 分别派生自 B。类 E 也继承自 D,后者继承自类 B,后者继承自类 A。

    显示虚拟基类的类层次结构

    在此层次结构中,A 是一个虚拟基类。 给定类 E 的实例和指向 A 子对象的指针, dynamic_cast 指向 的 B 指针由于不明确而失败。 必须首先转换回完整的 E 对象,然后以明确的方式备份层次结构,才能访问正确的 B 对象。

    来看看下图中显示的类层次结构。

    此图显示按如下方式排列的类 A、B、C、D 和 E 类:类 B 派生自类 A。类 C 派生自类 A。类 D 派生自类 B。类 E 派生自类 C,后者派生自类 A。在这种情况下,重复的基类是类 A,它直接或间接由所有其他类继承。 类 A 由类 B 和 C 直接继承,类 D 通过类 B 间接继承,类 E 通过类 C 间接继承,类 D 通过类 B 间接继承。

    显示重复基类的类层次结构

    在给定 E 类型对象和指向 D 子对象的指针的情况下,若要从 D 子对象导航到最左侧的 A 子对象,可以进行三次转换。 可以执行从 D 指针到 E 指针的 dynamic_cast 转换,然后执行从 EB 的转换(可以是 dynamic_cast,也可以是隐式转换),最后执行从 BA 的隐式转换。 例如:

    // dynamic_cast_5.cpp
    // compile with: /c /GR
    class A {virtual void f();};
    class B : public A {virtual void f();};
    class C : public A { };
    class D {virtual void f();};
    class E : public B, public C, public D {virtual void f();};
    void f(D* pd) {
       E* pe = dynamic_cast<E*>(pd);
       B* pb = pe;   // upcast, implicit conversion
       A* pa = pb;   // upcast, implicit conversion
    

    运算符dynamic_cast还可用于执行“交叉强制转换”。使用同一类层次结构,只要完整对象的类型E为 ,就可以将指针从BD对象强制转换为子对象。

    考虑到交叉强制转换,只需执行两个步骤即可从指针转换为 D 指向最 A 左侧子对象的指针。 可以执行从 DB 的交叉强制转换,然后从 BA 的隐式转换。 例如:

    // dynamic_cast_6.cpp
    // compile with: /c /GR
    class A {virtual void f();};
    class B : public A {virtual void f();};
    class C : public A { };
    class D {virtual void f();};
    class E : public B, public C, public D {virtual void f();};
    void f(D* pd) {
       B* pb = dynamic_cast<B*>(pd);   // cross cast
       A* pa = pb;   // upcast, implicit conversion
    

    一个空指针值通过 dynamic_cast 转换为目标类型的空指针值。

    使用 dynamic_cast < type-id > ( expression )时,如果expression无法安全地转换为类型type-id,则运行时检查会导致强制转换失败。 例如:

    // dynamic_cast_7.cpp
    // compile with: /c /GR
    class A {virtual void f();};
    class B {virtual void f();};
    void f() {
       A* pa = new A;
       B* pb = dynamic_cast<B*>(pa);   // fails at runtime, not safe;
       // B not derived from A
    

    未能强制转换为指针类型的值是空指针。 如果对引用类型的强制转换失败,会引发 bad_cast 异常。 如果未 expression 指向或引用有效对象, __non_rtti_object 则会引发异常。

    有关 __non_rtti_object 异常的说明,请参阅 typeid

    下面的示例创建了基类(结构 A)指针,指向一个对象(结构 C)。 这一点,加上有虚函数,可以实现运行时多形性。

    此示例还调用层次结构中的非虚拟函数。

    // dynamic_cast_8.cpp
    // compile with: /GR /EHsc
    #include <stdio.h>
    #include <iostream>
    struct A {
        virtual void test() {
            printf_s("in A\n");
    struct B : A {
        virtual void test() {
            printf_s("in B\n");
        void test2() {
            printf_s("test2 in B\n");
    struct C : B {
        virtual void test() {
            printf_s("in C\n");
        void test2() {
            printf_s("test2 in C\n");
    void Globaltest(A& a) {
        try {
            C &c = dynamic_cast<C&>(a);
            printf_s("in GlobalTest\n");
        catch(std::bad_cast) {
            printf_s("Can't cast to C\n");
    int main() {
        A *pa = new C;
        A *pa2 = new B;
        pa->test();
        B * pb = dynamic_cast<B *>(pa);
        if (pb)
            pb->test2();
        C * pc = dynamic_cast<C *>(pa2);
        if (pc)
            pc->test2();
        C ConStack;
        Globaltest(ConStack);
       // fails because B knows nothing about C
        B BonStack;
        Globaltest(BonStack);
    test2 in B
    in GlobalTest
    Can't cast to C
    

    强制转换运算符

  •