FAQ C++/CLI et VC++.Net
FAQ C++/CLI et VC++.NetConsultez toutes les FAQ
Nombre d'auteurs : 29, nombre de questions : 248, création le 22 février 2013
L'opérateur as du C# n'existe pas en C++/CLI. Il est utilisé pour effectuer des conversions entre des types compatibles.
Il retourne nullptr lorsque la conversion est impossible.
En C++, nous allons donc utiliser l'opérateur dynamic_cast pour effectuer une telle tâche.
Ainsi, il suffira d'utiliser le code suivant pour simuler le as du C# (ici T est un type quelconque).
T t =
dynamic_cast
<
T>
(e); // cette ligne uniquement correspond au 'as'
if
(t !=
nullptr
)
{
// ...
}
On peut rendre ceci générique en utilisant les templates du C++. Il est impossible ici d'utiliser les générics du C++/CLI, car on ne peut pas combiner l'utilisation de dynamic_cast avec ceux-ci.
Voici ce que serait l'implémentation du 'as' C# :
template
<
class
T, class
U >
T as(U u)
{
return
dynamic_cast
<
T >
(u);
}
Observons maintenant l'exemple suivant pour illuster cette fonction :
ref class
class1 {}
;
ref class
class2 {}
;
int
main()
{
array<
Object ^>
^
tabObj =
gcnew array<
Object ^>
(6
);
tabObj[0
] =
gcnew class1();
tabObj[1
] =
gcnew class2();
tabObj[2
] =
"chaine"
;
tabObj[3
] =
123
;
tabObj[4
] =
123.4
;
tabObj[5
] =
nullptr
;
for
(int
i =
0
; i <
tabObj->
Length ; i++
)
{
String ^
s =
as<
String ^>
(tabObj[i]);
Console::
Write("{0} : "
, i);
if
(s)
Console::
WriteLine("'{0}'"
, s);
else
Console::
WriteLine("n'est pas un String ^"
);
}
return
0
;
}
Cet exemple produit :
0 : n'est pas un String ^
1 : n'est pas un String ^
2 : 'chaine'
3 : n'est pas un String ^
4 : n'est pas un String ^
5 : n'est pas un String ^
L'opérateur is du C# n'existe pas en C++/CLI. Il permet de vérifier si un objet est compatible avec un type. Il effectue cette vérification en runtime.
L'opérateur C++ dynamic_cast est le candidat parfait pour cette vérification.
Il suffit, sur le même principe que Comment implémenter l'opérateur d'assignation 'as' du C# ?, d'utiliser ce code (T étant un type quelconque) :
T t =
dynamic_cast
<
T>
(e);
if
(t !=
nullptr
)
{
// ...
}
Le 'is' consiste en la combinaison des deux instructions ci-dessus.
On peut en faire une version générique, en utilisant les templates du C++. (En effet, on ne peut pas utiliser les générics du C++/CLI à cause de dynamic_cast).
template
<
class
T, class
U >
Boolean is(U u)
{
return
dynamic_cast
<
T >
(u) !=
nullptr
;
}
Observons maintenant l'exemple suivant pour illuster cette fonction :
void
Test(Object ^
o)
{
if
(is<
String ^>
(o))
{
Console::
WriteLine("o est une chaine"
);
String ^
a =
safe_cast<
String ^>
(o);
DoSomethingWith(a);
}
else
if
(is<
Boolean ^>
(o))
{
Console::
WriteLine("o est un Boolean"
);
Boolean ^
b =
safe_cast<
Boolean ^>
(o);
DoSomethingWith(b);
}
else
Console::
WriteLine("o n'est ni une chaine , ni un Boolean"
);
}
int
main()
{
String ^
s =
gcnew String("chaine"
);
Boolean ^
a =
gcnew Boolean(true
);
Test(s);
Test(a);
Test(1234
);
return
0
;
}
On obtient en sortie :
o est une chaine
o est un Boolean
o n'est ni une chaine , ni un Boolean
Nous avons vu dans Comment implémenter l'opérateur d'assignation 'as' du C# ? et dans Comment implémenter l'opérateur 'is' du C# ? comment effectuer une comparaison d'assignation.
Il peut être utile dans certains cas d'effectuer une comparaison d'identité.
Ces deux concepts sont différents dans la mesure où dans la comparaison d'assignation, on va vérifier si les types sont compatibles entre eux alors que dans la comparaison d'identité, on va vérifier si les types sont de même type.
On utilise pour ca la capacité du framework .Net de reflexion (d'introspection), en comparant le type d'un objet (méthode GetType) et le type d'un Type (méthode statique typeid).
Créons donc une fonction générique en C++/CLI pour cette comparaison :
generic <
typename
T, typename
U>
bool
isIdentity(U u)
{
return
T::
typeid
==
u->
GetType();
}
Nous allons illustrer cette fonction à travers l'exemple suivant, qui consiste à remettre à zéro tous les contrôles de type "textbox" dans une Winform, en parcourant tous les contrôles et en testant l'identité de ceux-ci :
for
each (Control ^
c in this
->
Controls)
if
(isIdentity<
TextBox ^>
(c))
c->
Text =
""
;