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
- Qu'est-ce qu'une classe managée ?
- Qu'est-ce qu'une classe non managée ?
- Qu'est-ce qu'un type de référence ?
- Qu'est-ce qu'un type de valeur ?
- Quelles sont les équivalences des types natifs dans le framework .Net ?
- Comment créer une énumération C++/CLI ?
- Comment définir un literal ?
- Comment définir une variable initonly ?
- Comment savoir si un handle est nul ?
- 3.4.1.1. Variables et fonctions statiques (3)
Une classe managée veut simplement dire que l'objet est pris en charge par le CLR. Son allocation (avec gcnew) et sa désallocation (utilisant soit delete explicitement, soit utilisant le garbage collector) sont donc entièrement gérées (managed en anglais) par le CLR. Microsoft a essayé de rayer le mot managé de son vocabulaire pour éviter l'abus de langage (pour parler par exemple de C++/CLI plutôt que de C++ managé).
Cet objet est alloué sur le tas (heap) managé par l'intermédiaire de gcnew et est référencé grâce à un handle.
String ^
str =
gcnew String("Ma chaîne managée est alloué sur le heap managé"
);
La désallocation est automatique grâce au garbage collector.
Evidement, les objets existants du framework .net (comme le String ci-dessus) sont managés.
Lien : Comment allouer un objet managé avec gcnew ?
Lien : Qu'est-ce que le garbage collector ?
Pour déclarer une classe non managée par le CLR, on n'utilise aucun autre mot clé que class.
class
CMaClasseNonManagee
{
CMaClasseNonManagee(void
);
~
CMaClasseNonManagee(void
);
bool
maFonctionNonManagee();
CString maChaineNonManagee;
}
;
Cette ancienne déclaration fonctionne toujours de la même façon, et est gérée par le CRT, allouée sur le tas (non managé) avec new.
Une classe non managée par le CLR est dite native.
Un type ref est un type CLI qui est alloué sur le heap managé. Il est pris complètement en charge par le garbage collector qui gère sa désallocation quand il n'est plus utile.
Le mot clé ref permet de créer donc des objets managés ou des structures managées (on utilise alors ref class ou bien ref struct).
ref class
CMaClasse
{
CMaClasse(void
);
~
CMyClass(void
);
bool
maFonction();
String ^
monAttributChaine;
}
;
Un type de valeur (value type) est un type CLI qui est alloué sur la pile et qui est détruit lorsqu'il sort de sa portée.
Il se comporte essentiellement comme un type POD (Plain Old Data : un type POD est un type C++ qui possède un équivalent en C. Il correspond aux types composés à partir des types primitifs).
On ne peut pas hériter d'un type de valeur. Ils n'ont pas non plus de constructeur par défaut, de destructeur, d'opérateur de copie ou d'affectation.
Lorsque l'on conçoit un objet qui fonctionne comme un type natif (un int par exemple), alors cette classe est une candidate parfaite pour un type de valeur.
Pour créer un type de valeur, on utilise alors value class ou bien value struct.
value class
MonTypeDeValeur {
String^
uneChaine;
String^
uneAutreChaine;
}
;
Remarque :
- Les types de valeurs ont été créés pour permettre une copie rapide et efficace de données, sans utiliser d'indirections de mémoire inutile pour y accéder (pas besoin d'une place mémoire dans le garbage collector et d'une place mémoire pour le handle le référençant). Ainsi, le type de mémoire n'est pas stocké sur le heap managé et permet d'éviter l'encombrement du garbage collector. Ils bénéficient de même des optimisations de registre.
- Sans les types de valeurs, .Net aurait été beaucoup trop lent face à ses concurrents Java et C++, même pour des petits projets.
Cependant, il faut noter que lors de la phase d'optimisation du compilateur, celui-ci peut décider lui même si le type de valeur aurait été un meilleur choix qu'un type de référence et choisir ainsi le meilleur emplacement pour ce type, dans la plupart des cas. - On utilise l'expression "types managés" ou "objets managés" par abus de langage. Il est plus correct de parler de types CLI.
Il est en général recommandé pour le CLS d'utiliser des structures pour les types de valeurs et des classes pour les types de références.
Vous trouverez dans ce tableau une équivalence des types natifs avec les types du framework .Net.
Types natifs C++ | Types du framework .Net |
---|---|
bool | System::Boolean |
signed char | System::SByte |
unsigned char | System::Byte |
wchar_t | System::Char |
double et long double | System::Double |
float | System::Single |
int, signed int, long, et signed long | System::Int32 |
unsigned int et unsigned long | System::UInt32 |
__int64 et signed __int64 | System::Int64 |
unsigned __int64 | System::UInt64 |
short et signed short | System::Int16 |
unsigned short | System::UInt16 |
void | System::Void |
Les énumérations C++/CLI diffèrent sensiblement des énumérations du C++ ISO/ANSI. Elles correspondent par défaut à des entiers.
Dans la mesure où ces énumérations sont des types CLI, elles doivent être définies en global. Il est impossible d'avoir une définition locale.
enum
class
Jours{
Lundi, Mardi, Mercredi, Jeudi, Vendredi, Samedi, Dimanche}
;
Jours jeudi =
Jours::
Jeudi;
Il est possible de définir un type différent pour les énumérations, dans la liste suivante :
short, int, long, long long, signed char, char, unsigned short, unsigned int , unsigned long, unsigned long long, unsigned char et bool.
Ainsi, il est possible de définir une énumération de type bool :
enum
class
JoursDeLaSemaine : bool
{
Lundi =
true
, Mardi =
true
, Mercredi =
true
,
Jeudi =
true
, Vendredi =
true
, Samedi =
false
, Dimanche =
false
}
;
On se sert d'un literal en C++/CLI comme on se servirait d'une variable static const en C++.
Cette variable doit être initialisée à sa déclaration et est une manière élégante de nommer des constantes.
ref struct
constMath
{
literal double
pi =
3.14159265
;
literal double
nombreOr =
1.61803399
;
}
;
int
main()
{
static
const
int
rayon =
5
;
double
circonference =
2
*
rayon*
constMath::
pi;
return
0
;
}
Une variable initonly fonctionne comme un literal à la différence qu'elle n'est pas obligée d'être initialisée à sa construction.
Cela veut dire qu'on peut par exemple initialiser cette variable dans un constructeur. Par contre, une fois initialisée, il sera impossible de la changer.
ref class
constMath
{
public
:
initonly double
pi;
constMath(int
x)
{
pi =
x;
}
}
;
En C/C++, on utilise 0 ou null pour savoir si un pointeur est null.
En C++/CLI, lorsqu'on affecte 0 à un handle, il s'effectue une conversion (un boxing) en Int32 qui sera castée en Object ^.
Ainsi le C++/CLI nous offre un nouveau mot clé : nullptr.
MonObjet ^
m =
nullptr
;
if
(m ==
nullptr
)
....
nullptr correspond aux nothing et null du VB.Net et du C#.