dynamic_cast运算符

将操作数 expression 转换为类型 type-id对象。

dynamic_cast < type-id > ( expression )

备注

type-id 必须是指针或引用无效的以前已定义的类类型或 “指针”。expression 的类型必须是指针,如果 type-id 是指针,或左值,如果 type-id 是引用。

为差异的声明静态和动态强制转换的不同请参见 static_cast ,因此,使用时,每个合适。

在 dynamic_cast 行为的两个重大更改在托管代码中:

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

  • dynamic_cast 将不再引发异常,则 type-id 是内部指针指向值类型,则转换在运行时失败。该转换将返回 0 个指针值而不是引发。

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

// 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的类型的完整对象。如果为 true,则结果是指向 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 结果 no-op 转换,则可以隐式执行, (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);
}

显示多重继承的类层次结构

显示多重继承的类层次结构

对类型 D 对象的指针可以安全地强制转换为 B 或 C。但是,因此,如果 D 转换指向 A 对象, A 实例将导致?这将导致一个不明确的强制转换错误。若要避免此问题,可以执行两个明确的转换。例如:

// dynamic_cast_4.cpp
// compile with: /c /GR
class A {virtual void f();};
class B {virtual void f();};
class D : public B {virtual void f();};

void f() {
   D* pd = new D;
   B* pb = dynamic_cast<B*>(pd);   // first cast to B
   A* pa2 = dynamic_cast<A*>(pb);   // ok: unambiguous
}

进一步多义性,当您使用虚拟基类时,可以引入。考虑如下图所示的类层次结构。

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

ClassHierarchyVirtualBaseClasses 图

此层次结构, A 是虚拟基类。对于虚拟基类的定义参见 虚拟基类 。将类 E 和指针实例 A subobject, dynamic_cast 指针 B 将失败由于多义性。必须先将返回完整 E 对象,然后工作方式备份层次结构,以明确的方式,到达正确的 B 对象。

考虑如下图所示的类层次结构。

类层次结构显示重复基类

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

命名类型 E 和指针对象 D subobject,从 D subobject 导航到最左侧的 A subobject,这将进行可以执行从 D 指针的一个 dynamic_cast 转换为 E 指针,然后转换 ( dynamic_cast 或隐式转换) 从 E 到 B最后从 B 的隐式强制转换为 A。例如:

// 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,将指针,例如,从 B subobject 到 D subobject 是可能的。

考虑相互转换,执行从指针的转换到 D 指针对两个步骤的最左侧的 A subobject 实际上是可能的。可以执行从 D 转换的交叉到 B,然后从 B 的隐式强制转换为 A。例如:

// 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
}

一个空指针值转换为目标类型的 null 指针值。 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
}

非限定转换的值设置为指针类型的是 null 指针。引用类型的非限定转换会引发 bad_cast 异常。   如果 expression 不指向也不引用有效的对象, __non_rtti_object 引发异常。

__non_rtti_object 异常的描述参见 typeid

示例

下面的示例创建基类 (结构) 指针,该对象 (结构 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);

   // will fail because B knows nothing about C
    B BonStack;
    Globaltest(BonStack);
}
  

请参见

参考

转换运算符

C++关键字