Comment : utiliser safe_cast dans C++/CLI
Cet article explique comment utiliser le safe_cast dans les applications d' C++/CLI .Pour plus d'informations sur le safe_cast dans C++/CX, consultez safe_cast (extensions du composant C++).
Cast ascendant
Un upcast est un cast d'un type dérivé vers l'une de ses classes de base.Ce cast est possible et ne requiert pas une notation de cast explicite.L'exemple suivant montre comment effectuer un upcast, avec safe_cast et sans lui.
// 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();
}
Cast descendant
Un cast aval est un cast d'une classe de base pour une classe dérivée de la classe de base.Un cast aval est possible que si l'objet qui est traité au moment de l'exécution adresse en fait un objet de classe dérivée.Contrairement à static_cast, safe_cast effectue un contrôle dynamique et lève InvalidCastException si la conversion échoue.
// 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);
}
safe_cast avec des conversions définies par l'utilisateur
L'exemple montre comment utiliser safe_cast pour appeler des conversions définies par l'utilisateur.
// 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
}
opérations de safe_cast et de boxing
Boxing
La conversion boxing est définie comme une conversion compilateur injectée et définie par l'utilisateur.Par conséquent, vous pouvez utiliser pour safe_cast boxing une valeur sur le tas CLR.
L'exemple suivant illustre la conversion boxing avec des types valeur simples et définis par l'utilisateur.safe_cast enferme dans une boîte une variable de type valeur qui se trouve sur la pile native afin qu'elle puisse être assignée à une variable sur le tas récupéré par le garbage collector.
// 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);
}
L'exemple montre que la conversion boxing est prioritaire sur une conversion définie par l'utilisateur dans une opération d' safe_cast .
// 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 est définie comme une conversion compilateur injectée et définie par l'utilisateur.Par conséquent, vous pouvez utiliser pour safe_cast unbox une valeur sur le tas CLR.
Unboxing est une conversion définie par l'utilisateur, mais contrairement à la conversion boxing, une conversion unboxing doit être explicite- autrement dit, il doit être effectuée par static_cast, cast de style C, ou safe_cast; unboxing ne peut pas être exécutée implicitement.
// safe_cast_unboxing.cpp
// compile with: /clr
int main() {
System::Object ^ o = 42;
int x = safe_cast<int>(o);
}
L'exemple suivant illustre la conversion unboxing avec les types valeur et les types primitifs.
// 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();
}
types de safe_cast et de générique
L'exemple montre comment utiliser safe_cast pour effectuer un cast aval à un type générique.
// 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);
}