深入解析C++中的动态类型转换与静态类型转换运算符
dynamic_cast 运算符 dynamic_cast < type-id > ( expression ) 备注 // 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 } 此转换类型称为“向上转换”,因为它将在类层次结构上的指针,从派生的类移到该类派生的类。向上转换是一种隐式转换。 // 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指向的类型。 // 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 } 此转换类型称为“向下转换”,因为它将在类层次结构下的指针,从给定的类移到该类派生的类。 // 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); } 显示多重继承的类层次结构 // 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 } 当使用虚拟基类时,其他多义性问题会被引入。考虑下图中显示的类层次结构。 显示虚拟基类的类层次结构 给定一个 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 运算符还可以使用执行 “相互转换”。使用同一个类层次结构可能进行指针转换,例如: 从B 子对象转换到D子对象(只要整个对象是类转换型E。 // 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 D {virtual void f();}; void f(D* pd) { B* pb = dynamic_cast<B*>(pd); // cross cast A* pa = pb; // upcast,implicit conversion } 通过 dynamic_cast 将 null 指针值转换到目标类型的 null 指针值。 // 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 异常引发。 // dynamic_cast_8.cpp // compile with: /GR /EHsc #include <stdio.h> #include <iostream> struct A { virtual void test() { printf_s("in An"); } }; struct B : A { virtual void test() { printf_s("in Bn"); } void test2() { printf_s("test2 in Bn"); } }; struct C : B { virtual void test() { printf_s("in Cn"); } void test2() { printf_s("test2 in Cn"); } }; void Globaltest(A& a) { try { C &c = dynamic_cast<C&>(a); printf_s("in GlobalTestn"); } catch(std::bad_cast) { printf_s("Can't cast to Cn"); } } 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); } 输出: in C test2 in B in GlobalTest static_cast 运算符 static_cast <type-id> ( expression ) 备注 // static_cast_Operator.cpp // compile with: /LD class B {}; class D : public B {}; void f(B* pb,D* pd) { D* pd2 = static_cast<D*>(pb); // Not safe,D can have fields // and methods that are not in B. B* pb2 = static_cast<B*>(pd); // Safe conversion,D always // contains all of B. } 与 dynamic_cast 不同,pb 的 static_cast 转换不执行运行时检查。由 pb 指向的对象可能不是 D 类型的对象,在这种情况下使用 *pd2 会是灾难性的。例如,调用 D 类(而非 B 类)的成员函数可能会导致访问冲突。 // static_cast_Operator_2.cpp // compile with: /LD /GR class B { public: virtual void Test(){} }; class D : public B {}; void f(B* pb) { D* pd1 = dynamic_cast<D*>(pb); D* pd2 = static_cast<D*>(pb); } 如果 pb 确实指向 D 类型的对象,则 pd1 和 pd2 将获取相同的值。如果 pb == 0,它们也将获取相同的值。 // static_cast_Operator_3.cpp // compile with: /LD /GR typedef unsigned char BYTE; void f() { char ch; int i = 65; float f = 2.5; double dbl; ch = static_cast<char>(i); // int to char dbl = static_cast<double>(f); // float to double i = static_cast<BYTE>(ch); } static_cast 运算符可以将整数值显式转换为枚举类型。如果整型值不在枚举值的范围内,生成的枚举值是不确定的。 (编辑:李大同) 【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容! |