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
类型对象的指针可以安全地强制转换为 B
或 C
。 但是,如果 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
转换,然后执行从 E
到 B
的转换(可以是 dynamic_cast
,也可以是隐式转换),最后执行从 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
子D
对象强制转换为子对象。
考虑到交叉强制转换,只需执行两个步骤即可从指针转换为 D
指向最 A
左侧子对象的指针。 可以执行从 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
一个空指针值通过 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
强制转换运算符