Cours de C/C++ par la pratique (Les classes)

Cours de C/C++ par la pratique

Chapitre 3 Bases Quelques generalités pour s’y retrouver :

Declaration / definition

En C/C++ on doit normalement declarer les choses avant de les utiliser : les variables, les classes, les fonctions, etc. Le C est plus « coulant » que le C++ sur ce point.
Une declaration est une ligne du type
// declaration de variable
extern int a; // indique une variable non d´efinie dans le fichier en cours
// d´eclaration de type typedef struct {
int a; float b;
} couple; // cr´ee un nouveau type de donn´ees : un couple entier/flottant
// d´eclaration de fonction (prototype)
float[] matrixmult(float[] a, float[] b, int size);
Une d´efinition est l’endroit du code o`u ce qui a et´ d´eclar´ est « fabriqu´e », exemple :
// d´efinition de fonction
int additionne(int a, int b)
{
int c; // d´eclaration ET d´efinition de variable c= a+b; // ceci est une expression.
return (c);
}

Types

Le C/C++ comme Java est un langage typ´e, c’est `a dire que toutes les variables sont attribu´ees d’un type (entier, flottant, classe, etc).

Types en C

Le C n’est pas un langage typ´e « fort » au sens ou on peut convertir un type en un autre, parfois automatiquement. Par exemple :
int a = 10 ;
float b = 20.0 ;
float c = a * b; // dans cette expression, a est automatiquement converti en float.
Les r`egles de « promotion » des types sont complexes mais vont g´en´eralement du type le moins capable au plus capable, donc ici d’entier vers flottant.
Transtypage En C/C++ On peut forcer un type vers un autre, mˆeme s’ils ne sont pas compatibles a-priori, en utilisant l’op´erateur de transtypage, encore appel´ « moulage » (ou cast en anglais). On « moule » un flottant en entier par l’op´eration suivante :
float f = 3.1415;
int d;
d = (int)f;
Le transtypage s’effectue avec le type de destination entre parenth`eses.
En C++, l’op´erateur de transtypage le plus courant a un une syntaxe diff´erente, plus verbeuse mais plus claire pour qui connaˆıt les templates :
d = static_cast<int>(f);
Le C++ poss`ede trois autres op´erateurs de transtypage :
– dynamic cast r´eserv´ aux pointeurs et r´ef´erences sur des classes. Ce transtypage effectue des v´erifications de validit´e.
– reinterpret cast n’effectue aucune v´erification, et est le plus proche du transtypage C. Il est a` d´econseill´ dans le contexte du C++.
– const cast permet de convertir un type constant (ou volatile) en un type normal, a` l’exclusion de toute autre conversion.
Entiers
Il existe au moins 4 types d’entiers :
– char, le type de caract`ere, est en fait un petit entier (8 bits, un octet) normalement non sign´e
– short, un type d’entier court (normalement 2 octets)
– int, le type entier normal (normalement 4 octets)
– long, le type entier long, capable d’accueillir le r´esultat d’une multiplication entre deux ints (4 ou 8 octets suivant le syst`eme).
De plus ces types peuvent ˆetre affubl´e des qualificatifs signed et unsigned. Comme on l’imagine, un entier unsigned ne peut ˆetre n´egatif. Il existe aussi le type long long (un entier tr`es long), qui est g´en´eralement `a ´eviter.
Le standard ne sp´ecifie que les tailles relatives de ces types, et non les tailles absolues. Le dernier standard C (C99) sp´ecifie des entiers `a taille absolue avec des noms diff´erents (int32 : un entier de 32 bits sign´e par exemple).
Flottants
Il existe 2 types de flottants, tout deux sign´es :
– float : un flottant simple pr´ecision cod´e sur 32 bits.
– double : un flottant double pr´ecision (d’o`u le nom) cod´e sur 64 bits.
Anciennement faire des calculs sur des float ´etait plus rapide, mais ce n’est plus vrai depuis longtemps. En revanche un tableau de double prend bien deux fois plus de place qu’un tableau de float. Le codage des float/double est formalis´e par la norme IEEE 754 et b´en´eficie du support mat´eriel de l’unit´e centrale.
Pour pouvoir r´ealiser des calculs sur les flottants plus compliqu´es que les 4 op´erations, on doit g´en´eralement inclure le header math.h (ou cmath en C++), par exemple :
#include <math.h>
double d = 2.0;
double s = sqrt(d); // calcul de la racine carr´ee
Exercice 2 (Type de fonction par d´efaut) Question : que se passerait-il dans le cas sui-vant ?
// sans inclure <math.h> double s = sqrt(2);
La r´eponse est subtile.

Tableaux

Comme on va tr`es vite parler des tableaux, donc voici comment on les d´eclare :
int a[100]; // un tableau de 100 entiers
double b[10][10] // une matrice `a 2 dimensions de doubles.
Voici comment on les utilise dans des fonctions :
int sumtrace(double mat[][], int size)
{
double s = 0;
for (int i = 0 ; i < size ; ++i) {
s += mat[i][i];
}
return s;
}
La syntaxe des tableaux en 2 dimensions peut sembler ´etrange mais vient de la tr`es grande proximit´e des notions de tableau et de pointeurs que nous verrons plus tard.

Pi`eges

Les pi`eges sont nombreux en C/C++. Pour les trouver plus facilement, utiliser les avertis-sements de votre compilateur. Pour le compilateur GNU (gcc, g++) il faut utiliser l’option Wall (all warnings).
Le pi`ege num´ero 1 est le mˆeme qu’en Java, c’est le suivant :
if (a = 2) {
/* faire quelque chose */
}
Exercice 3 (test pi`ege) Que fait ce code ? Pouvez vous sugg´erer une m´ethode ´eviter le probl`eme associ´e ?

Pr´eprocesseur

Le C et le C++ sont dot´es d’un pr´eprocesseur qui est une sorte de m´eta-langage de macros.
Toutes les directives du pr´eprocesseur commencent par le caract`ere #.

Inclusion

La directive la plus courante est le #include qui inclus un fichier dans un autre. On peut mettre n’importe quoi dans un fichier inclus, y compris du code ex´ecutable, mais par convention on n’y place que des d´eclarations. Un fichier qui est inclus s’appelle un « header » et est normalement un fichier qui se termine en .h (ou parfois .hh, .H, .hxx ou encore .h++ pour le C++)
Il y a deux fa¸con d’invoquer #include :
– #include <someheader.h> r´eserv´ aux headers du syst`eme.
– #include « someheader.h » pour vos propres headers, ceux que vous cr´eerez.
Il est usuel, dans un projet assez grand, de cr´eer ses propres headers et d’y mettre les d´efinitions qui sont partag´ees entre plusieurs fichiers.

Directives pr´eprocesseurs

On peut d´efinir des macros en pr´eprocesseur avec la directive #define, c’est a` dire des expressions qui ressemblent a` des fonctions (normalement tr`es courtes) qui sont substitu´ees directement dans le texte du programme. Une macro tr`es courante est :
#define MIN(a,b) ((a) < (b)) ? (a) : (b)
La construction ´etrange avec ? et : est un test simple en une ligne. De mani`ere g´en´erale, l’expression
(test) ? si_oui : si_non
est exactement ´equivalente a`
if (test)
si_oui;
else
si_non;
mais le test s’´ecrit en une ligne. Une macro doit ˆetre exprim´ee en une seule ligne, mais peut ˆetre d´efinie sur plusieurs lignes en les continuant avec le caract`ere ’\’. On pourrait ´ecrire la macro MAX de la fa¸con suivante :
#define MAX(a,b) \
if ((a) > (b)) \
(a) \
else \
(b)
Ici dans la macro MIN, si a est plus petit que b alors le r´esultat du test est a, sinon b. Notez que le type de a n’est pas sp´ecifi´. Ce test marche car la macro fonctionne par substitution de caract`ere par le pr´eprocesseur. En d’autre termes, avant la compilation, l’expression
int a = MIN(2, 5);
est substitu´e par l’expression
int a = ((2) < (5)) ? (2) : (5);
Et on a bien le r´esultat voulu : 2. Notez que l’un de (a) ou (b) est evalu´ deux fois, ce qui peut avoir des effets secondaires. Dans le code du listing 3.1
Listing 3.1 – Pi`ege des macros
#include < s t d i o . h>
#de fi ne MIN( a , b ) ( a ) < ( b ) ? ( a ) : ( b )
i n t f ( )
{
// une v a r i a b l e s t a t i c e s t p e r s i s t a n t e
// s a v a l e u r e s t g a r d ´e e d ’ un a p p e l au s u i v a n t .
s t a t i c i n t c o u n t = 0 ;
return ++c o u n t ;
}
i n t main ( )
{
p r i n t f ( « le min de (f() et 1) vaut %d\n »
« Le min de (1 et f()) vaut %d\n » , MIN( f ( ) , 1 ) , MIN ( 1 , f ( ) ) ) ;
}
on a le r´esultat suivant :
$ ./incf
le min de (f() et 1) vaut 1
Le min de (1 et f()) vaut 2
Ce qui est pour le moins curieux… Les macros pr´eprocesseur sont une grande source de pi`eges difficiles, on tˆachera de les ´eviter si possible. En C++ et en C99 on peut presque toujours les remplacer par une fonction inline, c’est a` dire substitu´ee en place comme les macros, mais en respectant la syntaxe des fonctions C normales. Dans les cas o`u l’on souhaite conserver l’ind´ependance de la macro quant aux types, on peut en C++ utiliser une fonction template, que nous verrons en section 7.6.

Compilation conditionnelle

Le pr´eprocesseur permet de ne compiler qu’une partie d’un fichier avec l’op´eration logique #define du pr´eprocesseur.
#ifdef SOMEVAR
/* le code ici n’est compil´e que si SOMEVAR est d´efinie par le pr´eprocesseur */
#endif // SOMEVAR
Ce m´ecanisme est particuli`erement utile dans les headers, pour ´eviter qu’un header soit inclus de mani`ere multiple.
Contenu dans le header myheader.h
#ifndef MYHEADER
#define MYHEADER
/* d´eclarations dans le header */
/* ces d´eclarations ne seront inclues qu’une fois par fichier */
#endif // MYHEADER

Autres

Entre autres :
– #pragma permet d’invoquer des caract´eristiques du compilateur
– #LINE et #FILE permettent d’´ecrire certains messages de d´ebogage.
– ## est une directive de concat´enation qui permet par exemple la programmation g´en´erique en C pur, mais est tr`es difficile d’emploi.

1 Comment demarrer ? 
1.1 Un programme simple en C pur
1.2 Un programme en C++
1.3 La suite
1.3.1 L’outil make
1.3.2 Autres outils
2 Introduction 
2.1 Pourquoi parler a la fois de C et de C++
2.2 C, C++ et Java
2.2.1 Ce qui est pareil
2.2.2 Ce qui differe entre C/C++ et Java
2.2.3 Ce qui differe entre C et C++
2.3 Style
2.3.1 Indentation
2.3.2 Commentez
3 Bases 
3.1 D´eclaration / d´efinition
3.2 Types
3.2.1 Types en C
3.2.2 Tableaux
3.3 Pi`eges
3.4 Pr´eprocesseur
3.4.1 Inclusion
3.4.2 Directives preprocesseurs
3.4.3 Compilation conditionnelle
3.4.4 Autres
4 Entr´ees – sorties 
4.1 Hello
4.2 Lecture/´ecriture
4.2.1 Sortie standard en C
4.2.2 Sortie standard en C++
4.2.3 Entr´ee standard en C
4.2.4 Entr´ee standard en C++
4.2.5 Fichiers en C
4.3 Fichiers en C++
4.4 Chaˆınes de caract`eres
4.4.1 Chaˆınes de caract`eres en C
4.4.2 Chaˆınes de caract`eres en C++
4.4.3 Arguments de la ligne de commande
5 Pointeurs et tableaux 
5.1 Pointeurs en C
5.1.1 R´ef´erence et d´er´ef´erence
5.1.2 Pointeur vide
5.1.3 Pointeurs et tableaux
5.1.4 Arithm´etique de pointeurs
5.1.5 Pointeurs dans les arguments de fonctions
5.1.6 Allocation de m´emoire dynamique
5.2 Pointeurs et r´ef´erences en C++
5.3 Tableaux dynamiques `a plus d’une dimension
5.3.1 Simulation des dimensions avec un vecteur
5.3.2 Allocation par vecteur de vecteur
5.3.3 Imposition de la structure n-dimensionnelle
6 Classes 
6.1 Structures en C
6.1.1 D´efinition de type par typedef
6.1.2 Utilisation des structures en C
6.2 Classes en C++
6.2.1 D´efinition
6.2.2 M´ethodes
6.2.3 H´eritage
6.2.4 Constructeurs et destructeurs
7 C++ avanc´e 
7.1 Les formes d’h´eritage ´etranges
7.2 Exceptions
7.3 RTTI
7.4 Op´erateurs
7.5 Friends
7.6 Templates
7.7 Lien entre C et C++
8 Idiomes du C++ 
8.1 Ressource allocation is initialisation
9 Systemes de developpement 
9.1 Syst`eme UNIX/GNU
9.2 Le d´ebogueur GDB
9.2.1 Utiliser GDB
9.2.2 Faire tourner gdb1 sous GDB
9.2.3 GDB et le d´ebogage m´emoire
9.2.4 Debugging libraries
9.2.5 Front-ends to gdb
9.2.6 More information
9.2.7 Summary of commands
9.3 Systeme Windows
10 Conseils et conclusion 
10.1 Sites web
10.2 Livres
10.3 Biblioth`eques
10.4 C ou C++ ?
10.4.1 Complexit´e
10.5 R´ef´erences web
A Solution des exercices 
A.1 Dans chapitre Introduction
A.2 Dans chapitre Bases

Cours gratuitTélécharger le cours complet

Télécharger aussi :

Laisser un commentaire

Votre adresse e-mail ne sera pas publiée. Les champs obligatoires sont indiqués avec *