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_cast
safe_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_cast
C-Format-Umwandlung oder safe_cast
einer 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);
}