Freigeben über


Vorgehensweise: Verwenden von safe_cast in C++/CLI

In diesem Artikel wird gezeigt, wie Sie safe_cast in C++/CLI-Anwendungen verwenden. Informationen zu safe_cast in C++/CX finden Sie unter safe_cast.

Umwandlung in eine Basisklasse

Ein Upcast ist eine Umwandlung von einem abgeleiteten Typ in eine seiner Basisklassen. Diese Umwandlung ist sicher und erfordert keine explizite Umwandlungsnotation. Im folgenden Beispiel wird gezeigt, wie Sie eine Upcast mit safe_cast und ohne einen Upcast ausführen.

// safe_upcast.cpp
// compile with: /clr
using namespace System;
interface class A {
   void Test();
};

ref struct B : public A {
   virtual void Test() {
      Console::WriteLine("in B::Test");
   }

   void Test2() {
      Console::WriteLine("in B::Test2");
   }
};

ref struct C : public B {
   virtual void Test() override {
      Console::WriteLine("in C::Test");
   };
};

int main() {
   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

Umwandlung in eine abgeleitete Klasse

Eine Downcast ist eine Umwandlung von einer Basisklasse in eine Von der Basisklasse abgeleitete Klasse. Eine Downcast ist nur dann sicher, wenn das objekt, das zur Laufzeit adressiert ist, tatsächlich ein abgeleitetes Klassenobjekt adressiert. Im Gegensatz dazu static_castsafe_cast führt eine dynamische Überprüfung aus und löst ausInvalidCastException, wenn die Konvertierung fehlschlägt.

// safe_downcast.cpp
// compile with: /clr
using namespace System;

interface class A { void Test(); };

ref struct B : public A {
   virtual void Test() {
      Console::WriteLine("in B::Test()");
   }

   void Test2() {
      Console::WriteLine("in B::Test2()");
   }
};

ref struct C : public B {
   virtual void Test() override {
      Console::WriteLine("in C::Test()");
   }
};

interface class I {};

value struct V : public I {};

int main() {
   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()

safe_cast mit benutzerdefinierten Konvertierungen

Das nächste Beispiel zeigt, wie Sie benutzerdefinierte safe_cast Konvertierungen aufrufen können.

// safe_cast_udc.cpp
// compile with: /clr
using namespace System;
value struct V;

ref struct R {
   int x;
   R() {
      x = 1;
   }

   R(int argx) {
      x = argx;
   }

   static operator R::V^(R^ r);
};

value struct V {
   int x;
   static operator 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);
   }

int main() {
   bool fReturnVal = 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)

safe_cast- und Boxvorgänge

Boxing

Boxen wird als compilerinjizierte, benutzerdefinierte Konvertierung definiert. Daher können Sie einen Wert für den CLR-Heap boxen safe_cast .

Das folgende Beispiel zeigt boxen mit einfachen und benutzerdefinierten Werttypen. A safe_cast boxes a value type variable that's on the native stack that it can be assigned to a variable on the garbage-collection heap.

// safe_cast_boxing.cpp
// compile with: /clr
using namespace System;

interface struct I {};

value struct V : public I {
   int m_x;

   V(int i) : m_x(i) {}
};

int main() {
   // 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);
}

Das nächste Beispiel zeigt, dass boxen Vorrang vor einer benutzerdefinierten Konvertierung in einem safe_cast Vorgang hat.

// safe_cast_boxing_2.cpp
// compile with: /clr
static bool fRetval = true;

interface struct I {};
value struct V : public I {
   int x;

   V(int argx) {
      x = argx;
   }

   static operator I^(V v) {
      fRetval = false;
      I^ pi = v;
      return pi;
   }
};

ref struct R {
   R() {}
   R(V^ pv) {}
};

int main() {
   V v(10);
   I^ pv = safe_cast<I^>(v);   // boxing will occur, not UDC "operator I^"
}

Unboxing

Unboxing ist als compilerinjizierte, benutzerdefinierte Konvertierung definiert. Daher können Sie zum Entpacken eines Werts im CLR-Heap verwenden safe_cast .

Unboxing ist eine benutzerdefinierte Konvertierung, aber im Gegensatz zu Boxen muss unboxing explizit sein , d. h. es muss von einer static_castC-Format-Umwandlung oder safe_casteiner Unboxing ausgeführt werden.

// safe_cast_unboxing.cpp
// compile with: /clr
int main() {
   System::Object ^ o = 42;
   int x = safe_cast<int>(o);
}

Das folgende Beispiel zeigt unboxing mit Werttypen und Grundtypen.

// safe_cast_unboxing_2.cpp
// compile with: /clr
using namespace System;

interface struct I {};

value struct VI : public I {};

void test1() {
   Object^ o = 5;
   int x = safe_cast<Int32>(o);
}

value struct V {
   int x;
   String^ s;
};

void test2() {
   V localv;
   Object^ o = localv;
   V unboxv = safe_cast<V>(o);
}

void test3() {
   V localv;
   V^ o2 = localv;
   V unboxv2 = safe_cast<V>(o2);
}

void test4() {
   I^ refi = VI();
   VI vi  = safe_cast<VI>(refi);
}

int main() {
   test1();
   test2();
   test3();
   test4();
}

safe_cast und generische Typen

Das nächste Beispiel zeigt, wie Sie eine Downcast mit einem generischen Typ ausführen können safe_cast .

// safe_cast_generic_types.cpp
// compile with: /clr
interface struct I {};

generic<class T> where T:I
ref struct Base {
   T t;
   void test1() {}
};

generic<class T> where T:I
ref struct Derived:public Base <T> {};

ref struct R:public I {};

typedef Base<R^> GBase_R;
typedef Derived<R^> GDerived_R;

int main() {
   GBase_R^ br = gcnew GDerived_R();
   GDerived_R^ dr = safe_cast<GDerived_R^>(br);
}

Siehe auch

safe_cast