Vous êtes sur la page 1sur 29

Chapitre 1

DE C À C++
Master SEIB
2019-2020
Azzedine DLIOU
Ecole Nationale des Sciences appliquées
Université Ibn Zohr
Plan
 Introduction
 Déclarations de fonctions
 Fonctions sans arguments
 Fonctions sans valeur de retour
 Le qualificatif const
 Nouvelles possibilités d’entrées-sorties
 Emplacement libre des déclarations
 La transmission par référence
 Les arguments par défaut
 Surdéfinition de fonctions
 Pointeur générique
 Gestion dynamique de la mémoire
Introduction
 Le langage C++ a été conçu à partir de 1982 par Bjarne
Stroustrup (AT&T Bell Laboratories), comme une extension
du langage C, lui-même créé dès 1972 par Denis Ritchie,
formalisé par Kerninghan et Ritchie en 1978.

 L’objectif principal de B. Stroustrup était d’ajouter des classes


au langage C et donc, en quelque sorte, de « greffer » sur un
langage de programmation procédurale classique des
possibilités de « programmation orientée objet » (en abrégé
P.O.O.).

 C++ est presque un sur-ensemble du C, tel qu’il est défini par


la norme ANSI.
Déclarations de fonctions
 En C++, toute fonction utilisée dans un fichier
source doit obligatoirement avoir fait l’objet :

1. Soit d’une déclaration sous forme d’un


prototype, par exemple :

float fct (int, double, char *);

2. Soit d’une définition préalable au sein du même


fichier source.
Fonctions sans arguments
 En C++, une fonction sans argument se définit et se
déclare en fournissant une « liste d’arguments vide »
comme dans :
float fct ();
 En C, on pouvait indifféremment utiliser cette
notation ou faire appel au mot-clé void, comme
dans :
float fct (void);
Fonctions sans valeur de retour

 En C++, une fonction sans valeur de retour se


définit et se déclare obligatoirement à l’aide du
mot-clé void, comme dans :

void fct (int, double);

 En C, l’emploi du mot-clé void était, dans ce cas,


facultatif.
Le qualificatif const
 En C++, un symbole global déclaré avec le
qualificatif const : peut être utilisé dans une
expression constante (calculable au moment de la
compilation), alors qu’il ne pouvait pas l’être en C ;

 Ce dernier point permet notamment d’utiliser de


tels symboles pour définir la taille d’un tableau (en
C, il fallait obligatoirement avoir recours à une
définition de symboles par la directive #define).
Nouvelles possibilités d’entrées-sorties
 C++ dispose de nouvelles facilités d’entrées-sorties,
bien qu’elles soient fortement liées à des aspects
P.O.O. (surdéfinition d’opérateur en particulier), elles
sont parfaitement utilisables en dehors de ce
contexte.

 C’est tout particulièrement le cas des possibilités


d’entrées-sorties conversationnelles (clavier, écran)
qui remplacent avantageusement les fonctions printf
et scanf.
Nouvelles possibilités d’entrées-sorties
 Ainsi :
cout << "donnez un entier et un flottant\n";

Remplace :

printf ("donnez un entier et un flottant\n");

 De même :

cin >> n >> x ;

Remplace :

scanf ("%d %f", &n, &x) ;


Nouvelles possibilités d’entrées-sorties
 De manière générale :
cout << expr1 << expr2 << ..... << exprn;
affiche les valeurs des différentes expressions indiquées,
selon une présentation adaptée à leur type (on sait
distinguer les attributs de signe et on peut afficher des
valeurs de pointeurs).

 De même :
cin >> var1 >> var2 >> ..... >> varn;
Lit des informations de l’un des types char, short, int, long,
float, double ou char * ( les pointeurs ne sont pas admis).
Emplacement libre des déclarations

 En C++, il n’est plus nécessaire de regrouper les


déclarations en début de fonction ou en début de
bloc. Par exemple :
int n ;
.....
n = ... ;
.....
int q = 2*n - 1 ;
.....
Emplacement libre des déclarations

 Ces possibilités s’appliquent également aux


instructions structurées for, switch, while et
do...while, comme dans cet exemple :
for (int i=0 ; ... ; ...)
// la portée de i est limitée au bloc qui suit
{
.....
}
La transmission par référence

 En faisant suivre du symbole & le type d’un argument


dans l’en-tête (et dans le prototype) d’une fonction,
on réalise une transmission par référence.
 Cela signifie que les éventuelles modifications
effectuées au sein de la fonction porteront sur
l’argument effectif de l’appel et non plus sur une
copie.
 On notera qu’alors l’argument effectif doit
obligatoirement être une variable du même type que
l’argument muet correspondant.
La transmission par référence

 Toutefois, si l’argument muet est, de surcroît, déclaré


avec l’attribut const, la fonction reçoit quand même
une copie de l’argument effectif correspondant,
lequel peut alors être une constante ou une
expression d’un type susceptible d’être converti dans
le type attendu.
 Ces possibilités de transmission par référence
s’appliquent également à une valeur de retour (dans
ce cas, la notion de constance n’a plus de
signification).
Les arguments par défaut
 Dans la déclaration d’une fonction (prototype), il est
possible de prévoir pour un ou plusieurs arguments
(obligatoirement les derniers de la liste) des valeurs
par défaut ; elles sont indiquées par le signe =, à la
suite du type de l’argument comme dans cet
exemple :
float fct (char, int = 10, float = 0.0) ;
 Ces valeurs par défaut seront alors utilisées
lorsqu’on appellera ladite fonction avec un nombre
d’arguments inférieur à celui prévu.
Les arguments par défaut
 Par exemple, avec la précédente déclaration, l’appel :
fct ('a')
sera équivalent à
fct ('a', 10, 0.0)
 De même, l’appel
fct ('x', 12) sera
équivalent à
fct ('x', 12, 0.0)
 En revanche, l’appel fct() sera illégal.
Surdéfinition de fonctions

 En C++, il est possible, au sein d’un même


programme, que plusieurs fonctions possèdent le
même nom.
 Dans ce cas, lorsque le compilateur rencontre l’appel
d’une telle fonction, il effectue le choix de la
«bonne» fonction en tenant compte de la nature des
arguments effectifs.
 Ces règles peuvent faire intervenir toutes les
conversions usuelles.
Surdéfinition de fonctions
Exemple 1
void sosie (int) ; // sosie I
void sosie (double) ; // sosie II
char c ; float y ;
.....
sosie(c) ;
// appelle sosie I, après conversion de c en int
sosie(y) ;
// appelle sosie II, après conversion de y en double
sosie(’d’) ;
// appelle sosie I, après conversion de ’d’ en int
Surdéfinition de fonctions
Exemple 2
void essai(int, double) ; // essai I
void essai(double, int) ;
int n, p ;
double z ; char c ;
.....
essai(n,z); // appelle essai I
essai(c,z);
// appelle essai I, après conversion de c en int
essai(n,p); // erreur de compilation
Surdéfinition de fonctions
Exemple 3
void test (int n=0, double x=0) ; // test I
void test (double y=0, int p=0) ; // test II
int n ; double z ;
.....
test(n,z) ; // appelle test I
test(z,n) ; // appelle test II
test(n) ; // appelle test I
test(z) ; // appelle test II
test() ; // erreur de compilation (Ambiguïté).
Surdéfinition de fonctions
Exemple 4

Avec ces déclarations :


void truc (int) ; // truc I
void truc (const int) ; // truc II
Erreur de compilation. En effet, C++ n’a pas prévu de
distinguer int de const int.
Cela se justifie par le fait que, les deux fonctions truc
recevant une copie de l’information à traiter, il n’y a
aucun risque de modifier la valeur originale.
Surdéfinition de fonctions
Exemple 5
void chose (int &) ; // chose I
void chose (const int &) ; // chose II
int n = 3 ;
const int p = 5 ;
.....
chose (n) ; // appelle chose I
chose (p) ; // appelle chose II
Cette fois, la distinction entre int & et const int &
est justifiée.
En effet, on peut très bien imaginer que chose I
modifie la valeur dont elle reçoit la référence, tandis
que chose II n’en fait rien.
Surdéfinition de fonctions
Exemple 6
L’exemple précédent a montré comment on pouvait distinguer
deux fonctions agissant, l’une sur une référence, l’autre sur une
référence constante. Mais l’utilisation de références possède des
conséquences plus subtiles :
void chose (int &) ; // chose I
void chose (const int &); // chose II
int n; float x ;
.....
chose (n) ; // appelle chose I
chose (2) ; /* appelle chose II, après copie éventuelle
de 2 dans un entier temporaire dont la référence
sera transmise à chose*/
chose (x) ; /* appelle chose II, après conversion de la
valeur de x en un entier temporaire dont la
référence sera transmise à chose*/
Surdéfinition de fonctions
Remarques
➢ En dehors de la situation examinée dans l’exemple 5,
on notera que le mode de transmission (référence
ou valeur) n’intervient pas dans le choix d’une
fonction surdéfinie.
➢ Par exemple, les déclarations suivantes conduiraient à
une erreur de compilation due à leur ambiguïté
(indépendamment de tout appel de chose) :
void chose (int &) ;
void chose (int) ;
Pointeur générique
 Il existe un type particulier : void *
qui désigne un pointeur sur un objet de type
quelconque (on parle souvent de « pointeur
générique »). Il s’agit d’un pointeur sans type.
 Un pointeur de n’importe quel type peut être converti
implicitement en void * comme dans :
void * ad ;
int * adi ;
void f (void *) ;
.....
ad = adi ; // OK
f(adi) ; // OK
Cette possibilité revient à ne conserver du pointeur
d’origine que l’information d’adresse.
Pointeur générique
 En revanche, la conversion inverse ne peut pas être
réalisée implicitement. On doit recourir à
l’opérateur de cast, comme dans :
float * adf ;
void * ad ;
void g (float *) ;
.....
adf = ad ; // illégal
adf = (float *) ad ; // OK
f(ad) ; // illégal
f ( (float *) ad) ; // OK
Pointeur générique
Remarques
1. Une variable de type void * ne peut pas
intervenir dans des opérations arithmétiques, par
exemple :
• Si p et q sont de type void *, on ne peut pas
parler de p+i (i étant entier) ou de p-q ;
• On ne peut pas davantage utiliser l’expression
p++ ;
• car ne connaît pas la taille des objets pointés.
2. Pour des raisons similaires, il n’est pas possible
d’appliquer l’opérateur d’indirection * à un
pointeur de type void *.
Gestion dynamique de la mémoire
 En C++, les fonctions malloc, calloc... et free sont
remplacées avantageusement par les opérateurs
new et delete.

 Par exemple :

int* adr = new int [n];

alloue l’emplacement nécessaire pour n éléments


du type int et fournit en résultat un pointeur
(de type int *) sur le premier élément.
Gestion dynamique de la mémoire
 L’indication n est facultative : avec new int, on
obtient un emplacement pour un élément du type
int, comme si l’on avait écrit new int[1].

 L’expression :

delete adr;

libère un emplacement préalablement alloué par


new à l’adresse indiquée.

Vous aimerez peut-être aussi