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
Sommaire→Le langage C++/CLI→Compatibilité d'assignation et comparaison de d'identité de typesL'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 BooleanNous 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 = "";


