Exood4 Studio - Video Game Development, Toulouse (France)
Exood4 Studios Exood4 Tutorials

   
L a n g a g e   C++

L e   p a s s a g e   d e   C   à   C + +




 C++ est un sur-ensemble du C tel qu'il est défini dans la norme ANSI. Ce qui signifie que C++ est compatible avec C : il utilise les types fondamentaux char, int, float, double ... Mais le C++ permet d'aller plus loin pour construire des nouveaux types de données et faire de la Programmation Objet en utilisant des types abstraits. Il a été conçu pour rendre la programmation plus agréable.


Incompatibilités entre C et C++


1) Déclarations des fonctions

 En C++ toute fonction utilisée doit obligatoirement avoir fait l'objet :

  • soit d'une déclaration sous forme de prototype :

    float fct (int,double,char);

  • soit d'une définition préalable au sein du fichier source, avec chaque argument précédé de son type :

    float fct (int x, double y, char z)
    {
     ...
    }

    Une fonction sans valeur de retour doit obligatoirement être de type void.

  • contrairement au C, une fonction C++ qui n'a pas d'argument n'a pas besoin d'avoir void comme paramètre :

    int fct (void); // fonction sans argument en C
    int fct (); // fonction sans argument en C++

2) Les constantes

 La norme C Ansi a introduit le qualificatif const pour déclarer des constantes. On peut également les simuler en utilisant les macros : #define. Les constates sont des entités à part entière. Une constante se déclare de la même façon qu'une variable initialisée mais elle est introduite par le mot réservé const. Il est impossible de modifier le contenu d'une constante.

const float pi = 3.14159;
const char espace = ' ';

 C++ admet également l'utilisation des constantes. Lorsque const s'applique à des variables locales automatiques, aucune différence n'existe entre C et C++; la portée étant limitée au bloc ou à la fonction concernée par la déclaration. Par contre, lorsque const s'applique à une variable globale, C++ limite la portée du symbole au fichier source concernant la déclaration (le langage C ne fait aucune limitation).


Remarque :
Les constantes sont souvent utilisées en C++ dans le cas où les arguments de fonction sont passés par référence alors qu'on ne doit en aucun cas les modifier dans le corps de la fonction.
float moyenne (const int notes[], int nbnotes)
{
 float somme = 0;
 for (int i = 0; i < nbnotes; i++) somme = somme + notes[i];
 return (somme / nbnotes);
}


3) Définition d'une structure

 En C, lorsqu'on définit une structure, il est nécessaire de rappeler struct pour déclarer des variables de ce type :

struct point
{
 float abscisse;
 float ordonnee;
};

struct point a, b;

 Pour éviter le rappel dans une déclaration de variable, on peut introduire une structure par l'intermédiaire d'une définition de type en utilisant le qualificatif typedef :

typedef struct point
{
 float abscisse;
 float ordonnee;
};

point a, b;

 En C++ une structure n'a plus besoin d'être introduite par le qualificatif typedef :

struct point
{
 float abscisse;
 float ordonnee;
};

point a, b;


Spécificités de C++


 C++ dispose, par rapport au C, d'un certain nombre de spécificités qui ne sont pas véritablement axées sur la Programmation Objet.


1) Les entrées/sorties

 cin et cout remplacent avantageusement les fonctions printf() et scanf() de la librairie standard d'entrées-sorties du C dont les spécifications se trouvent dans le fichier d'en-tête <stdio.h> :
  • cout affiche sur la sortie standard stdout les valeurs des différentes expressions, suivant une présentation adaptée à leur type.

    cout <<expression1<<expression2<< ... <<expressionN;

  • cin lit sur l'entrée standard stdin les différentes valeurs et les affecte aux identificateurs de variables précisés dans l'appel.

    cin >>idenfiticateur1>>identificateur2>> ... >>identificateurN;
 Pour pouvoir utiliser cin et cout, il faut inclure le fichier d'en-tête <iostream.h> dans le programme source :

#include <iostream.h>
void main()
{
 int a,b;
 cout << "Entrer deux entiers";
 cin >> a >> b;
 cout << "le produit de " << a << " par " << b << "\nest : " << a*b;
}

Remarques :
  • Le manipulateur flush permet de forcer le vidage de la mémoire tampon associée au fichier de sortie

  • Le manipulateur endl insère d'abord le caractère '\n' avant de faire flush
#include <iostream.h>
void main()
{
 int a,b;
 cout << "Entrer deux entiers" << flush;
 cin >> a >> b;
 cout << "le produit de " << a << " par " << b << "\nest : " << a*b << endl;
}


2) Les commentaires

 C++ admet une autre forme de commentaires en utilisant //. La fin de ligne est considérée comme fin de commentaire.

void main()
{
 int a=5, b=8;
 // déclarations de deux variables
 a = a + b;
 // somme
 // de deux variables
}


3) La déclaration des variables

 En C, il est nécessaire de déclarer toutes les variables en début de bloc { .. } ou en début de programme. En C++, la déclaration peut se faire n'importe où. La portée reste limitée au bloc ou à la fonction suivant l'endroit où elle a été déclarée.

void main()
{
 int nb;
 cout << "taille du tableau :";
 cin >> nb;
 int t[nb];
 for (int i = 0; i < nb; i++)
 {
 cout << "entrer une valeur :";
 cin >> t[i];
 }
 ...
}


4) Les références

 Une donnée est accessible soit par le nom d'une variable, soit par l'adresse de la case mémoire où elle est stockée. Il est possible de faire référence à la même zone qui contient la donnée en utilisant une seconde référence.

int i = 1;
int &j = i;
i++; // i et j valent 2
j++; // i et j valent 3

Remarque :
Il n'y a aucune opération sur la référence mais uniquement sur l'objet référencé.

5) La transmission par référence

 En C, la transmission des paramètres par référence n'existe pas. On est obligé de la gérer en manipulant explicitement des pointeurs. En C++, la transmission par référence est possible en faisant précéder le nom de l'argument dans l'en-tête d'une fonction par le symbole &.


Langage C
Langage C++
#include <stdio.h>

void somme (int x, int y, int *z)
{
 *z = x+y;
}

void main(void)
{
 int a, b, c;

 printf ('entrer a ';);
 scanf ("%d",&a);
 printf ("entrer b");
 scanf ("%d",&b);
 somme (a, b, &c);
 printf ("somme : %d\n",c);
}
#include <iostream.h>

void somme (int x, int y, int &z)
{
 z = x + y;
}

void main()
{
 int a, b, c;

 cout << "entrer a ";
 cin >> a;
 cout << "entrer b ";
 cin >> b;
 somme (a, b, c);
 cout << "somme : " << c << "\n";
}


6) Les arguments par défaut

 Dans la déclaration d'une fonction il est possible de prévoir pour un ou plusieurs arguments une valeur par défaut. Elle est indiquée par le symbole = à la suite de l'argument. Les arguments par défaut sont obligatoirement les derniers de la liste.

#include <iostream.h>

int somme (int x, int y=1, int z=1)
{
 return (x+y+z);
}

void main()
{
 int a=2, b=3, c=4;

 cout << "somme : " << somme (a, b, c) << "\n"; // somme : 9
 cout << "somme : " << somme (a, b) << "\n"; // somme : 6
 cout << "somme : " << somme (a) << "\n"; // somme : 4
}


7) La surcharge des fonctions

 Au sein d'un même programme, il est possible que plusieurs fonctions possèdent le même nom. Le choix de la fonction utilisée dépendra du type des arguments à l'appel.

float somme (float x, float y) { return (x+y); }

int somme (int x, int y) { return (x+y); }

void main ()
{
 int a=3, b=4;
 float c=2.5, d=1.0;

 cout << somme (a, b) << "\n"; // 7
 cout << somme (c, d) << "\n"; // 3.5
}


8) Allocation dynamique

 En C++, les fonctions malloc() et free() sont remplacées par les opérateurs new et delete.

Exemple : allocation dynamique d'un emplacement mémoire pour y mettre un réel

Langage C
Langage C++
#include <stdlib.h>
...
float *x;
x = (float *) malloc (sizeof(float));
*x = 126.5;
...
free(x);
...

...
float *x;
x = new float;
*x = 126.5;
...
delete x;
...

 En cas de succès, l'opérateur new fournit un pointeur sur la zone mémoire allouée. En cas d'échec, new retourne un pointeur NULL. L'opérateur delete, quant à lui permet de libérer la place mémoire allouée par new.


Exemple : on veut allouer et libérer dynamiquement un emplacement mémoire de 20 caractères consécutifs

char *ptr_tab;

ptr_tab = new char[20];
delete ptr_tab; // équivalent à : delete[20] ptr_tab


9) L'opérateur de portée

 En C, tout variable globale est masquée dans un bloc si une variable locale de même nom y est déclarée; la variable globale est donc inaccessible dans ce bloc.

int var = 1;
...
void fct()
{
 int var = 134;

 printf ("%d\n", var); // affiche 134
}

 En C++, il existe un opérateur (noté '::') appelé opérateur de résolution de portée, qui permet l'accès explicite à une variable globale.

int var = 1;
...
void fct()
{
 int var = 134;

 cout << var << ::var; // affiche 1 et 134
}


10) Les conversions explicites

 En C, pour effectuer une conversion explicite, on utilise un forçage de type (cast) qui permet de transformer une expression dans le type voulu : (type) expression

Exemple : double moyenne = (double) somme/nb;

 C++ autorise une autre écriture pour réaliser la même chose : type (expression)

Exemple : double moyenne = double(somme)/nb


Remarque :
En C++, le type void *, contrairement au C, ne peut être converti implicitement en un pointeur d'un autre type. Il faut obligatoirement effectuer un forçage de type. Par contre tout pointeur peut être converti implicitement en un pointeur de type void *.

11) Les fonctions "en ligne"

 En C, lorsque le corps d'une fonction est courte et que le temps d'exécution est à privilégier par rapport à l'espace mémoire, on utilise une macro. En C++, l'écriture des fonctions peut se faire "en ligne" par l'intermédiaire du qualificatif inline. Dans la macro, la substitution se fait par le préprocesseur, dans la fonction inline, le compilateur sait que chaque occurrence de l'appel de la fonction devra être remplacée par le code machine correspondant.

 Ce type de fonction permet également d'avoir un contrôle plus strict au niveau des paramètres transmis.

// macro de calcul d'un maximum
#define max(a,b) a>b?a:b // aucun contrôle sur le type de a et b

// fonction en ligne du calcul du maximum
inline int max (int a, int b) { return (a>b?a:b); } // ici a et b devront être des entiers


 Limite des fonctions inline :
Le compilateur peut très bien ignorer une fonction inline si cette dernière est trop "complexe". Par exemple, dans le cas d'une fonction trop longue ou contenant des boucles, le compilateur la considèrera comme une fonction simple. Il est donc nécessaire d'utiliser les fonctions inline pour des opérations rapides (séquences d'instructions, affectations etc...)


12) Les fonctions génériques

 Une fonction générique est une fonction qui ne dépend pas des types des arguments instanciés. Un mécanisme très puissant est prévu en C++ pour pouvoir créer des fonctions génériques tout en conservant le contrôle de type : c'est le concept des templates.

 Pour créer une fonction générique, l'en-tête de la fonction doit être précédée du mot réservé template suivi d'une liste de paramètres entre les symboles < > Chaque paramètre doit être de la forme : class identificateur. Le choix de l'identificateur est laissé au programmeur. L'identificateur représente un type qui est instancié au moment de la compilation par un type existant.


Exemple :
La permutation de deux valeurs entières et deux valeurs réelles nécessite l'écriture de deux fonctions distinctes dont les instructions sont identiques excepté le type des variables. L'écriture d'une fonction générique permut() permet d'éviter cette redondance de code :
template <class T>
void permut (T &a, T &b)
{
 T c;

 c = a; a = b; b = c;
}

void main ()
{
 int x=5, y=8;
 float z=2.5, t=8.9;

 permut (x, y);
 permut (z, t);
}

Remarque :
Le compilateur détecte une erreur si à l'appel de la fonction les deux paramètres sont de types différents.
 Pour utiliser des types génériques différents dans une fonction générique, il suffit de fournir des noms symboliques différents.

template <class T1, class T2>
void fct (T1 a, T2 b)
{
 ...
}


  Retour en haut de page Page suivante