Vous êtes sur la page 1sur 18

UVT - N2TR C++&Java

Chapitre I.II :Les bases du langage C++

Partie 2 : Nouvelles possibilités du C++


Dans cette section sont exposés les plus et les différences du C++ par rapport au C, sans toutefois
aborder la programmation orientée objet (P.O.O.) qui sera vue lors des prochains chapitres.

1.1. Les commentaires

En C++, les commentaires s’écrivent derrière un // et se terminent avec la fin de la ligne.

1.2. Le type supplémentaire


Les types de bases disponibles en C, tels que char, int, float, double, void sont également
disponibles en C++. Un type supplémentaire a été introduit pour manipuler de manière plus
rigoureuse et plus explicite les booléens, c’est le type bool. Les variables de type bool peuvent avoir
deux valeurs différentes : true ou false. Cependant, afin de rester compatible avec les variables
booléennes utilisées en C, il est toujours possible de stocker et de manipuler des booléens à partir de
variables de type int.

1.3. Le qualificatif « const »


C++ offre la possibilité de définir des entités constantes. La valeur de ces entités ne peut alors plus
être modifiée lors de l’exécution du programme, ce qui suppose qu’elles doivent être initialisées à la
déclaration.

1
UVT - N2TR C++&Java

Toute tentative de modification du contenu d’une constante génère une erreur à la compilation :
seules les opérations de lecture sont autorisées. On est donc assuré à la déclaration d’une telle entité
qu’aucune modification de valeur ne sera permise. Cette restriction entraîne qu’il n’est pas possible
de définir un pointeur « normal » sur une constante : le contenu de la constante pourrait alors être
modifié via le pointeur. On est alors obligé de définir un pointeur sur constante. De même, si on
souhaite que la valeur du pointeur ne soit pas modifiée au cours du programme, il faut définir un
pointeur constant sur constante.

2
UVT - N2TR C++&Java

1.4. La déclaration des variables


En C++, on peut déclarer les variables LOCALES au moment où on en a besoin.variable locale est
déclarée au début d’un bloc, sa portée est limitée à ce bloc.

Cette possibilité autorise une gestion plus précise de la mémoire, mais peut nuire à la structuration
des programmes.

3
UVT - N2TR C++&Java

1.5. Les nouvelles possibilités d’entrées/sorties


On peut utiliser en C++ les fonctions d’entrées/sorties classiques du C (printf, scanf, puts, gets,
putc, getc ...), à condition de déclarer le fichier d’en-tête stdio.h.
Il existe de nouvelles possibilités en C++, à condition de déclarer le fichier d’en-tête iostream.h.
Ces nouvelles possibilités ne nécessitent pas de FORMATAGE des données.

4
UVT - N2TR C++&Java

1.6. Les conversions de type


Le langage C++ autorise les conversions de type entre variables de type char, int, float, double.

a) Conversions de type à l’affectation

5
UVT - N2TR C++&Java

Une conversion de type float -->int ou char est dite dégradante


Une conversion de type int ou char --> float est dite non dégradante

b) Conversions de type lors d’appel à une fonction


Le C++, contrairement au C, autorise, dans une certaine mesure, le non-respect du type des
arguments lors d’un appel à une fonction : le compilateur opère alors une conversion de type.

1.7. Les arguments par défaut


En C++, on peut préciser la valeur prise par défaut par un argument de fonction. Lors de l’appel à
cette fonction, si on omet l’argument, il prendra la valeur indiquée par défaut, dans le cas contraire,
cette valeur par défaut est ignorée.

Remarques :

6
UVT - N2TR C++&Java

• Les arguments, dont la valeur est fournie par défaut, doivent OBLIGATOIREMENT se
situer en fin de liste. Autrement dit, dès qu’un argument reçoit une valeur par défaut, il faut
que tous les arguments qui le suivent le soient également.

Les déclarations suivantes sont interdites :

void F4 (char c=2, int n) ;

void F5 (int a=0, int b, int c=6);

• Les valeurs par défaut doivent être mentionnées uniquement dans la déclaration d’une
fonction.

1.8. La surdéfinition des fonctions


Le principe de la surcharge (overloading), appelée aussi surdéfinition, consiste à associer des sens
différents à un seul et même mot : En utilisant cette propriété de surdéfinition ou surcharge on peut
définir plusieurs fonctions qui sont différentes, mais portant le même nom, sachant que pour le
compilateur, la différenciation de fonctions ayant le même nom se fait par le type et le nombre de
paramètres de ces fonctions.

Le C++autorise la définition de fonctions différentes et portant le même nom.

7
UVT - N2TR C++&Java

1.9. Les opérateurs new et delete


Ces deux opérateurs remplacent malloc et free (que l’on peut toujours utiliser). Ils permettent de
réserver de la place en mémoire, et d’en libérer.

L’opérateur new alloue de l’espace mémoire à des objets de type élémentaire ou étendu.

• Pour allouer de la mémoire à un seul objet : ptr = new type ;

Avec ptr : pointeur contenant l’adresse du bloc alloué

type représente le type de l’objet qui occupera ce bloc

• Pour allouer de la mémoire à un tableau : ptr= new type [N];

Avec ptr : pointeur contenant l’adresse du bloc alloué)

type : représente le type des éléments du tableau

N : est une expression donnant le nombre d’éléments du tableau (N peut être une constante
ou une variable)

• Pour allouer de la mémoire à un tableau à plusieurs dimensions : ptr = new type [C1]
[C2] ... [Cn];

• Pour effacer un objet isolé, la syntaxe est : delete ptr ;

Avec ptr : pointeur contenant l’adresse du bloc alloué

8
UVT - N2TR C++&Java

• Pour effacer un tableau dynamique, la syntaxe est : delete [ ] ptr ;

Avec ptr : pointeur contenant l’adresse du bloc alloué

Remarques :

• II peut arriver qu’une tentative d’allocation se solde par un échec (par exemple, lorsqu’il n’y
a pas assez d’espace mémoire libre). Dans ce cas, il ne se produit pas d’erreurs au niveau de
l’exécution du programme, mais l’opérateur new va retourner un pointeur nul, contenant la
valeur NULL (constante représentant une adresse nulle). D’où, il est toujours conseillé de
faire un test après l’allocation

• Il ne faut pas utiliser conjointement malloc et delete ou bien new et free.

• En Turbo C++, l’opérateur new permet de réserver au maximum 64 Koctets en mémoire; La


fonction set_new_handler permet de gérer cette limite.

1.10.Le mot clé static


a) Les variables statiques
Rappel : Le mot clé STATIC permet de définir des variables statiques. Celles-ci sont alors stockées
dans un emplacement fixe en mémoire et existent pendant toute l’exécution du programme (les
variables globaux sont par défaut des statiques accessibles dans tout le fichier). Ainsi, lorsque le
mot clé static est placé devant la déclaration d’une variable locale, celle-ci devient une variable
statique qui gardera sa valeur dans un emplacement fixe à chaque nouvelle exécution de ce bloc.

9
UVT - N2TR C++&Java

Rappel : Initialisation / Affectation

Considérons la séquence d’instructions suivante :

int i = 3;

i++;
Ceci peut s’écrire, dans un autre style, mais ayant le même résultat :

int i;
i = 3;
i++;
En C il existe une totale équivalence, garantie, entre les deux écritures. L’opérateur = de
l’initialisation est traité de la même façon que celui de l’affectation.

i = 3 affectation
int i = 3 abus de langage, initialisation
Si on considère maintenant le qualificatif static appliqué à une variable locale

void F()
{static int i = 3;

10
UVT - N2TR C++&Java

i++;
}
L’initialisation n’est faite qu’une fois, lors de la déclaration de la variable. Cela illustre qu’il y a
quand même une différence entre une initialisation et une simple affectation.

b) Les fonctions statiques


Par défaut, lorsqu’une fonction est définie dans un fichier C/C++, elle peut être utilisée dans tout
autre fichier pourvu qu’elle soit déclarée avant son utilisation. Dans ce cas, la fonction est dite
externe. Il peut cependant être intéressant de définir des fonctions locales à un fichier, soit afin de
résoudre des conflits de noms (entre deux fonctions de même nom et de même signature mais dans
deux fichiers différents), soit parce que la fonction est uniquement d’intérêt local. Le C et le C++
fournissent donc le mot-clé static, qui, une fois placé devant la définition et les éventuelles
déclarations d’une fonction, la rend unique et utilisable uniquement dans ce fichier. À part ce détail,
les fonctions statiques s’utilisent exactement comme des fonctions classiques.

5.11. La notion de référence


En C, la notation &n signifie « l’adresse de la variable n »

11
UVT - N2TR C++&Java

En C++, cette notation possède deux significations :

• Il peut toujours s’agir de l’adresse de la variable n

• Il peut aussi s’agir de la référence à n

Seul le contexte du programme permet de déterminer s’il s’agit de l’une ou l’autre des deux
significations.

a) Le type référence
Le type référence est un type nouveau introduit par C++. C’est un nom alternatif ou un alias pour un
objet. La syntaxe de la déclaration d’une variable référence est la suivante :

Type & NomRef = VarAReferencer ;

Cette déclaration permet de définir une variable NomRef qui est une référence sur la variable
VarAReferencer qui est du type spécifié. VarAReferencer est une variable déclarée au préalable et
pour laquelle NomRef est un alias ou un synonyme.

Une variable de type Référence doit obligatoirement être initialisée lors de sa déclaration (càd,
associée à une variable déjà déclarée).

Ainsi déclarée et initialisée, une variable de type référence se comporte comme un synonyme de la
variable à laquelle elle a été associée --> tout se passe comme si les deux variables représentaient le
même objet en MC : càd que les opérations effectuées sur l’une affecte automatiquement l’autre.

Voici des exemples qui montrent qu’une référence se comporte comme un synonyme de la variable
précisée lors de l’initialisation.

12
UVT - N2TR C++&Java

Remarques

• Contrairement aux pointeurs, on ne peut pas modifier l’association d’une référence à sa


variable synonyme après sa déclaration. D’où l’intérêt des références, en effet l’utilisation
des pointeurs comme alias de variables est possible mais présente l’inconvénient que
l’adresse contenue dans un pointeur peut être modifiée. Le C++ offre avec les références une
alternative plus sûre : en effet, une variable référence ne peut être initialisée qu’une fois et
désigne ainsi toujours le même objet.

• Les variables références en tant que telles sont très peu utilisées. Elles sont principalement
utilisées dans la spécification des paramètres et dés valeurs de retour d’une fonction.

b) Le passage de paramètre par référence


Rappel :

13
UVT - N2TR C++&Java

En C, comme en C++, un sous-programme ne peut modifier la valeur d’une variable locale passée
en argument de
fonction. Pour
se faire, en C, il
faut passer
l’adresse de la
variable.

14
UVT - N2TR C++&Java

c) Retour de fonction par référence et par adresse


Le C permet, par utilisation des pointeurs, de manipuler les adresses de récipients, mais l’écriture
qui en découle n’est pas simple.

L’exemple illustre la création d’une variable i, par appel de fonction. C’est une variable locale (ou
"privée") de la fonction, que l’on ne peut atteindre autrement que par la fonction (forme
d’encapsulage). La fonction en fournit l’adresse en retour d’appel. On peut alors écrire le code du
main () suivant :

La fonction f () a une fonctionnalité de lvalue et de rvalue si, et seulement si, on utilise la notion de
pointeur. On a donc l’encapsulage (protection des accès directs aux données), même en C "normal".
Mais on doit systématiquement utiliser la notion de pointeur. Par contre, on sait écrire

*f() = *f();

15
UVT - N2TR C++&Java

En C++, la fonction f() en tant que valeur de retour peut devenir une lvalue (l’appel de fonction peut
devenir un récipient, et non plus rester une simple rvalue). On déclare la fonction f() comme
retournant un récipient (retourne une référence sur un objet).

La fonction retourne i, mais celui-ci est commue en une référence. C’est le "mot" f qui est en fait
une référence sur i. Dans le programme appelant, on trouve la notation suivante :

f() = f();

On a, pour l’instruction d’affectation,

• f () à gauche est une référence sur i (lvalue). On a l’impression de travailler sur l’adresse et
de faire l’équivalent du *f() dans la manipulation des pointeurs.

• f () à droite est la valeur de i (rvalue)

Ce qui permet d’écrire quelque chose d’impossible en C : f() = 3;

En C on se fait jeter par le compilateur, avec un message du type " left-value required". En effet,
une affectation exige un récipient en opérande gauche. Or une fonction C est une right-value. Si la
fonction f() retourne un pointeur, adresse d’un récipient, alors on doit écrire en C : *(f()) = 3;

Le retour de la fonction est ambigu. On retourne une valeur. Mais i est aussi un entier, c’est donc
aussi une variable. Si à l’arrivée dans le code de la fonction i vaut 3, on retourne la valeur 4. Mais
on retourne aussi l’endroit où réside cette valeur (son adresse !). On a donc deux informations qui
sont retournées dans le cas d’un retour de fonction défini comme une référence :

• la valeur

• sa localisation

On peut alors écrire le code du main () suivant :

16
UVT - N2TR C++&Java

Lorsqu’on manipule une référence, rien ne la distingue de la variable à laquelle elle correspond, ni
de la valeur que celle-ci contient.

Axiome : toute utilisation d’une référence est totalement équivalente à l’utilisation d’une variable
"normale".

La transparence reste totale lorsqu’on manipule des objets de type composé tels des structures :

Remarque : on peut constater que ce genre de fonction ne marche que pour des objets statiques.

1.11.Les fonctions inline


Les fonctions offrent beaucoup d’avantages, mais ont un inconvénient majeur lorsque le nombre
d’instructions qu’elles comportent est réduit : elles sont coûteuses en temps d’exécution (exemple :
fonction int min(int a, int b);). En effet, à chaque appel de fonction, le système met à jour un certain
nombre de valeurs (essentiellement avec la pile) et effectue d’autres mises à jour lors de la
terminaison de la fonction. Le coût de ces mises à jour est d’autant plus élevé (relativement) que le
nombre d’instructions contenues dans la fonction est réduit, ce qui peut être critique dans des
traitements exigeant de hautes performances. On peut cependant vouloir garder la structure offerte
par les fonctions pour des raisons de lisibilité, d’uniformisation, de réutilisation. La solution est de
définir ce genre de fonctions comme inline.

17
UVT - N2TR C++&Java

En rajoutant le mot-clé inline lors de la définition de la fonction, la fonction est considérée comme
inline : chaque appel fait à la fonction sera remplacé par le code source correspondant à la fonction.
On dit que la fonction est expansée à son point d’appel.

Remarques :

i. inline est utile pour les applications sensibles au temps d’exécution.

ii. Pour bénéficier de cette fonctionnalité, la fonction doit être définie et déclarée inline.

iii. la déclaration inline d’une fonction n’est qu’une recommandation faite au compilateur, qui
peut décider ou non d’effectivement laisser cette fonction inline. En particulier, si le corps
de la fonction est trop important, il y a peu de chances que la fonction reste inline (il y a peu
de gain) cette technique s’avérant rentable uniquement sur les fonctions comportant peu
d’instructions.

18

Vous aimerez peut-être aussi