next up previous contents index
suivant: Élection d'un chef à monter: main précédent: Argument tableau pluridimensionnel d'une   Table des matières   Index


Structures

Les structures sont des types de données permettant de construire un objet en regroupant plusieurs autres objets. Elles sont l'analogue des enregistrements de Pascal (record) ou de CAML, et un cas particulier des classes (class) de C++ ou de Java, construction essentielle pour la programmation à objets. Un exemple simple est celui des nombres complexes, représentés par le type suivant :


struct complexe {
  double re;
  double im;
};

Il s'agit de la définition d'un nouveau type, de nom complexe, ayant deux champs re et im de type double. On n'oubliera pas le << ; >> qui suit l'accolade fermant la définition. La définition suivante déclare z comme un nom dont le type est complexe, et alloue un bloc de mémoire pouvant contenir deux doubles.


  complexe z;

Le nom z désigne alors ce nouvel objet, qui a deux sous-objets de type double ; ces sous-objets sont désignés par les expressions z.re et z.im, elles-même de type double. Une structure peut être initialisée lors de sa définition de la façon suivante :


complexe z = {1.0, 2.0};

Les structures sont des valeurs qui peuvent être passées en argument des fonctions et retournées par celles-ci. Comme pour tout autre type de données, le passage des arguments et du résultat peut se faire par valeur, ou si le type du paramètre ou le type de retour est suivi de &, par référence. On définira par exemple l'impression d'un nombre complexe et l'addition de deux nombres complexes par


void complexe_print(complexe z) {
  cout << z.re << " + " << z.im << " i";
}   

complexe complexe_add(complexe z1, complexe z2) {
  complexe z = {
    z1.re + z2.re,
    z1.im + z2.im
  };
  return z;
}

Deux structures ne pouvant pas être comparées par == ou !=, il faudra le cas échéant construire ses propres fonctions de comparaison. Par exemple, pour les complexes :


bool complexe_eq(complexe z1, complexe z2) {
  return z1.re == z2.re && z1.im == z2.im;
}

Tableaux et structures sont des constructions très différentes, malgré les apparences. Une première différence est que les sous-objets d'un tableau (ses éléments) sont tous de même type, tandis que ceux d'une structure (ses champs) peuvent être de types distincts. On utilise souvent les structures en tant qu'<< enregistrement >> d'un individu avec des champs pour son nom, sa date de naissance, son adresse, son numéro de téléphone, etc.

La différence la plus importante concerne la notion de valeur. Avec les définitions


  double t[2] = {1.0, 2.0};
  complexe z = {1.0, 2.0};

dans les deux cas, il y allocation d'un bloc mémoire contenant les deux flottants $1.0$ et $2.0$ ; mais l'expression t est une constante dont la valeur est l'adresse du bloc alloué, tandis que l'expression z est une variable dont la valeur est la structure elle-même. Ainsi, les tableaux ne peuvent pas être affectés (t = ... est interdit), tandis que les structures peuvent l'être : z = ... est permis, ainsi que ... = z. L'affectation des structures signifie une copie de l'objet, qui peut être coûteuse en temps et en espace pour de grosses structures. Cependant, aussi bien t[0] et t[1] que z.re et z.im désignent des objets (qui sont les sous-objets du tableau ou de la structure).

Pour éviter la copie d'un objet, réalisée au cours du passage par valeur des arguments d'une fonction, il est presque toujours préférable de passer les structures par référence. Dans ce cas, pour ne pas risquer de modifier ces arguments, on les passe par référence à des constantes. Par exemple, la comparaison de nombres complexes (qui ne sont pourtant pas des structures volumineuses) devrait être programmée ainsi et utilisée comme auparavant :


bool complexe_eq(const complexe& z1, const complexe& z2) {
  return z1.re == z2.re && z1.im == z2.im;
}

Bien sûr, const ne doit pas être spécifié pour un paramètre passé par référence qui contiendra un résultat. Par exemple, si l'on programme l'addition comme une procédure à trois paramètres, les deux premiers étant les données (donc const) et le troisième le résultat (donc non-const), il faut la déclarer ainsi :


void add3(const complexe& z1, const complexe& z2, complexe& z);


next up previous contents index
suivant: Élection d'un chef à monter: main précédent: Argument tableau pluridimensionnel d'une   Table des matières   Index
R Lalement