Les primitives et les Handles |
|||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
A ce stade, nous ne pouvons continuer notre apprentissage du C# sans passer par une étude approfondie des primitives et des handles. Examinons donc les types fondamentaux du langage C# et la façon dont ces données sont conservées en mémoire. |
|||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
Sommaire2. les types 3. Où se trouvent les données manipulées par C# ? 4. Présentation des différents types du C# 7. Le type byte 12. Le type char 13. Les types à virgule flottante 14. Le type float 15. Le type double 16. Le type décimal 17. Le type bool 19. Savoir écrire un identificateur 20. Les mots clés 21. Les constantes 23. Constantes non nommées entières 24. Constantes non nommées réelles 26. les séquences d'échappement 27. Constantes string (chaînes de caractères) 29. Les variables 30. Initialisation 31. affectation 32. Valeurs par défaut des primitives 33. Portée des identificateurs de variables ou de constantes 34. Portée des identificateurs de méthodes 35. identificateurs des objets 36. Les types fondamentaux objets 37. La classe Object 38. La classe string |
|||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
La
mémoire d'un ordinateur est un ensemble "d'états
binaires" qui, comme nous l'avons vu dans la première
partie, se nomment "bits" (8 bits donnent un octet). Un
bit peut indifféremment prendre 0 ou 1 comme valeur. Il va
de soit qu'un ordinateur peut mémoriser bien plus qu'un
simple bit d'information. Il manipule généralement
les données par tranches de format fixe qu'on appelle mots.
La taille d'un mot varie d'un ordinateur à l'autre. Sur les
plus anciens, elle était de 8 ou 16 bits (soit un ou deux
octets) mais on arrive aujourd'hui à 32 bits (soit quatre
octets). |
|||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
Comment
un ordinateur peut savoir, avec une mémoire composée
de milliards de 0 et de 1, où commence un nombre et où
il finit ? De même, comment peut-il savoir si ce nombre est
entier, flottant, ou s'il s'agit d'un caractère ? |
|||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
Nos
programmes peuvent manipuler des données se trouvant dans
trois endroits différents. C'est la façon dont elles
seront utilisées qui déterminera leur
emplacement. |
|||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
En
C#, les types sont soit prédéfinis, soit définis
par le programmeur lui-même. Les types prédéfinis
sont appelés types de données fondamentaux. Les
types créés par le programmeur peuvent être
soit des pointeurs, des énumérations, des tableaux
(arrays), ou bien évidemment des classes (nous reviendrons
sur tous ces termes). |
|||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
C# n'est pas un langage à 100 % objet. Il existe des éléments qu'on appelle primitives. Ils sont créés de façon différente des objets et ne sont pas manipulés dans la mémoire de la même manière. Leur existence a pour principale origine les performances ; ces primitives permettent de créer des données en mémoire et d'effectuer des opérations sur elles très rapidement. Les objets étant gérés dans le heap, leurs réactions auraient été beaucoup trop lentes pour effectuer des algorithmes rapides. |
|||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
Pour la représentation des nombres entiers, c'est-à-dire ceux dépourvus de décimales, le C# permet l'utilisation des types int, short, long, char, sbyte, byte, ushort, uint, ulong. Les lettres minuscules u, précédant les types ushort, uint, ulong, et s, précédant sbyte, indiquent que les nombres peuvent être mémorisés avec un signe ou non. |
|||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
Une donnée de type byte occupe un octet (ou byte en anglais) en mémoire soit 8 bits, elle est utilisée pour stocker un entier faible compris entre 0 et 255 (c'est-à-dire les chiffres compris entre 0 et 2^8-1) soit un nombre positif exclusivement. Contrairement au type sbyte que nous allons voir après, la mémoire occupée par un type byte ne dépend pas de l'existence d'un signe. Le nombre codé en binaire est codé avec la totalité des 8 octets. Il n'est pas nécessaire de réserver un emplacement pour coder le signe. D'un point de vue mathématique, ce nombre sera positif, pour l'ordinateur il n'aura simplement pas de signe. Chacun de ces bits peut prendre la valeur 0 ou 1, c'est à dire deux états possibles huit fois de suite, soit 2^8 (256) combinaisons possibles, la première étant : |
|||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
0000 0000 |
|||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
ce qui correspond au nombre 0, et la dernière étant : |
|||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
1111 1111 |
|||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
c'est-à-dire le nombre 255. |
|||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
A l'inverse du type byte, sbyte permet le stockage de données sur 8 bits signées. Ces données sont des nombres codés sur 7 bits, le huitième bit étant utilisé pour contenir une information de signe. |
|||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
Le nombre en mémoire est considéré comme négatif ou positif selon la valeur de ce huitième bit. Si celui-ci est égal à 1 alors le nombre est considéré comme négatif, s'il vaut 0 alors le nombre est positif. Il ne reste donc plus pour les nombres positifs que 128 valeurs représentables soit de 0 à 127 (de 00000000 à 01111111). A l'opposé, les combinaisons 1000000 à 11111111 représentent les nombres négatifs -1 à 128. |
|||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
La représentation des nombres négatifs est appelée méthode du complément à deux. Le complément à deux d'un nombre binaire b est le nombre b' tel que |
|||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
b + b' = 2^n |
|||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
n
représente le nombre de bits du nombre binaire. Dans le cas
du type sbyte n vaut 8. Le complément à deux d'un
nombre binaire s'obtient en remplaçant chaque 0 de la
combinaison binaire le représentant par 1, et chaque 1 par
0, puis en ajoutant 1 au résultat. |
|||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
00000001 |
|||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
Si on change chaque bits 0 en 1 et vice et versa on obtient : |
|||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
11111110 |
|||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
on lui rajoute alors 1 : |
|||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
111111111 |
|||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
pour obtenir la combinaison de bits représentant le nombre -1. Si vous cherchez le complément à deux de la suite binaire 11111111 vous obtiendrez évidemment 00000001. En additionnant 11111111 à 00000001 on obtient le nombre 256 qui est égal à 2^8. |
|||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
Il convient de rester prudent quand au stockage de nombres avec le type sbyte. Voyons le stockage de deux nombres 65 et 227 avec les types byte et sbyte. |
|||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
65
étant inférieur à 127, il est représentable
sur 7 bits et ne modifie pas le huitième bit de signe.
Celui-ci ne servant pas reste à 0, laissant le nombre en
positif. |
|||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
En byte on obtient 227 car le huitième bit sert au codage du nombre mais pas à donner le signe. En sbyte, ce bit va servir à indiquer le signe du nombre codé par les sept autres bits. La combinaison binaire qui était égale à 227 en byte va être lu comme -29 par le C# (le négatif venant du huitième bit à 1). |
|||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
Les
types short et ushort prennent en mémoire la même
place que le type char : 2 octets. Leur existence peut donc
sembler inutile. En fait on les utilise pour une raison
d'esthétique du code ; si un char (comme nous le verrons
plus loin) peut coder un nombre, il est surtout d'usage de
l'utiliser pour représenter les caractères en
mémoire. Il est donc plus logique de coder un nombre avec
le type short. Enfin le type char en mémoire ne représente
que des valeurs positives (c'est à dire les codes des
caractères) alors que le short permet de coder les nombres
signés sur deux octets. |
|||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
0000 0000 0000 0000 |
|||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
à |
|||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
0111 1111 1111 1111 |
|||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
c'est à dire les nombres 0 à 32767 et les nombres négatifs -1 à -32768 : |
|||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
1111 1111 1111 1111 |
|||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
et |
|||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
1000 0000 0000 0000 |
|||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
short permet donc de mémoriser un nombre dans un intervalle compris entre -32768 et 32767. |
|||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
Le type int et son équivalent non signé uint représentent les types entiers standards qui sont le plus souvent utilisés par les programmeurs. Ils occupent en mémoire 4 octets soit 32 bits. Ils fonctionnent sur le même principe que short et ushort, mais la plage des nombres représentables est beaucoup plus importante puisqu'il est possible de combiner 2^32 (4294967296) entiers. uint représentera les entiers entre 0 et 4294967295, et int les entiers positifs entre 0 et 2147483647 et négatifs entre -1 et 2147483648. |
|||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
Les types long et ulong permettent de stocker des entiers très grands puisqu'ils sont tous les deux stockés sur 64 bits (8 octets). Il est donc possible de coder 2^64 (1.844*10^19) nombres ! Ulong codera des entiers compris entre 0 et 2^64 et long permettra de coder des nombres entre -2^63 et 2^63-1 (soit entre -9 223 372 036 854 775 808 et + 9 223 372 036 854 775 807) ! |
|||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
Le type de données char (de l'anglais caractère) occupe une place de 2 octets en mémoire. Il sert à manipuler les caractères par l'intermédiaire d'Unicode. Ce dernier est un système 16 bits permettant de représenter 65536 caractères (2^16). |
|||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
Chaque nombre de cet intervalle correspond à un caractère ou à un idéogramme permettant de coder les signes de toutes les langues du monde. Par exemple la lettre A possède la valeur 65 dans le code Unicode/ASCII. |
|||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
Les types à virgules flottantes (appelés également réels ou tout simplement flottants) permettent de stocker en mémoire les nombres qui possèdent des décimales comme 3.14 ou -0.01258. En C# la virgule est représentée par un point décimal. Ce point peut se déplacer en n'importe quel endroit du nombre : |
|||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
45.123 |
|||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
est équivalent à |
|||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
4.5123*10^1 |
|||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
mais aussi à |
|||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
451.23*10^-1 |
|||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
c'est la multiplication par différentes puissances de dix qui fait que ces diverses représentations sont une seule et même valeur. En C# la représentation des nombres flottants est différente des nombres entiers. L'emplacement mémoire occupé par un nombre flottant est divisé en trois parties : le signe, l'exposant et la mantisse : |
|||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
La
partie signe fonctionne de la même manière que le bit
de signe des types entiers, soit à 1 pour les nombres
négatifs et à 0 pour les positifs. La mantisse est
la suite de chiffres qui constitue le nombre flottant. Dans le
nombre 45.123 la mantisse serait ainsi égale à
45123. Enfin l'exposant est la puissance nécessaire pour
écrire le nombre dans la forme voulue. |
|||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
0.mantisse * 10^exposant |
|||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
c'est-à-dire en forme binaire : |
|||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
0.mantisse-codée-en-binaire * 2^exposant |
|||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
notre nombre 45.123 s'écrira ainsi en décimal : |
|||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
0.45123*10^2 |
|||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
et en binaire |
|||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
0.0101101*2^5 |
|||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
Le type float occupe 4 octets en mémoire, divisés en trois parties énoncées ci-dessous. Les 32 bits sont divisés en 24 bits pour coder la mantisse, 7 bits pour coder l'exposant et 1 bit de signe. Le type float peut mémoriser des nombres compris entre 3.4*10^-38 et 3.4*10^38 avec une précision de 7 digits. |
|||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
Le type double occupe 8 octets en mémoire avec une mantisse de 53 bits et un exposant de 10 bits assurant une couverture des nombres de 1.7*10^-308 à 1.7*10^308 offrant une précision de 15 à 16 digits. |
|||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
Le type décimal en occupant 128 bits en mémoire offre une plage de nombres plus petite que les deux autres types flottants, mais avec une très grande précision avec 28-29 digits significatifs. Les nombres pouvant être mémorisés sont compris entre 1.0 à10^-28 à 7.9 à10^28. |
|||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
Le type bool n'occupe théoriquement que 1 bit en mémoire. En fait celui-ci prend au minimum un octet. Car une cellule ne peut pas être subdivisée en plusieurs parties. Une variable de type bool ne peut prendre que deux valeurs littérales, soit true ou false. Elles sont donc très utiles pour les programmes nécessitant un résultat ne pouvant prendre que deux états. Comme le lancer d'une pièce de monnaie par exemple : soit pile, soit face. |
|||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
Tout comme les handles permettent de donner un nom à un objet, il est possible d'attribuer à une donnée un identificateur. Cet identificateur doit cependant respecter certaines règles édictées par le langage. Celles-ci s'appliquent aussi bien aux noms attribués aux données qu'à ceux des handles. |
|||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
En principe un identificateur doit être constitué d'un ou plusieurs caractères. Ceux-ci peuvent être des lettres, des chiffres, ou bien l'underscore ( _ ) ; le premier caractère de l'identificateur devant être soit une lettre soit un underscore mais jamais un chiffre. |
|||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
pepette //bon pepette2 //bon 2pepette //mauvais : commence par un chiffre MA_VARIABLE //bon MES_2variables //bon fichier_13 //bon #_de_participants //mauvais : utilisation du caractère # nombre de participants //mauvais : utilisation d'un caractère d'espacement nombre-1 //mauvais : utilisation du caractère - |
|||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
Le compilateur fait aussi une distinction entre les majuscules et les minuscules, ce qui est souvent source d'erreurs au moment de la compilation. |
|||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
pepette |
|||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
est ainsi différent de |
|||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
Pepette |
|||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
Les
identificateurs sont aussi soumis à une autre forme de
restriction ; ils ne doivent surtout pas correspondre à un
mot clé du langage C#. Ainsi, il serait faux d'utiliser
using ou public en tant qu'identificateurs.
|
|||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
Les
données ne se caractérisent pas uniquement par leur
type (ce que nous venons de voir) ou leur valeur, mais aussi par
les constantes et les variables. Ces deux derniers éléments
vont nous permettre de modifier leur valeur. |
|||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
Les constantes non nommées sont soit entières pour affecter une valeur à un entier, soit flottantes pour les flottants, soit chaînes de caractères pour les strings. |
|||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
Ces constantes sont une suite de chiffres décimaux ou hexadécimaux. |
|||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
Constantes
décimales |
|||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
1 45 1256489 895 |
|||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
Constantes
hexadécimales |
|||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
0x1 0x2D 0x132C29 0x37F |
|||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
Constantes
négatives |
|||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
-1 -0x132C29 -01577 |
|||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
définir
les constantes entières |
|||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
22L |
|||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
force
le compilateur à donner le type long à cette
constante grâce à la lettre L la terminant, alors
qu'elle tenait fort bien dans un byte ou un short.
|
|||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
Les
constantes à virgules flottantes se composent d'une partie
entière (c'est-à-dire les chiffres situés
avant le point décimal), d'une partie décimale (soit
les chiffres après le point) et éventuellement d'un
exposant. Ils se trouvent toujours exprimés en base
10. |
|||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
45.12E-1 |
|||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
et |
|||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
45.12e-1 |
|||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
représentent le nombre 4.512 c'est-à-dire : |
|||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
45.12*10^-1 |
|||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
Nous aurions aussi pu écrire ce nombre ainsi : |
|||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
0.4512e1 |
|||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
Lorsque la partie entière est nulle comme ici elle peut être omise : |
|||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
.4512e1 |
|||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
Si c'est la partie décimale qui est nulle, nous pouvons écrire : |
|||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
4512.e-3 |
|||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
qui est équivalent à |
|||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
4512E-3 |
|||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
Les réels négatifs s'obtiennent tout simplement en rajoutant le préfixe moins ( - ). |
|||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
définir
les constantes réelles
|
|||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
Une constante caractère se compose d'un ou plusieurs caractères placés entre une paire d'apostrophes. Exemple : |
|||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
'A' //caractère majuscule A '1' //caractère 1 (à ne pas confondre avec la valeur numérique) |
|||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
Les constantes de caractères sont de type char et pourraient se classer dans les constante entières comme nous l'avons vu lors de l'étude du type char. Ces constantes représentent les codes entiers du jeu de caractères Unicode. Pour l'ordinateur la constante 'A' équivaut à la valeur numérique 65 et '1' à la valeur numérique 49 (et non 1 comme on pourrait le penser). A chaque nombre de 0 à 65535 correspond un caractère imprimable par l'ordinateur. |
|||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
Il
faut bien comprendre que les caractères '1', '2' ou '3' ne
sont pas équivalents aux entiers 1, 2 et 3. Les premiers
correspondent aux nombres 49, 50 et 51 et les seconds aux valeurs
1 à 3. |
|||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
Certains
caractères ne peuvent pas être représentés
sous une forme imprimable. L'apostrophe est un bon exemple. Pour
le compilateur elle représente un séparateur. |
|||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
Console.Out.Write('''); |
|||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
Nous obtenons une erreur à la compilation : |
|||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
TroisiemeProgramme.cs(29,23): error CS1010: Newline in constant |
|||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
Pour représenter l'apostrophe, il faut la faire précéder d'une barre oblique inversée ( \ ) ou backslash : |
|||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
Console.Out.Write('\''); |
|||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
La compilation se déroule ici sans erreur. Le backslash masque au compilateur l'utilité du caractère apostrophe en le faisant passer pour un caractère ordinaire, permettant son affichage sur la sortie standard. |
|||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
//TroisièmeProgramme.cs /**************************************************/ /* */ /* troisème programme d'apprentissage du C# */ /* (premiere version) */ /* */ /**************************************************/ //utiliser le namespace System using System ; /** * objet qui contient notre fonction main */ class TroisiemeProgramme { /** * méthode principale du programme */ public static void Main() { Console.Out.Write(' '); } } |
|||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
Les
caractères introduits par un backslash s'appellent les
séquences d'échappement.
|
|||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
Console.Out.Write('"'); |
|||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
Par contre à l'intérieur d'une constante string (chaîne de caractères) la séquence d'échappement est obligatoire |
|||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
Console.Out.WriteLine("et Cesar dit : \" les dés sont jetés\" "); |
|||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
A l'inverse, si le caractère apostrophe nécessite obligatoirement une barre oblique inversée en tant que caractère, à l'intérieur d'une string il peut être affiché directement. |
|||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
Console.Out.WriteLine("l'alibi d'la donzelle l'a protégé"); |
|||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
Il existe un grand nombre de caractères non imprimables mais très souvent utilisés par les programmes C#. Ils ont le code décimal 0 à 31 dans l'Unicode ; le signal sonore ( \a ) permet d'émettre un Bip, le caractère Backspace (\b) permet de faire reculer d'un caractère la position du curseur etc. Ainsi l'instruction : |
|||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
Console.Out.WriteLine("le cours sur le C*\b# est bien "); |
|||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
affichera : |
|||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
le cours sur le C# est bien |
|||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
La tabulation et le saut de ligne permettent de modifier la présentation de ce que nous écrivons à l'écran |
|||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
Console.Out.WriteLine("1ere ligne\ ligne\n3emeligne vive le C\"); |
|||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
La séquence d'échappement \f permet d'effectuer des sauts de pages pour l'impression de données. Par exemple copiez ce code dans un fichier que vous nommerez texte.cs |
|||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
//texte.cs /**************************************************/ /* */ /* affiche 3 pages */ /* */ /**************************************************/ //utiliser le namespace System using System ; /** * objet qui contient notre fonction main */ class TroisiemeProgramme { /** * méthode principale du programme */ public static void Main() { Console.Out.Write("première page"); Console.Out.WriteLine('\f'); Console.Out.Write("seconde page"); Console.Out.WriteLine('\f'); Console.Out.WriteLine("troisième page"); } } |
|||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
si vous l'exécutez, vous obtiendrez une sortie avec des caractères incompréhensibles. En redirigeant (par l'intermédiaire du caractère supérieur) la sortie vers l'imprimante grâce à la commande prn, vous imprimerez trois feuilles avec en haut de chacune d'elles première page, seconde page et troisième page. |
|||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
Terminons notre étude des caractères d'échappement en étudiant ceux qui comportent un nombre hexadécimal. Tous les caractères Unicode peuvent être représentés avec leur code hexadécimal. Les séquences d'échappement hexadécimales sont constituées d'une barre oblique inversée suivie d'une valeur en base 16. Le caractère # est codé en hexadécimal par la valeur 23. Ainsi l'instruction : |
|||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
Console.Out.WriteLine("langage C\x23"); |
|||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
donnera à la sortie : |
|||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
langage C# |
|||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
Les constantes chaînes de caractères permettent l'affichage de texte. Elle sont constituées d'une suite de caractères placés entre guillemets. Notre premier programme contenait ainsi la string |
|||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
"Bonjour de la part de C#" |
|||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
Comme nous l'avons vu précédemment les string peuvent contenir des caractères ordinaires mais aussi des séquences d'échappement. |
|||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
Séquences
d'échappement hexadécimales dans les
string |
|||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
\x21 |
|||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
Employée dans un WriteLine seule, cette séquence ne posera pas de problème : |
|||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
Console.Out.WriteLine("\x21"); |
|||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
Et donnera la sortie : |
|||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
! |
|||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
Mais si nous voulons afficher la sortie !exclamation une erreur risque de se produire : |
|||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
Console.Out.WriteLine("\x21exclamation"); |
|||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
donne la sortie |
|||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
?xclamation |
|||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
ce qui n'est pas ce que nous attendions. En réalité le compilateur n'a pas lu la séquence \x21 mais \x21e qui représente un caractère tout autre sur le point d'exclamation en Unicode. Ceci est souvent pour le programmeur une source d'erreurs incompréhensible et pourtant facilement débuggable . |
|||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
Les
strings verbatim |
|||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
\\server\share\file.txt |
|||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
il va nous falloir utiliser la string : |
|||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
"\\\\sever\\share\\file.txt"; |
|||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
dans l'instruction : |
|||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
Console.Out.WriteLine("\\\\sever\\share\\file.txt"); |
|||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
Heureusement C# permet de rendre cette instruction beaucoup plus représentable à l'aide de l'opérateur verbatim ( @ ). Celui-ci placé dans une chaîne de caractères demande au compilateur d'ignorer toutes les séquences d'échappement jusqu'au dernier guillemet de l'instruction et de les afficher telles quelles. |
|||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
Console.Out.WriteLine( @"\\sever\share\file.txt" ); |
|||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
Le
code est ainsi beaucoup plus lisible. |
|||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
Console.Out.WriteLine(@"ce livre a pour titre ""rivières pourpres"" ;\t il est bien"); |
|||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
Ce qui donnera la sortie : |
|||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
ce livre a pour titre "rivières pourpres" ;\t il est bien |
|||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
Le
verbatim a permis ici l'inclusion d'une sous string "rivières
pourpres" et a laissé la séquence d'échappement
\t telle quelle. |
|||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
Console.Out.WriteLine(@"ligne 1 ligne 2 ligne 3"); |
|||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
Ce qui donnera la sortie : |
|||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
ligne 1 ligne 2 ligne 3 |
|||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
Les string verbatim sont à utiliser avec modération, si elles peuvent rendre le code source plus lisibles dans bien des cas, elles peuvent leur rendre incompréhensible en cas d'utilisation trop importante. |
|||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
Intéressons-nous dès maintenant aux constantes nommées. Celles-ci sont des variables auxquelles il est impossible de changer une valeur. Contrairement aux constantes non nommées, les constantes de ce type disposent d'un identificateur auquel est associé une valeur dans le code source. Elles nécessitent une déclaration dans votre code source. |
|||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
La
déclaration d'une constante |
|||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
const type_de_la_constante nom_de_la_constante = valeur_de_la_constante [ nom_de_la_constante = valeur_de_la_constante, ]; |
|||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
Les crochets indiquent le facultatif : une instruction peut définir plusieurs constantes. Par exemple, l'instruction : |
|||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
const int jours = 365; |
|||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
définit
une constante de type int appelée jours qui a pour valeur
365. |
|||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
const byte âge= 23, taille = 185; |
|||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
permet
la création, en une instruction, de deux constantes de type
byte nommées âge et taille, en leur donnant
respectivement la valeur 23 et 185. Notons que si, dans les deux
derniers exemples, nous omettions le mot clé const, nous
déclarerions alors une variable. |
|||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
Const short x; |
|||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
Provoquera une erreur au moment de la compilation : |
|||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
constante.cs(28,18): error CS0145: A const field requires a value to be provided |
|||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
L'initialisation
d'une constante s'effectue à l'aide de l'opérateur
d'affectation = qui copie la valeur se trouvant à sa droite
(right value) dans l'opérande de gauche (left value) |
|||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
x = 92; |
|||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
provoquera une erreur : |
|||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
constante.cs(30,5): error CS0131: The left-hand side of an assignment must be a variable, property or indexer |
|||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
Tant qu'il existera, x représentera une valeur dans le programme. Celle-ci ne pourra plus être modifiée après sa création. |
|||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
Où déclarer ? |
|||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
Une déclaration de constante, tout comme une déclaration de variable, peut se faire n'importe où à l'intérieur d'une classe ou d'une méthode. Il est ainsi possible de générer un code ainsi : |
|||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
//constante.cs /**************************************************/ /* */ /* troisème programme d'apprentissage du C# */ /* (premiere version) */ /* */ /**************************************************/ //utiliser le namespace System using System ; /** * objet qui contient notre fonction main */ class Constante { /** * méthode principale du programme */ public static void Main() { Console.Out.Write("par "); const short x = 3; Console.Out.Write( x ); Console.Out.Write(" fois mon record au lancer de poids a été de "); const sbyte RECORD = -23; Console.Out.Write(RECORD); Console.Out.WriteLine(" metres. La valeur de PI vaut :"); const float PI = 3.14F; Console.Out.WriteLine( PI ); Console.Out.Write(". Queen a vendu "); const uint NOMBRE_ALBUMS = 175000000; Console.Out.Write(NOMBRE_ALBUMS); Console.Out.WriteLine(" albums dans le monde et un Euro vaut"); const decimal EURO = 6.7556624787854254857m; Console.Out.Write(EURO); Console.Out.WriteLine(" francs"); } } |
|||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
Pour
afficher la valeur d'une constante, d'une variable ou d'un handle,
il suffit de donner en paramètre à la méthode
WriteLine() ou Write() le nom de la constante voulue. La valeur de
celle-ci sera alors affichée sur la sortie standard. |
|||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
//constante.cs /**************************************************/ /* */ /* troisème programme d'apprentissage du C# */ /* (seconde version) */ /* */ /**************************************************/ //utiliser le namespace System using System ; /** * objet qui contient notre fonction main */ class Constante { /** * méthode principale du programme */ public static void Main() { const sbyte RECORD = -23; const short x = 3; const float PI = 3.14F; const decimal EURO = 6.7556624787854254857m; const uint NOMBRE_ALBUMS = 175000000; Console.Out.Write("par "); Console.Out.Write( x ); Console.Out.Write(" fois mon record au lancer de poids a été de "); Console.Out.Write(RECORD); Console.Out.WriteLine(" metres. La valeur de PI vaut :"); Console.Out.WriteLine( PI ); Console.Out.Write(". Queen a vendu "); Console.Out.Write(NOMBRE_ALBUMS); Console.Out.WriteLine(" albums dans le monde et un Euro vaut"); Console.Out.Write(EURO); Console.Out.WriteLine(" Francs"); } } |
|||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
Les constantes nommées permettent une sécurité du code en interdisant le programmeur d'en modifier la valeur par inadvertance, et en rendant le code source un peu plus lisible grâce au remplacement des valeurs numériques par des noms explicites. |
|||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
Lorsque la constante primitive est déclarée à l'intérieur d'une classe et à l'extérieur d'une méthode, c'est un membre de classe qui contient une valeur de référence. Si nous avions créé une classe mammifères, nous aurions pu lui donner le membre : |
|||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
class Mammifere { public const sbyte NOMBRE_DE_PATTES = 4; //... } |
|||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
car tous les mammifères ont quatre membres et cela ne risque pas de changer au cours des vingt prochains millions d'années. Un programmeur utilisant cette classe plus tard ne pourra pas changer la valeur de NOMBRE_DE_PATTES à 18 par inadvertance. |
|||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
Si les constantes sont un atout pour rendre un code clair en créant des données références dont la valeur ne peut changer, elles souffrent d'un grave défaut : elles sont constantes ! Heureusement le programmeur pour aussi faire appel à des variables qui, elles, peuvent contenir au cours de leur vie un grand nombre de valeurs (qui seront toujours du même type de la variable). Une variable est un emplacement mémoire d'un ou de plusieurs octets (suivant le type) qui fixe la manière dont ces octets sont à interpréter. Ainsi pour un emplacement de quatre octets, c'est en connaissant le type de la variable que nous saurons s'il s'agit d'un int ou d'un float. Pour que la variable soit localisable en mémoire centrale, on lui donne une adresse. Cette adresse nous importe peu pour l'instant car avec le nom de la variable nous allons pouvoir la manipuler dans nos programmes. |
|||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
Ici
notre variable a pour adresse 5423. L'emplacement d'une variable
est totalement imprévisible, il dépend de l'état
de la mémoire au moment de l'exécution du
programme. |
|||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
type_de_la_constante nom_de_la_constante [= valeur_de_la_constante] [ nom_de_la_constante = valeur_de_la_constante, ]; |
|||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
comme on le voit ici, une variable ne doit pas nécessairement être initialisée lors de sa déclaration. Ainsi l'instruction : |
|||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
long population; |
|||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
déclare
une variable de type long nommée population. |
|||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
int resultat1, resultat2, resultat3; |
|||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
Déclare trois variables nommées respectivement resultat1, resultat2 et resultat3 de type int. Sachant qu'un int occupe quatre octets en mémoire, nous réservons donc 4 * 3 octets soit 12 octets. |
|||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
En l'absence d'initialisation d'une variable, le compilateur générera une erreur si le programmeur veut l'utiliser. Le code suivant : |
|||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
//variable.cs /**************************************************/ /* */ /* programme montrant le */ /* fonctionnement des variables */ /* */ /**************************************************/ //utiliser le namespace System using System ; /** * objet qui contient notre fonction main */ class Variable { /** * méthode principale du programme */ public static void Main() { long population; Console.Out.WriteLine(population); } } |
|||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
génèrera l'erreur suivante : |
|||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
L'initialisation se fait ici aussi à l'aide du signe égal lors de la création de la variable : |
|||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
/** * méthode principale du programme */ public static void Main() { long population = 3; Console.Out.WriteLine(population); } } |
|||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
En
initialisant la variable population, comme ci-dessus, la
compilation se déroulera sans aucun problème. |
|||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
int resultat1 = 15, resultat2 = 12, resultat3 = 6; |
|||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
La valeur d'une variable peut être modifiée après sa déclaration. Qu'il y ait eu ou non initialisation. On utilise ici aussi l'opérateur égal = pour affecter à la variable une nouvelle valeur. |
|||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
ushort poids; //... poids = 423; |
|||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
Dans le code ci-dessus, après la déclaration de la variable, on affecte la valeur 423 à la variable poids. Si poids possédait déjà une valeur, elle aurait été remplacée par la nouvelle. Nous aurions pu évidemment écrire : |
|||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
ushort poids = 423 ; |
|||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
mais il s'agirait ici d'une initialisation et non une affectation. L'initialisation d'une variable se fait au moment de sa déclaration, alors que l'affectation se fait à n'importe quel moment et dans un nombre indéfini de fois. L'opérande située à droite de l'opérateur = n'est pas forcément une constance non nommée. Avec les déclarations suivantes : |
|||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
int a = 1, b = 7; const int c = 12; |
|||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
il est possible de faire : |
|||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
b = a; |
|||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
mais aussi |
|||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
a = c; |
|||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
Nous transférons tout d'abord la valeur contenue par a dans b. Cette dernière est maintenant égale à la valeur de a (soit 1). Dans la deuxième instruction, nous transférons la valeur de la constante nommée c dans a. La variable a prend la valeur 12. |
|||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
Nous
venons de voir que les primitives déclarées à
l'intérieur d'une méthode devaient obligatoirement
être initialisées avant leur utilisation. Nous
pouvons en déduire qu'elles n'ont donc pas de valeur par
défaut lors de leur création. |
|||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
//troisiemeProgramme.cs /**************************************************/ /* */ /* troisième programme d'apprentissage du C# */ /* */ /**************************************************/ //utiliser le namespace System using System ; /** * objet qui contient notre fonction main */ class TroisiemeProgramme { /** * méthode principale du programme */ public static void Main() { Chien rex; } } /** * classe qui permet la création d'un objet de type Chien */ class Chien { /** * membre qui contient l'âge du chien */ byte age; /** * constructeur de notre classe chien */ public Chien() { Console.Out.WriteLine("création d'un chien"); } /** * méthode qui permet à notre chien d'aboyer */ public void Aboyer() { Console.Out.WriteLine("Ouah ! ouah ! grrrrrrrrrrrrrrrr Ouah !"); } /** * méthode qui permet à notre chien de couiner */ public void Couiner() { Console.Out.WriteLine("Kaï Kaï Kaï !!!!"); } /** * méthode qui permet à notre chien de sentir */ public void Sentir() { Console.Out.WriteLine("snif ? snif ! snif ?!"); } } |
|||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
Nous avons ajouté ici un membre de type byte, nommé âge, à la classe de type byte. Celui-ci est déclaré comme public afin que nous puissions accéder au membre depuis notre fonction Main. Il contiendra évidemment l'âge du chien. Voyons maintenant ce qui va se passer si, dans la fonction main, nous demandons d'afficher l'âge du chien sans avoir donné de valeur à ce membre : |
|||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
/** * méthode principale du programme */ public static void Main() { Chien rex; rex = new Chien(); Console.Out.Write("Rex a "); Console.Out.Write(rex.age); Console.Out.WriteLine(" an(s)"); } |
|||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
la compilation se déroule sans erreur mais avec un warning (le compilateur pense qu'il peut y avoir un problème) : |
|||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
TroisiemeProgramme.cs(51,15): warning CS0649: Field 'Chien.age' is never assigned to, and will always have its default value 0 |
|||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
Il
nous prévient ici que le membre âge de chien ne prend
jamais de valeur et qu'il lui en assigne une par défaut
(0). Il nous met donc en garde au cas où nous n'aurions pas
pensé à cette affectation forcée. |
|||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
création d'un chien Rex a 0 an(s) |
|||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
Remarquons
que nous utilisons ici aussi le point pour relier l'objet Chien
rex à une de ses variables d'instances(ici âge) tout
comme nous le faisions pour le relier à une de ses méthodes
dans le capitre précédent.
|
|||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
Pour
faire référence à un objet, une variable ou
une constance nommée, nous utilisons un identificateur. Cet
identificateur va nous permettre de manipuler soit une primitive
(pour les variables et les constantes), soit un objet (pour les
handles). |
|||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
Voyons cela concrètement en compilant le programme suivant : |
|||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
//exemplevisibilite.cs /**************************************************/ /* */ /* programme montre la portée et la */ /* la visibilitée des identificateurs */ /* */ /**************************************************/ //utiliser le namespace System using System ; /** * objet qui contient notre fonction main */ class ExempleVisibilite { static char membreCaractere = 'S'; /** * méthode principale du programme */ public static void Main() { int donnee = 10; Console.Out.Write("voici la valeur du membre variable membreCaractere: "); Console.Out.Write(" dans la méthode Main() : "); Console.Out.WriteLine(ExempleVisibilite.membreCaractere ); Console.Out.Write("voici la valeur de la variable donnée dans Main() : "); Console.Out.WriteLine(donnee); //nouveau bloc { string donneeBloc = "me voyez vous ?"; Console.Out.Write("voici la valeur de la variable donneeBloc dans Main() : "); Console.Out.WriteLine(donneeBloc); } //appel de la méthode visibilité ExempleVisibilite.Visibilite(); //enlevez le commentaire ci-dessous pour générer une erreur //Console.Out.WriteLine(donneeBloc); } /** * méthode pour démontrer les principes de la visibilité */ public static void Visibilite() { double donnee = 54.123589D; Console.Out.Write("voici la valeur de la variable donnée dans la"); Console.Out.Write(" méthode Visibilite(): "); Console.Out.WriteLine(donnee); Console.Out.Write("voici la valeur du membre variable membreCaractere "); Console.Out.Write(" dans la méthode Visibilite() : "); Console.Out.WriteLine(ExempleVisibilite.membreCaractere ); } } |
|||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
nous obtenons la sortie : |
|||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
voici la valeur du membre variable membreCaractere dans la méthode Main() : S voici la valeur de la variable donnee dans Main() : 10 voici la valeur de la variable donneeBloc dans Main() : me voyez vous ? voici la valeur de la variable donnee dans la méthode Visibilite: 54.123589 voici la valeur du membre variable membreCaractere dans la méthode Visibilite(): S |
|||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
Dans
ce programme, il y a plusieurs remarques à formuler : |
|||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
voici la valeur de la variable donnee dans la méthode Visibilite: 54.123589 |
|||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
La
variable de type int nommée donnee n'a donc pas de
visibilité ici ; elle est cachée par la variable de
même nom déclarée dans Visibilite(). |
|||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
double donnee = 54.123589D; |
|||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
alors le compilateur générera l'erreur suivante : |
|||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
exemplevisibilite.cs(62,27): error CS0103: The name 'donnee' does not exist in the class or namespace 'ExempleVisibilite' |
|||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
nous
indiquant qu'il n'y a aucun identificateur visible se nommant
donnee dans la méthode. La variable donnee de Main() n'est
évidemment plus visible après l'accolade fermante du
corps de cette méthode. |
|||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
//enlevez le commentaire ci-dessous pour générer une erreur //Console.Out.WriteLine(donneeBloc); |
|||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
si nous enlevons le commentaire, une erreur se produira. La variable nommée donneeBloc n'est en effet pas accessible en dehors du petit bloc dans lequel elle a été déclarée. |
|||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
Contrairement aux handles et aux noms de primitives, un identificateur de méthode a une portée qui s'étend à la totalité de la classe qui la contient. Ainsi dans le programme ci-dessus, la méthode Visibilite() se trouve après la méthode Main(). Mais lorsque cette dernière l'appelle, le compilateur ne génère pas d'erreur car il sait qu'elle existe. |
|||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
Les
objets n'ont pas de portée. Seul leur identificateur en a
une (c'est-à-dire le handle). |
|||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
Tous les types de C# ne sont évidemment pas des primitives. Nous allons maintenant voir deux classes dont nous allons souvent nous servir dans nos programmes ; la classe Object et la class String. |
|||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
Le
type object est le type ultime de C#. Une instance de cette classe
peut revêtir la forme de n'importe quel objet ou
primitive. |
|||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
//objets.cs /**************************************************/ /* programme montant le type Object en action */ /* */ /* */ /**************************************************/ //utiliser le namespace System using System ; /** * objet qui contient notre fonction main */ class Objet { /** * méthode principale du programme */ public static void Main() { Object premierObjet; System.Object secondObjet; object troisiemeObjet; } } |
|||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
nous créons trois variables de type Object à l'intérieur de la méthode principale Main() : |
|||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
/** * méthode principale du programme */ public static void Main() { Object premierObjet; System.Object secondObjet; object troisiemeObjet; } |
|||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
Dans le premier cas : |
|||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
Object premierObjet; |
|||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
Nous faisons appel à l'alias, le compilateur lit donc cette ligne ainsi : |
|||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
System.Object premierObjet; |
|||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
C'est à dire le namespace où se trouve les classes que nous utilisons (System) et le nom de la classe elle-même. A la seconde ligne de la méthode, cette notation est d'ailleurs présente en complet pour la création d'un deuxième objet de type Object. Enfin, en troisième ligne de Main(), nous utilisons le nom de la classe directement pour créer une variable. Ceci est possible car au début du programme nous avons donné l'instruction : |
|||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
using System ; |
|||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
qui
indique au compilateur que s'il ne connaît pas une classe
dans le source, c'est dans le namespace System qu'il la
trouvera. |
|||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
int i = 123; |
|||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
La ligne suivante applique une opération de boxing sur la variable i : |
|||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
object o = i; |
|||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
Par cette instruction, un objet de type Object est créé sur la pile. Celui-ci référence une valeur de type int sur le heap (tas). Cette valeur est une copie de la valeur de i. |
|||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
Voyons un exemple concret : |
|||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
Dans le même principe que la classe Object, le type string est un alias de System.String. Il est donc possible de créer un objet de type String de trois manières différentes : |
|||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
/** * méthode principale du programme */ public static void Main() { string premierObjet; System.String secondObjet; String troisiemeObjet; } |
|||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
Une string est une chaîne de caractères Unicode. Contrairement aux primitives standards, leur place en mémoire est totalement aléatoire et dépend de la longueur de la chaîne. Testons le comportement des strings : |
|||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
//strings.cs /**************************************************/ /* programme montrant le type String en action */ /* */ /* */ /**************************************************/ //utiliser le namespace System using System ; /** * objet qui contient notre fonction main */ class ChaineCaracteres { /** * méthode principale du programme */ public static void Main() { string chaine1 = new String("les strings..."); Console.Out.WriteLine(chaine1); string chaine2 = "se déchainent..."; Console.Out.WriteLine(chaine2); string chaine3 = chaine1; Console.Out.WriteLine(chaine3); chaine3 = "sont des objets spéciaux..."; Console.Out.WriteLine(chaine3); } } |
|||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
Notons tout d'abord que nous initialisons les strings de trois manières différentes . L'instruction : |
|||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
string chaine1 = new String("les strings..."); |
|||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
crée une string comme un objet. La constante string "les strings..." située entre les parenthèses du constructeur est un paramètre.du constructeur. |
|||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
Le constructeur va s'en servir pour initialiser la string. L'instruction : |
|||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
string chaine2 = "se déchainent..."; |
|||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
crée une string comme nous le ferions avec une primitive. Cette notation est équivalente à |
|||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
string chaine1 = new String("se déchainent..."); |
|||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
pour
le compilateur. Ce cas est une exception dans le principe de
création d'objets qui permet de pouvoir donner la
possibilité au programmeur de gérer le type string
comme une primitive. |
|||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
chaine3 = "sont des objets spéciaux..."; |
|||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
Le programme nous donne la sortie : |
|||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
les strings... se déchainent... les strings... sont des objets spéciaux... |
|||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
Etudions plus en détail l'exemple de la variable chaine3 qui pointe sur le même objet que chaine1. Que se passera t'il si après une telle instruction nous changeons la valeur de chaine1 et que nous affichons chaine3 ? Voyons cela en changeant le programme comme ci-dessous : |
|||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
/** * méthode principale du programme */ public static void Main() { string chaine1 = new String("les strings..."); string chaine3 = chaine1; Console.Out.WriteLine(chaine3); Chaine1 = "sont des objets spéciaux..."; Console.Out.WriteLine(chaine3); } } |
|||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
nous obtenons la sortie : |
|||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
les strings... sont des objets spéciaux... |
|||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
contrairement
aux variables et aux constantes, qui ont leur propre emplacement
mémoire contenant une valeur, les handle chaine1 et chaine3
pointent toutes les deux sur un même objet situé dans
le tas. C'est cet objet qui a été modifié par
l'intermédiaire du handle chaine1 et c'est toujours lui qui
a été affiché par l'intermédiaire du
handle chaine3. |
|||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
/** * méthode principale du programme */ public static void Main() { string chaine1 = "les strings..."; Chaine1 = "sont des objets spéciaux..."; } } |
|||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
dans cet exemple nous créons un premier objet string qui contient la chaîne "les strings..." : |
|||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
string chaine1 = "les strings..."; |
|||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
Dans un second temps, nous faisons pointer notre handle sur un autre objet. Le premier objet qui contient la chaîne "les strings..." est donc perdu en mémoire. Le Garbage collector le détruira à sa prochaine activation. |
|||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
L'utilisation des strings verbatim est bien évidemment possible comme le montre l'exemple suivant : |
|||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
/** * méthode principale du programme */ public static void Main() { string chaine1 = @"c:\Docs\Source\a.txt" Console.Out.WriteLine(chaine1) } } |
|||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
qui donnera la sortie suivante : |
|||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
c:\\Docs\\Source\\a.txt" |
|||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
Lorsqu'un handle est déclaré avec le mot clé const la contrainte ne s'applique qu'à lui ; le handle ne pourra jamais plus pointer sur un autre objet que celui qu'on lui a donné à référencer lors de sa déclaration. Les caractéristiques de cet objets peuvent néanmoins être modifiées à la condition qu'elle ne soit pas elles-même déclarées avec const. |
|||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
Nous terminerons ce chapitre par l'étude d'un programme en mettant en avant les diverses notions que nous avons apprises : |
|||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
//ordinateurs.cs /**************************************************/ /* */ /* programme de démonstration finale des handles */ /* et des primitives */ /**************************************************/ //utiliser le namespace System using System ; /** * objet qui contient notre fonction main */ class TroisiemeProgramme { /** * méthode principale du programme */ public static void Main() { double tailleInstallationWindows = .6D; double memoireUtiliseeParWindows = 90.12D; Console.Out.Write("Aujourd'hui les pc possèdent des disques durs "); Console.Out.Write(" d'une capacité de "); Console.Out.Write(DisqueDur.capaciteMaximale); Console.Out.Write(" gigas(s) et une mémoire de "); Console.Out.Write(Memoire.capaciteMaximale); Console.Out.WriteLine(" mégas\n"); Ordinateur monPC = new Ordinateur(); monPC.hdd.memoireUtilisee = 0; Console.Out.Write("\nnous formatons le disque dur.\nla taille utlisée"); Console.Out.Write(" sur le disque est de :"); Console.Out.WriteLine(monPC.hdd.memoireUtilisee); monPC.hdd.memoireUtilisee = tailleInstallationWindows ; Console.Out.Write("\nnous installons Windows sur le pc,\nla taille utilisée "); Console.Out.Write(" sur le disque est de :"); Console.Out.WriteLine(monPC.hdd.memoireUtilisee); monPC.ram.memoireUtilisee = memoireUtiliseeParWindows ; Console.Out.Write("\nnous démarrons Windows sur le pc,\nmémoire prise est de :"); Console.Out.WriteLine(monPC.ram.memoireUtilisee); Console.Out.Write("\nbref il reste "); Console.Out.Write(Memoire.capaciteMaximale - monPC.ram.memoireUtilisee); Console.Out.Write(" mégas en ram et "); Console.Out.Write(DisqueDur.capaciteMaximale - monPC.hdd.memoireUtilisee); Console.Out.Write(" giga(s) sur le disque dur"); } } class Ordinateur { /** * membre disque dur de l'ordinateur */ public DisqueDur hdd; /** * membre mémoire de l'ordinateur */ public Memoire ram; /** * constructeur de la classe */ public Ordinateur() { Console.Out.WriteLine("un ordinateur a été construit"); Console.Out.WriteLine("il possède :"); //faire pointer le handle sur un nouvel objet disque dur hdd = new DisqueDur(); //faire pointer le handle sur un nouvel objet disque dur ram = new Memoire(); } } class DisqueDur { /** * membre indiquant la capacité maximale du disque dur * il est static car toutes les instances auront la même capacité. */ public static double capaciteMaximale = 45.0D; /** * membre indiquant la mémoire déjà occupée sur le disque dur * ce membre n'est pas statique car tous les disques durs ne sont pas * remplis de la même façon */ public double memoireUtilisee = 0; public DisqueDur() { Console.Out.Write("un disque Dur d'une capacité de "); Console.Out.Write(capaciteMaximale ); Console.Out.WriteLine(" giga(s) a été créé"); } } class Memoire { /** * membre indiquant la capacité maximale de la mémoire * il est statique car toutes les instances auront la même capacité. */ public statique double capaciteMaximale = 128.0D; /** * membre indiquant la mémoire déjà utilisée * ce membre n'est pas statique car toute la mémoire utilisée * dépend de l'utilisation de l'ordinateur. */ public double memoireUtilisee; public Memoire() { Console.Out.Write("une mémoire d'une capacité de "); Console.Out.Write(capaciteMaximale ); Console.Out.WriteLine(" mégas a été créée"); } } |
|||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
Enregistrez ce programme sous le nom ordinateurs.cs et compilez-le. A l'exécution vous obtenez la sortie : |
|||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
Aujourd'hui
les pc possèdent des disques durs d'une capacité de
45 gigas(s) et une mémoire de 128 mégas |
|||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
Etudions
ce programme plus en détails : |
|||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
/** * méthode principale du programme */ public static void Main() { double tailleInstallationWindows = .6D; double memoireUtiliseeParWindows = 90.12D; Console.Out.Write("Aujourd'hui les pc possèdent des disques durs"); Console.Out.Write(" d'une capacité de "); Console.Out.Write(DisqueDur.capaciteMaximale); Console.Out.Write(" gigas(s) et une mémoire de "); Console.Out.Write(Memoire.capaciteMaximale); Console.Out.WriteLine(" mégas\n"); Ordinateur monPC = new Ordinateur(); monPC.hdd.memoireUtilisee = 0; Console.Out.Write("\nnous formatons le disque dur.\nla taille utlisée"); Console.Out.Write(" sur le disque est de :"); Console.Out.WriteLine(monPC.hdd.memoireUtilisee); monPC.hdd.memoireUtilisee = tailleInstallationWindows ; Console.Out.Write("\nnous installons Windows sur le pc,\nla taille utilisée"); Console.Out.Write(" sur le disque est de :"); Console.Out.WriteLine(monPC.hdd.memoireUtilisee); monPC.ram.memoireUtilisee = memoireUtiliseeParWindows ; Console.Out.Write("\nnous démarrons Windows sur le pc,\nmémoire prise est de :"); Console.Out.WriteLine(monPC.ram.memoireUtilisee); Console.Out.Write("\nbref il reste "); Console.Out.Write(Memoire.capaciteMaximale - monPC.ram.memoireUtilisee); Console.Out.Write(" mégas en ram et "); Console.Out.Write(DisqueDur.capaciteMaximale - monPC.hdd.memoireUtilisee); Console.Out.Write(" giga(s) sur le disque dur"); } |
|||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
Ici, nous avons créé deux variables nommées tailleInstallationWindows qui indiquent la taille que prend Windows sur le disque dur et memoireUtiliseeParWindows qui donne la mémoire utilisée par Windows lorsque celui-ci est en fonctionnement. Le groupe d'instructions : |
|||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
Console.Out.Write("Aujourd'hui les pc possèdent des disques durs d'une capacité de "); Console.Out.Write(DisqueDur.capaciteMaximale); Console.Out.Write(" gigas(s) et une mémoire de "); Console.Out.Write(Memoire.capaciteMaximale); Console.Out.WriteLine(" mégas\n"); |
|||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
est intéressant dans la mesure où nous affichons les membres capaciteMaximale et memoireUtilisee en les référant par rapport à la classe et non à l'objet (car ils sont statiques). Jusqu'ici en effet pour accéder aux membres d'un objet nous indiquions le handle de l'objet suivi d'un point puis du membre lui-même. Ici c'est le nom de la classe qui est utilisé à la place du handle : |
|||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
Console.Out.Write(DisqueDur.capaciteMaximale); |
|||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
et |
|||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
Console.Out.Write(Memoire.capaciteMaximale); |
|||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
Le programme crée alors un objet Ordinateur : |
|||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
Ordinateur monPC = new Ordinateur(); |
|||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
Cette instruction va appeler le constructeur de la classe Ordinateur : |
|||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
/** * constructeur de la classe */ public Ordinateur() { Console.Out.WriteLine("un ordinateur a été construit"); Console.Out.WriteLine("il possède :"); //faire pointer le handle sur un nouvel objet disque dur hdd = new DisqueDur(); //faire pointer le handle sur un nouvel objet disque dur ram = new Memoire(); } |
|||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
Le constructeur crée deux objets de type DisqueDur et de type Memoire provoquant l'appel des constructeurs respectifs de ces deux classes. Il fait alors pointer les handles hdd et ram sur les deux instances ainsi créées. Le constructeur de DisqueDur ne fait rien d'autre que d'afficher sur la sortie qu'un objet a été créé : |
|||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
public DisqueDur() { Console.Out.Write("un disque Dur d'une capacité de "); Console.Out.Write(capaciteMaximale ); Console.Out.WriteLine(" giga(s) a été créé"); } |
|||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
celui de la classe Memoire fait lui aussi la même chose. |
|||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
public Memoire() { Console.Out.Write("une mémoire d'une capacité de "); Console.Out.Write(capaciteMaximale ); Console.Out.WriteLine(" mégas a été créée"); } |
|||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
Dans le groupe d'instruction suivant nous manipulons les membres des deux objets hdd et ram appartenant à notre objet monPC |
|||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
monPC.hdd.memoireUtilisee = 0; Console.Out.Write("\nnous formatons le disque dur.\nla taille utlisée"); Console.Out.Write(" sur le disque est de :"); Console.Out.WriteLine(monPC.hdd.memoireUtilisee); monPC.hdd.memoireUtilisee = tailleInstallationWindows ; Console.Out.Write("\nnous installons Windows sur le pc,\nla taille utilisée"); Console.Out.Write(" sur le disque est de :"); Console.Out.WriteLine(monPC.hdd.memoireUtilisee); |
|||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
Nous initialisons tout d'abord la place prise sur le disque dur de notre ordinateur à 0 ! |
|||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
monPC.hdd.memoireUtilisee = 0; |
|||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
Pour accéder à ce membre nous donnons le nom de notre objet ( monPC) suivi du nom de l'objet de type DisqueDur qui lui appartient (hdd). Puis nous donnons le membre de cet objet que nous voulons atteindre, le tout séparé par des points. Nous pourrions lire l'instruction ci-dessus comme "le membre mémoireUtilisé de l'objet hdd de l'objet monPC doit prendre la valeur 0". Les trois lignes de code suivantes : |
|||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
monPC.hdd.memoireUtilisee = tailleInstallationWindows ; Console.Out.Write("\nnous installons Windows sur le pc,\nla taille utilisée"); Console.Out.Write(" sur le disque est de :"); Console.Out.WriteLine(monPC.hdd.memoireUtilisee); |
|||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
font la même chose mais avec le membre ram de l'objet monPC. Enfin le dernier groupe d'instructions : |
|||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
monPC.ram.memoireUtilisee = memoireUtiliseeParWindows ; Console.Out.Write("\nnous démarrons Windows sur le pc,\nmémoire prise est de :"); Console.Out.WriteLine(monPC.ram.memoireUtilisee); Console.Out.Write("\nbref il reste "); Console.Out.Write(Memoire.capaciteMaximale - monPC.ram.memoireUtilisee); Console.Out.Write(" mégas en ram et "); Console.Out.Write(DisqueDur.capaciteMaximale - monPC.hdd.memoireUtilisee); Console.Out.Write(" giga(s) sur le disque dur"); |
|||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
Se contente d'afficher les valeurs des différents membres des objets de monPC. Notons ici l'utilisation par deux fois de l'opérateur de soustraction - : |
|||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
Console.Out.Write(Memoire.capaciteMaximale - monPC.ram.memoireUtilisee); |
|||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
et |
|||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
Console.Out.Write(DisqueDur.capaciteMaximale - monPC.hdd.memoireUtilisee); |
|||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
Qui demande au compilateur de soustraire la capacitéMaximal de la mémoire ou du disque dur, par la mémoire déjà occupée et d'afficher le résultat (nous reviendrons sur les opérateurs dans le chapitre 6). |
|||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||