description | title | ms.date | helpviewer_keywords | ms.assetid | |
---|---|---|---|---|---|
Learn more about: How to: Use safe_cast in C++/CLI | How to: Use safe_cast in C++/CLI | 11/04/2016 |
| 0fbc87d8-ecdf-4cd5-81f4-0d8cc18e2aff |
This article shows how to use safe_cast in C++/CLI applications. For information about safe_cast in C++/CX, see safe_cast.
An upcast is a cast from a derived type to one of its base classes. This cast is safe and does not require an explicit cast notation. The following sample shows how to perform an upcast, with safe_cast
and without it.
// safe_upcast.cpp// compile with: /clrusingnamespaceSystem; interface classA { voidTest(); }; ref structB : publicA { virtualvoidTest() { Console::WriteLine("in B::Test"); } voidTest2() { Console::WriteLine("in B::Test2"); } }; ref structC : publicB { virtualvoidTest() override { Console::WriteLine("in C::Test"); }; }; intmain() { C ^ c = gcnew C; // implicit upcast B ^ b = c; b->Test(); b->Test2(); // upcast with safe_cast b = nullptr; b = safe_cast<B^>(c); b->Test(); b->Test2(); }
in C::Test in B::Test2 in C::Test in B::Test2
A downcast is a cast from a base class to a class that's derived from the base class. A downcast is safe only if the object that's addressed at runtime is actually addressing a derived class object. Unlike static_cast
, safe_cast
performs a dynamic check and throws xref:System.InvalidCastException if the conversion fails.
// safe_downcast.cpp// compile with: /clrusingnamespaceSystem; interface classA { voidTest(); }; ref structB : publicA { virtualvoidTest() { Console::WriteLine("in B::Test()"); } voidTest2() { Console::WriteLine("in B::Test2()"); } }; ref structC : publicB { virtualvoidTest() override { Console::WriteLine("in C::Test()"); } }; interface classI {}; value structV : publicI {}; intmain() { A^ a = gcnew C(); a->Test(); B^ b = safe_cast<B^>(a); b->Test(); b->Test2(); V v; I^ i = v; // i boxes V V^ refv = safe_cast<V^>(i); Object^ o = gcnew B; A^ a2= safe_cast<A^>(o); }
in C::Test() in C::Test() in B::Test2()
The next sample shows how you can use safe_cast
to invoke user-defined conversions.
// safe_cast_udc.cpp// compile with: /clrusingnamespaceSystem; value structV; ref structR { int x; R() { x = 1; } R(int argx) { x = argx; } staticoperator R::V^(R^ r); }; value structV { int x; staticoperator R^(V& v) { Console::WriteLine("in operator R^(V& v)"); R^ r = gcnew R(); r->x = v.x; return r; } V(int argx) { x = argx; } }; R::operator V^(R^ r) { Console::WriteLine("in operator V^(R^ r)"); return gcnew V(r->x); } intmain() { boolfReturnVal = false; V v(2); R^ r = safe_cast<R^>(v); // should invoke UDC V^ v2 = safe_cast<V^>(r); // should invoke UDC }
in operator R^(V& v in operator V^(R^ r)
Boxing is defined as a compiler-injected, user-defined conversion. Therefore, you can use safe_cast
to box a value on the CLR heap.
The following sample shows boxing with simple and user-defined value types. A safe_cast
boxes a value type variable that's on the native stack so that it can be assigned to a variable on the garbage-collected heap.
// safe_cast_boxing.cpp// compile with: /clrusingnamespaceSystem; interface structI {}; value structV : publicI { int m_x; V(int i) : m_x(i) {} }; intmain() { // box a value type V v(100); I^ i = safe_cast<I^>(v); int x = 100; V^ refv = safe_cast<V^>(v); int^ refi = safe_cast<int^>(x); }
The next sample shows that boxing has priority over a user-defined conversion in a safe_cast
operation.
// safe_cast_boxing_2.cpp// compile with: /clrstaticboolfRetval = true; interface structI {}; value structV : publicI { int x; V(int argx) { x = argx; } staticoperator I^(V v) { fRetval = false; I^ pi = v; returnpi; } }; ref structR { R() {} R(V^ pv) {} }; intmain() { V v(10); I^ pv = safe_cast<I^>(v); // boxing will occur, not UDC "operator I^" }
Unboxing is defined as a compiler-injected, user-defined conversion. Therefore, you can use safe_cast
to unbox a value on the CLR heap.
Unboxing is a user-defined conversion, but unlike boxing, unboxing must be explicit—that is, it must be performed by a static_cast
, C-style cast, or safe_cast
; unboxing cannot be performed implicitly.
// safe_cast_unboxing.cpp// compile with: /clrintmain() { System::Object ^ o = 42; int x = safe_cast<int>(o); }
The following sample shows unboxing with value types and primitive types.
// safe_cast_unboxing_2.cpp// compile with: /clrusingnamespaceSystem; interface structI {}; value structVI : publicI {}; voidtest1() { Object^ o = 5; int x = safe_cast<Int32>(o); } value structV { int x; String^ s; }; voidtest2() { V localv; Object^ o = localv; V unboxv = safe_cast<V>(o); } voidtest3() { V localv; V^ o2 = localv; V unboxv2 = safe_cast<V>(o2); } voidtest4() { I^ refi = VI(); VI vi = safe_cast<VI>(refi); } intmain() { test1(); test2(); test3(); test4(); }
The next sample shows how you can use safe_cast
to perform a downcast with a generic type.
// safe_cast_generic_types.cpp// compile with: /clr interface structI {}; generic<classT> where T:I ref structBase { T t; voidtest1() {} }; generic<classT> where T:I ref structDerived:publicBase <T> {}; ref structR:publicI {}; typedef Base<R^> GBase_R; typedef Derived<R^> GDerived_R; intmain() { GBase_R^ br = gcnew GDerived_R(); GDerived_R^ dr = safe_cast<GDerived_R^>(br); }