Chapitre 7 – Conversions de types et transtypage
Document réservé
Vous consultez actuellement la présentation publique de ce chapitre.
Les documents PDF complets, comprenant les développements théoriques, les exemples détaillés et les exercices, sont disponibles sur demande.
Pour obtenir un accès, contactez-moi via la page Contact en indiquant les domaines qui vous intéressent (C++, ESP-IDF, électronique, etc.).
7 Conversions de types et transtypage
7.1 Pourquoi convertir un type ? . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
7.1.1 Une conversion déjà familière . . . . . . . . . . . . . . . . . . . . . . . . . . .
7.1.2 Toutes les conversions ne sont pas équivalentes . . . . . . . . . . . . . . . . .
7.1.3 Qui décide de la conversion ? . . . . . . . . . . . . . . . . . . . . . . . . . . .
7.1.4 Pourquoi demander explicitement une conversion ? . . . . . . . . . . . . . . .
7.2 Les conversions implicites . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
7.2.1 Conversion lors d’une affectation . . . . . . . . . . . . . . . . . . . . . . . . .
7.2.2 Conversion lors d’un appel de fonction . . . . . . . . . . . . . . . . . . . . . .
7.2.3 Expressions contenant plusieurs types . . . . . . . . . . . . . . . . . . . . . . .
7.2.4 Les promotions . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
7.2.5 Le type de destination n’agit pas rétroactivement . . . . . . . . . . . . . . . .
7.2.6 Conversion possible et conservation de l’information . . . . . . . . . . . . . .
7.3 Conversions et pertes d’information . . . . . . . . . . . . . . . . . . . . . . . . . . . .
7.3.1 Perte de la partie fractionnaire . . . . . . . . . . . . . . . . . . . . . . . . . . .
7.3.2 Le compilateur peut accepter une perte d’information . . . . . . . . . . . . .
7.3.3 Conversion d’un entier vers un réel . . . . . . . . . . . . . . . . . . . . . . . .
7.3.4 Conversion entre types entiers . . . . . . . . . . . . . . . . . . . . . . . . . . .
7.3.5 Types signés et non signés . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
7.3.6 Les accolades et les conversions réductrices . . . . . . . . . . . . . . . . . . .
7.3.7 La taille du type n’est pas le seul critère . . . . . . . . . . . . . . . . . . . . .
7.4 Le transtypage : conversion explicite . . . . . . . . . . . . . . . . . . . . . . . . . . . .
7.4.1 Exprimer explicitement son intention . . . . . . . . . . . . . . . . . . . . . . .
7.4.2 Deux situations différentes . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
7.4.3 Pourquoi utiliser un transtypage ? . . . . . . . . . . . . . . . . . . . . . . . . .
7.4.4 Modifier le type avant une opération . . . . . . . . . . . . . . . . . . . . . . .
7.4.5 Le type de la variable originale ne change pas . . . . . . . . . . . . . . . . . .
7.4.6 Un transtypage n’autorise pas n’importe quelle opération . . . . . . . . . . .
7.4.7 Plusieurs formes de transtypage . . . . . . . . . . . . . . . . . . . . . . . . . .
7.5 Le transtypage de style C . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
7.5.1 Conversion de double vers int . . . . . . . . . . . . . . . . . . . . . . . . . .
7.5.2 Le transtypage porte sur une expression . . . . . . . . . . . . . . . . . . . . .
7.5.3 Transtyper avant une opération . . . . . . . . . . . . . . . . . . . . . . . . . .
7.5.4 Une syntaxe héritée du langage C . . . . . . . . . . . . . . . . . . . . . . . . .
7.5.5 Une syntaxe peu descriptive . . . . . . . . . . . . . . . . . . . . . . . . . . . .
7.5.6 Une syntaxe toujours valide . . . . . . . . . . . . . . . . . . . . . . . . . . . .
7.6 static_cast . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
7.6.1 Une première conversion . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
7.6.2 Une intention clairement exprimée . . . . . . . . . . . . . . . . . . . . . . . .
7.6.3 Pourquoi le mot static ? . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
7.6.4 Modifier le type utilisé dans une expression . . . . . . . . . . . . . . . . . . .
7.6.5 static_cast n’empêche pas les pertes d’information . . . . . . . . . . . . .
1
3
3
3
4
5
5
6
6
6
7
7
8
8
9
9
10
10
10
10
11
11
12
12
13
13
13
14
14
14
15
15
16
16
17
17
18
19
19
19
19
20
20
2026 – Partie II C++
Conversions de types et transtypage
7.6.6 Une conversion soumise à des règles précises . . . . . . . . . . . . . . . . . .
7.6.7 Une conversion visible dans le programme . . . . . . . . . . . . . . . . . . . .
7.7 dynamic_cast . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
7.7.1 Une hiérarchie polymorphe . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
7.7.2 Type du pointeur et type réel de l’objet . . . . . . . . . . . . . . . . . . . . .
7.7.3 Vérifier le type réel de l’objet . . . . . . . . . . . . . . . . . . . . . . . . . . .
7.7.4 Échec du transtypage d’un pointeur . . . . . . . . . . . . . . . . . . . . . . . .
7.7.5 Pourquoi le mot dynamic ? . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
7.7.6 Remonter ou redescendre dans une hiérarchie . . . . . . . . . . . . . . . . . .
7.7.7 static_cast ou dynamic_cast ? . . . . . . . . . . . . . . . . . . . . . . . . .
7.7.8 Le cas des références . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
7.7.9 Une classe de base polymorphe . . . . . . . . . . . . . . . . . . . . . . . . . .
7.8 const_cast . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
7.8.0.1
L’objet et la manière d’y accéder . . . . . . . . . . . . . . . . . . .
7.8.1 Retirer une qualification const . . . . . . . . . . . . . . . . . . . . . . . . . .
7.8.2 Un objet réellement constant . . . . . . . . . . . . . . . . . . . . . . . . . . .
7.8.3 const_cast et les références . . . . . . . . . . . . . . . . . . . . . . . . . . .
7.8.4 Ajouter la qualification const . . . . . . . . . . . . . . . . . . . . . . . . . . .
7.8.5 Pourquoi utiliser const_cast ? . . . . . . . . . . . . . . . . . . . . . . . . . .
7.8.6 La qualification volatile . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
7.9 reinterpret_cast . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
7.9.1 Une adresse et un type . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
7.9.2 Réinterpréter un pointeur . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
7.9.3 Le transtypage ne garantit pas un accès valide . . . . . . . . . . . . . . . . .
7.9.3.1
Convertir ou réinterpréter . . . . . . . . . . . . . . . . . . . . . . . .
7.9.4 Convertir un pointeur en valeur entière . . . . . . . . . . . . . . . . . . . . . .
7.9.5 Aucun nouvel objet n’est créé . . . . . . . . . . . . . . . . . . . . . . . . . . .
7.9.6 Pourquoi utiliser reinterpret_cast ? . . . . . . . . . . . . . . . . . . . . . .
7.9.7 Ne pas confondre réinterprétation et examen des bits . . . . . . . . . . . . .
7.10 Comparaison des quatre casts C++ . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
7.10.1 Une syntaxe commune . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
7.10.2 static_cast : effectuer une conversion connue . . . . . . . . . . . . . . . . .
7.10.3 dynamic_cast : vérifier un type dans une hiérarchie polymorphe . . . . . . .
7.10.4 const_cast : modifier une qualification . . . . . . . . . . . . . . . . . . . . .
7.10.4.1 reinterpret_cast : effectuer une conversion de bas niveau . . .
7.10.4.2 Tableau comparatif . . . . . . . . . . . . . . . . . . . . . . . . . . .
7.10.5 Quatre opérateurs, quatre questions différentes . . . . . . . . . . . . . . . . .
7.10.6 Et le transtypage de style C ? . . . . . . . . . . . . . . . . . . . . . . . . . . .
7.10.7 Des responsabilités différentes . . . . . . . . . . . . . . . . . . . . . . . . . . .
7.10.8 Conclusion . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
23/08/2026
(expression)
Le type placé entre les chevrons indique le type vers lequel nous souhaitons effectuer la conversion.
7.6.1
Une première conversion
Considérons :
1
2
3
double x = 8.7;
int n = static_cast(x);
L’expression :
1
static_cast(x)
demande explicitement la conversion de la valeur de x vers le type int.
Nous obtenons :
8.7double −→ 8int .
Comme précédemment, la partie fractionnaire est supprimée.
7.6.2
Une intention clairement exprimée
L’écriture :
1
static_cast(x)
est plus longue que :
1
(int)x
mais cette longueur est volontaire.
Le nom static_cast indique explicitement la catégorie de transtypage demandée. Le lecteur sait
immédiatement qu’il s’agit d’une conversion que le compilateur peut vérifier selon les règles correspondant à static_cast.
7.6.3
Pourquoi le mot static ?
Dans static_cast, le terme static indique que la validité de la conversion est déterminée lors de
la compilation. Le compilateur connaît les types concernés et peut vérifier si la conversion demandée
est autorisée par les règles de static_cast.
Il n’est pas nécessaire d’effectuer une vérification dynamique du type de l’objet pendant l’exécution
du programme.
23/08/2026
(a) / b;
L’expression :
1
static_cast(a)
produit une valeur de type double avant que la division soit effectuée.
Nous avons donc conceptuellement :
5int −→ 5.0double .
La division est alors effectuée avec le type approprié :
5.0/2.0 = 2.5.
Nous obtenons donc :
resultat = 2.5
7.6.5
static_cast n’empêche pas les pertes d’information
L’utilisation de static_cast ne garantit pas que la conversion conserve toute l’information.
Par exemple :
1
2
3
double x = 8.7;
int n = static_cast(x);
est parfaitement valide.
Nous obtenons toujours :
8.7 −→ 8.
Le rôle de static_cast n’est donc pas d’empêcher toutes les conversions susceptibles de perdre
de l’information. Il permet d’exprimer explicitement une conversion appartenant aux catégories qu’il
autorise.
7.6.6
Une conversion soumise à des règles précises
static_cast n’est pas un ordre permettant de transformer arbitrairement n’importe quel type en
n’importe quel autre type. Le compilateur vérifie que la conversion demandée appartient aux conversions autorisées par static_cast.
Si ce n’est pas le cas, la compilation échoue.
23/08/2026
(a)
est particulièrement visible dans le code.
Cette propriété est utile lors de la lecture ou de l’analyse d’un programme : une recherche sur le mot
1
static_cast
permet de retrouver directement les conversions de cette catégorie.
Cette possibilité est beaucoup moins évidente avec les transtypages de style C, dont la syntaxe repose
simplement sur des parenthèses.
Caractéristique
Style C
C++
Syntaxe
Conversion explicite
Intention facilement visible
Catégorie de conversion indiquée
Recherche dans le code
(int)x
oui
faible
non
difficile
static_cast(x)
oui
forte
oui
facile
Dans la suite de ce cours, lorsque nous aurons besoin d’une conversion appartenant à cette catégorie,
nous privilégierons donc l’écriture :
1
static_cast(expression)
plutôt que le transtypage de style C.
1
2
3
4
5
6
#include
int main()
{
int a = 5;
int b = 2;
7
8
9
10
11
12
double resultat1 = a / b;
double resultat2 = (double)a / b;
double resultat3 =
static_cast(a) / b;
std::cout
<< resultat1
<< std::endl;
13
14
15
16
17
18
std::cout
<< resultat2
<< std::endl;
19
20
21
22
23
24
25
26
std::cout
<< resultat3
<< std::endl;
return 0;
}
23/08/2026
https://cpp-iot-etc.ch
21/42
2026 - Partie II C++
Conversions de types et transtypage
La sortie est :
2
2.5
3 2.5
1
2
À retenir
• La syntaxe générale de static_cast est :
1
static_cast(expression)
• static_cast permet d’exprimer explicitement de nombreuses conversions vérifiables à
la compilation.
• Dans les conversions numériques simples :
1
(int)x
et
1
static_cast(x)
peuvent produire le même résultat.
• static_cast exprime cependant plus précisément l’intention du programmeur et la
catégorie de conversion demandée.
• static_cast peut être utilisé avant une opération afin d’imposer le type avec lequel
celle-ci sera effectuée.
• Il ne garantit pas l’absence de perte d’information.
• Il n’autorise pas n’importe quelle conversion : le compilateur vérifie si la conversion
demandée est permise.
• En C++ moderne, static_cast est généralement préféré au transtypage de style C pour
les conversions auxquelles il s’applique.
7.7
dynamic_cast
L’opérateur dynamic_cast est principalement utilisé lors de conversions entre types appartenant à
une même hiérarchie de classes polymorphes. Contrairement à static_cast, il peut effectuer une
vérification du type réel d’un objet pendant l’exécution du programme.
Sa syntaxe générale est :
1
dynamic_cast(expression)
7.7.1
Une hiérarchie polymorphe
Considérons une classe de base Forme et deux classes dérivées :
1
2
3
class Forme
{
public:
23/08/2026
(forme);
L’opérateur dynamic_cast vérifie si l’objet désigné par forme peut effectivement être considéré
comme un Carre.
Dans notre exemple, c’est le cas. Le transtypage réussit et carre2 contient l’adresse du même objet.
Fig. 7.2 – Schéma.
23/08/2026
(forme);
Le pointeur forme désigne cette fois un objet dont le type réel est Cercle. Il n’est donc pas possible
d’obtenir un Carre* désignant cet objet.
Lorsque dynamic_cast échoue lors d’une conversion de pointeur, il retourne un pointeur nul.
Nous avons donc :
1
carre == nullptr
7.7.5
Pourquoi le mot dynamic ?
Le type réel de l’objet désigné par un pointeur de classe de base peut dépendre de ce qui se produit
pendant l’exécution du programme.
Dans :
1
Forme* forme;
le pointeur pourrait, selon la situation, désigner un Carre, un Cercle ou un autre objet appartenant
à la hiérarchie. dynamic_cast permet d’effectuer une vérification du type réel de l’objet pendant
l’exécution.
C’est cette vérification dynamique qui explique son nom.
Exemple :
1
2
3
4
#include
class Forme
{
5 public:
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
virtual ~Forme() = default;
};
class Carre : public Forme
{
};
class Cercle : public Forme
{
};
int main()
{
Carre carre;
Cercle cercle;
23/08/2026
(forme1);
27
28
29
30
31
32
Carre* resultat2 =
dynamic_cast(forme2);
if (resultat1 != nullptr)
{
std::cout
<< "forme1 est un Carre"
<< std::endl;
}
33
34
35
36
37
38
if (resultat2 == nullptr)
{
std::cout
<< "forme2 n’est pas un Carre"
<< std::endl;
}
39
40
41
42
43
44
45
46
47
Conversions de types et transtypage
return 0;
}
La sortie est :
1
2
3
forme1 est un Carre
forme2 n’est pas un Carre
Program ended with exit code: 0
7.7.6
Remonter ou redescendre dans une hiérarchie
Une conversion d’un type dérivé vers son type de base est souvent appelée upcast.
Par exemple :
1
2
3
Carre carre;
Forme* forme = &carre;
Cette conversion est naturelle : un Carre est une Forme. Elle peut être effectuée implicitement.
La conversion inverse est souvent appelée downcast. Elle est plus délicate. Un pointeur Forme* ne
désigne pas nécessairement un Carre : il pourrait désigner un Cercle ou un autre type dérivé.
Une vérification peut donc être nécessaire avant de considérer l’objet comme appartenant au type
dérivé demandé.
7.7.7
static_cast ou dynamic_cast ?
Dans certaines situations liées à l’héritage, un transtypage vers un type dérivé peut également être
exprimé avec static_cast.
23/08/2026
https://cpp-iot-etc.ch
25/42
2026 - Partie II C++
Conversions de types et transtypage
Cependant, static_cast n’effectue pas la vérification dynamique permettant de déterminer si l’objet désigné possède réellement le type dérivé demandé. Lorsque cette vérification est nécessaire,
dynamic_cast constitue l’outil approprié.
Fig. 7.3 – Schéma.
7.7.8
Le cas des références
dynamic_cast peut également être utilisé avec des références.
Contrairement à un pointeur, une référence valide ne possède pas de valeur nulle permettant de
signaler simplement l’échec du transtypage. Si un dynamic_cast vers une référence échoue, une
exception de type :
1
std::bad_cast
est déclenchée.
Nous reviendrons sur le mécanisme des exceptions à l’endroit approprié du cours.
7.7.9
Une classe de base polymorphe
Pour utiliser dynamic_cast afin d’effectuer ce type de vérification dynamique dans une hiérarchie,
la classe de base doit être polymorphe. Une classe est polymorphe lorsqu’elle possède au moins une
fonction virtuelle.
Dans notre exemple :
1
2
3
4
5
6
class Forme
{
public:
virtual ~Forme() = default;
};
le destructeur virtuel rend la classe Forme polymorphe.
23/08/2026
https://cpp-iot-etc.ch
26/42
2026 - Partie II C++
Conversions de types et transtypage
À retenir
• dynamic_cast est principalement utilisé pour certaines conversions dans des hiérarchies
de classes polymorphes.
• Il peut vérifier pendant l’exécution si l’objet désigné possède un type compatible avec le
type demandé.
• Un pointeur vers une classe de base peut désigner un objet appartenant à une classe
dérivée.
• Lorsqu’un dynamic_cast de pointeur échoue, le résultat est nullptr.
• Une conversion d’un type dérivé vers un type de base est souvent appelée upcast et
peut généralement être effectuée implicitement.
• Une conversion d’un type de base vers un type dérivé est souvent appelée downcast. Elle
peut nécessiter une vérification du type réel de l’objet.
• Contrairement à static_cast, dynamic_cast peut effectuer cette vérification dynamique.
• Pour les vérifications dynamiques étudiées ici, la classe de base doit être polymorphe,
c’est-à-dire posséder au moins une fonction virtuelle.
• Lorsqu’un dynamic_cast vers une référence échoue, une exception std::bad_cast est
déclenchée.
7.8
const_cast
L’opérateur const_cast permet de modifier certaines qualifications d’un type, principalement la
qualification const.
Sa syntaxe générale est :
1
const_cast(expression)
Contrairement à static_cast, son objectif n’est pas de convertir une valeur numérique vers un
autre type. Il agit sur les qualifications associées à l’accès à un objet, notamment par l’intermédiaire
d’un pointeur ou d’une référence.
7.8.0.1
L’objet et la manière d’y accéder
Considérons :
1
2
3
int a = 5;
const int* p = &a;
La variable a est de type int. Elle n’a donc pas été déclarée constante. Le pointeur p, en revanche,
est de type :
1
const int*
Il permet de lire la valeur de a, mais interdit de la modifier par son intermédiaire.
Ainsi :
23/08/2026
(p);
Le pointeur p possède le type :
1
const int*
tandis que q possède le type :
1
int*
Les deux pointeurs désignent cependant le même objet.
Nous pouvons alors écrire :
1
*q = 10;
Cette opération est valide dans cet exemple, car l’objet original a n’a jamais été déclaré const.
Après cette instruction :
a = 10.
Le const_cast n’a donc pas transformé un objet constant en objet modifiable. Il a retiré la qualification const de l’accès utilisé pour atteindre un objet qui était lui-même modifiable.
7.8.2
Un objet réellement constant
Considérons maintenant :
1
2
const int a = 5;
3
4
5
6
const int* p = &a;
int* q =
const_cast(p);
Cette fois, l’objet original a été déclaré :
1
const int a = 5;
Il s’agit donc réellement d’un objet constant. const_cast permet d’obtenir un pointeur dont le type
ne contient plus la qualification const :
1
int* q
mais cela ne rend pas pour autant l’objet original modifiable, si nous tentons :
1
*q = 10;
23/08/2026
(ref);
const int& ref = a;
autreRef = 20;
La référence ref fournit initialement un accès constant à a. const_cast permet ici d’obtenir une
référence non constante vers le même objet. Cette modification est valide parce que l’objet original
a n’a pas été déclaré const.
7.8.4
Ajouter la qualification const
const_cast peut également être utilisé dans des conversions ajoutant certaines qualifications.
Cependant, lorsqu’il s’agit simplement d’obtenir un accès constant à partir d’un accès modifiable,
aucun transtypage explicite n’est généralement nécessaire.
Par exemple :
1
2
3
4
int a = 5;
int* p = &a;
const int* q = p;
est directement accepté.
L’ajout de const est ici naturel et ne nécessite donc pas l’emploi de const_cast.
23/08/2026
int main()
{
int a = 5;
const int* p = &a;
std::cout
<< "a = "
<< a
<< std::endl;
int* q =
const_cast(p);
*q = 10;
std::cout
<< "a = "
<< a
<< std::endl;
23/08/2026
https://cpp-iot-etc.ch
30/42
2026 - Partie II C++
24
25
26
27
28
std::cout
<< "*p = "
<< *p
<< std::endl;
29
30
31
32
33
34
std::cout
<< "*q = "
<< *q
<< std::endl;
35
Conversions de types et transtypage
return 0;
}
La sortie est :
1
2
3
4
a = 5
a = 10
*p = 10
*q = 10
À retenir
• const_cast permet de modifier certaines qualifications d’un type, principalement const
.
• Sa syntaxe générale est :
1
const_cast(expression)
• Il faut distinguer la constance de l’objet lui-même de la constance de l’accès fourni par
un pointeur ou une référence.
• Si l’objet original n’est pas constant, il est possible de retirer const d’un accès puis de
modifier cet objet.
• Si l’objet original a réellement été déclaré const, retirer la qualification de l’accès ne
rend pas l’objet modifiable.
• Tenter ensuite de modifier un objet réellement constant conduit à un comportement
indéfini.
• const_cast fonctionne notamment avec les pointeurs et les références.
• L’ajout de const ne nécessite généralement aucun transtypage explicite.
• Retirer const doit rester exceptionnel et ne doit pas servir simplement à contourner une
erreur signalée par le compilateur.
• const_cast peut également intervenir sur la qualification volatile.
7.9
reinterpret_cast
L’opérateur reinterpret_cast est destiné à certaines conversions de bas niveau.
Sa syntaxe générale est :
23/08/2026
(expression)
Contrairement à une conversion numérique telle que :
1
static_cast(8.7)
reinterpret_cast n’a généralement pas pour objectif de transformer une valeur numérique en
une valeur équivalente appartenant à un autre type mais permet notamment d’effectuer certaines
conversions entre types de pointeurs ou entre pointeurs et types entiers capables de représenter une
adresse.
7.9.1
Une adresse et un type
Considérons :
1
2
int n = 90;
int* p = &n;
Le pointeur p contient l’adresse de n.
Son type est :
1
int*
Ce type ne décrit donc pas seulement une adresse. Il indique également au compilateur le type de
l’objet auquel nous souhaitons accéder par l’intermédiaire de cette adresse.
7.9.2
Réinterpréter un pointeur
Nous pouvons écrire :
1
2
3
int n = 90;
int* p = &n;
4
5
double* q =
reinterpret_cast(p);
Le pointeur p possède le type :
1
int*
tandis que q possède le type :
1
double*
reinterpret_cast permet ici une conversion de bas niveau entre ces types de pointeurs.
L’existence de q ne signifie cependant pas que l’objet n est devenu un double. L’objet stocké en
mémoire reste un objet de type int.
Le transtypage a modifié le type du pointeur utilisé pour considérer l’adresse ; il n’a pas transformé
l’objet situé à cette adresse.
7.9.3
Le transtypage ne garantit pas un accès valide
Le fait qu’un reinterpret_cast soit accepté par le compilateur ne signifie pas que toutes les utilisations ultérieures du résultat sont valides.
Dans notre exemple :
1
2
double* q =
reinterpret_cast(p);
23/08/2026
(n);
Une nouvelle valeur de type double correspondant numériquement à la valeur de n est produite :
90int −→ 90.0double .
En revanche, une expression telle que :
1
reinterpret_cast(p)
ne convertit pas la valeur entière en valeur réelle. Elle effectue une conversion de bas niveau portant
ici sur le type du pointeur.
Fig. 7.4 – static_cast
reinterpret_cast
7.9.4
vs.
Convertir un pointeur en valeur entière
reinterpret_cast peut notamment intervenir lors de certaines conversions entre pointeurs et types
entiers.
La bibliothèque standard définit, lorsqu’il est disponible, le type :
1
std::uintptr_t
destiné à fournir un type entier non signé capable de contenir une valeur de pointeur convertie sous
forme entière.
Par exemple :
1
2
3
#include
int n = 90;
23/08/2026
(&n);
Et maintenant adresse est un entier, pas un pointeur.
Dans les conditions prévues par le langage, une valeur de pointeur convertie vers un type entier
suffisamment grand peut être reconvertie vers son type de pointeur original.
Par exemple :
1
2
int* nouveauPointeur =
reinterpret_cast(adresse);
Nous pouvons alors vérifier :
1
2
3
4
std::cout
<< std::boolalpha
<< (nouveauPointeur == &n)
<< std::endl;
7.9.5
Aucun nouvel objet n’est créé
Lorsqu’un pointeur est converti avec reinterpret_cast, aucun nouvel objet n’est créé par cette
seule opération.
Le transtypage ne copie pas l’objet et ne transforme pas automatiquement les octets présents en
mémoire. Il produit une valeur du type demandé selon les conversions de bas niveau autorisées par
cet opérateur.
7.9.6
Pourquoi utiliser reinterpret_cast ?
Certaines opérations de programmation de bas niveau nécessitent de manipuler explicitement des
représentations ou des adresses sous des formes différentes. reinterpret_cast fournit une syntaxe
clairement identifiable pour certaines de ces conversions.
Son utilisation signale immédiatement au lecteur que le programme effectue une opération de bas
niveau dont la validité ne peut pas être déduite simplement d’une conversion ordinaire de valeurs.
7.9.7
Ne pas confondre réinterprétation et examen des bits
Le nom reinterpret_cast pourrait laisser penser qu’il constitue l’outil général permettant de lire
arbitrairement les bits d’un objet sous la forme d’un autre type.
Cette interprétation serait dangereuse.
Les règles C++ concernant le type réel des objets, leur alignement et les accès à leur représentation
doivent toujours être respectées. Le C++ moderne fournit d’autres mécanismes lorsque l’objectif est
spécifiquement d’examiner ou de transférer une représentation binaire.
Exemple :
1
2
3
4
#include
#include
#include
23/08/2026
(p);
std::cout
<< "p = "
<< p
<< std::endl;
16
17
18
19
20
21
std::cout
<< "adresse en decimal = "
<< adresse
<< std::endl;
22
23
24
25
26
27
std::cout
<< "adresse en hexadecimal = 0x"
<< std::hex
<< adresse
<< std::endl;
28
29
30
31
32
33
int* q =
reinterpret_cast(adresse);
std::cout
<< std::boolalpha
<< "q == p : "
<< (q == p)
<< std::endl;
34
35
36
37
38
39
40
Conversions de types et transtypage
return 0;
}
La sortie est :
1
2
3
4
p = 0x16fdfee64
adresse en decimal = 6171917924
adresse en hexadecimal = 0x16fdfee64
q == p : true
23/08/2026
https://cpp-iot-etc.ch
35/42
2026 - Partie II C++
Conversions de types et transtypage
À retenir
• reinterpret_cast est destiné à certaines conversions de bas niveau.
• Sa syntaxe générale est :
1
reinterpret_cast(expression)
• Il ne faut pas le confondre avec une conversion numérique effectuée par static_cast.
• Une conversion entre types de pointeurs ne transforme pas l’objet situé à l’adresse
considérée.
• Le fait qu’un reinterpret_cast soit accepté par le compilateur ne garantit pas que le
résultat puisse ensuite être déréférencé ou utilisé arbitrairement.
• Un accès incompatible avec le type réel de l’objet peut conduire à un comportement
indéfini.
• reinterpret_cast peut notamment être utilisé pour certaines conversions entre pointeurs et types entiers capables de représenter une adresse.
• Lorsqu’un transtypage de pointeur est effectué, aucun nouvel objet n’est créé par cette
seule opération.
• L’utilisation de reinterpret_cast doit rester limitée aux situations de bas niveau dans
lesquelles la représentation et les contraintes des données sont précisément connues.
7.10
Comparaison des quatre casts C++
Le C++ moderne distingue quatre opérateurs principaux de transtypage :
static_cast
dynamic_cast
const_cast
4 reinterpret_cast
1
2
3
Cette séparation n’est pas simplement syntaxique, chaque opérateur correspond à une catégorie
particulière de transtypage et exprime donc une intention différente du programmeur.
Le choix d’un opérateur de transtypage renseigne immédiatement le lecteur sur la nature de l’opération demandée.
7.10.1
Une syntaxe commune
Les quatre opérateurs utilisent une syntaxe de même forme :
1
nom_du_cast(expression)
Par exemple :
1
2
3
4
5
6
7
static_cast(a)
dynamic_cast(forme)
const_cast(p)
reinterpret_cast(p)
23/08/2026
(x);
Nous obtenons :
8.7double −→ 8int .
static_cast exprime ici une véritable conversion de valeur.
7.10.3
dynamic_cast : vérifier un type dans une hiérarchie polymorphe
dynamic_cast intervient principalement dans les hiérarchies de classes polymorphes. Considérons :
1
2
Forme* forme = …;
3
4
Carre* carre =
dynamic_cast(forme);
Le pointeur forme possède statiquement le type Forme*, mais l’objet qu’il désigne peut réellement
être un Carre, un Cercle ou un autre type dérivé. dynamic_cast permet ici de vérifier à l’exécution
si l’objet est compatible avec le type demandé.
7.10.4
const_cast : modifier une qualification
const_cast possède un rôle très différent. Il permet de modifier certaines qualifications d’un type,
principalement const.
Par exemple :
1
2
3
4
5
6
int a = 5;
const int* p = &a;
int* q =
const_cast(p);
L’objet a reste le même objet. Le transtypage modifie ici la qualification de l’accès utilisé pour
l’atteindre.
7.10.4.1
reinterpret_cast : effectuer une conversion de bas niveau
reinterpret_cast est destiné à certaines conversions de bas niveau.
Par exemple :
1
2
std::uintptr_t adresse =
reinterpret_cast(p);
23/08/2026
(n)
dynamic_cast
const_cast
reinterpret_cast
dynamic_cast(p)
const_cast(p)
reinterpret_cast(p)
static_cast −→ convertir
dynamic_cast −→ vérifier dynamiquement
const_cast −→ modifier une qualification
reinterpret_cast −→ conversion de bas niveau
7.10.5
Quatre opérateurs, quatre questions différentes
Les quatre opérateurs ne constituent donc pas quatre manières concurrentes d’effectuer exactement
la même opération. Ils répondent à des questions différentes.
Avec static_cast, nous demandons principalement :
« Cette valeur peut-elle être convertie selon les règles prévues pour static_cast ? »
Avec dynamic_cast :
« L’objet désigné possède-t-il réellement un type compatible avec celui que je demande ? »
Avec const_cast :
« Je souhaite modifier la qualification const ou volatile de cet accès. »
Avec reinterpret_cast :
« J’effectue volontairement cette conversion de bas niveau entre les représentations de types
autorisées par cet opérateur. »
7.10.6
Et le transtypage de style C ?
Le transtypage hérité du langage C possède une syntaxe beaucoup plus générale :
1
(type)expression
Par exemple :
1
(int)x
Cette syntaxe indique le type souhaité, mais elle ne distingue pas explicitement les différentes catégories de transtypages que le C++ moderne sépare au moyen de ses opérateurs spécialisés. C’est l’une
des principales raisons pour lesquelles les opérateurs de transtypage C++ sont généralement préférés
dans du code C++ moderne.
23/08/2026
(8.7)
dynamic_cast fournit au contraire un mécanisme permettant de vérifier dynamiquement certaines
conversions dans une hiérarchie polymorphe.
const_cast peut conduire à un comportement indéfini si l’on tente ensuite de modifier un objet
réellement constant.
Enfin, reinterpret_cast intervient dans des opérations de bas niveau pour lesquelles la validité de
l’utilisation ultérieure du résultat demande une connaissance précise des types, des objets et de leur
représentation.
À retenir
• Le C++ possède quatre opérateurs de transtypage spécialisés : static_cast,
dynamic_cast, const_cast et reinterpret_cast.
• Ces quatre opérateurs ne sont pas quatre syntaxes différentes pour effectuer la même
opération.
• static_cast est utilisé pour de nombreuses conversions dont la validité peut être
déterminée à la compilation.
• dynamic_cast permet notamment de vérifier à l’exécution certaines conversions dans
une hiérarchie de classes polymorphes.
• const_cast permet de modifier certaines qualifications, principalement const.
• reinterpret_cast est destiné à certaines conversions de bas niveau et exige une
connaissance précise de l’utilisation qui sera faite du résultat.
• Le nom de chaque opérateur renseigne le lecteur sur la nature du transtypage demandé.
• Le transtypage de style C reste valide en C++, mais il exprime moins précisément la
catégorie de conversion demandée.
• Dans du code C++ moderne, on privilégie généralement l’opérateur C++ correspondant
exactement à l’intention du programmeur.
7.10.8
Conclusion
Les types constituent l’un des mécanismes fondamentaux du C++. Ils permettent au compilateur de
déterminer quelles opérations sont possibles, comment les valeurs doivent être interprétées et quelles
incompatibilités doivent être signalées.
Cependant, un programme réel doit fréquemment faire interagir des valeurs de types différents. Le
C++ fournit pour cela deux grandes catégories de mécanismes :
• les conversions implicites, appliquées automatiquement selon les règles du langage ;
• les conversions explicites, ou transtypages, demandées directement par le programmeur.
Les conversions implicites rendent possibles de nombreuses opérations naturelles :
23/08/2026
Accueil20 21 22 22 23 23 24 24 25 25 26 26 27 27 28 28 29 29 30 30 31 32 32 32 33 33 34 34 34 36 36 37 37 37 37 38 38 38 39 39 2/42 Chapitre 7 Conversions de types et transtypage 7.1 Pourquoi convertir un type ? Le C++ est un langage fortement typé. Lorsque nous déclarons une variable, nous indiquons le type des données qu’elle peut contenir : 1 2 3 int nombre = 5; double mesure = 3.7; char lettre = ’A’; Ces types ne sont pas interchangeables. Un int représente un nombre entier, un double permet de représenter un nombre réel avec une précision limitée et un char représente notamment un caractère. Il arrive cependant très fréquemment qu’une valeur d’un certain type doive être utilisée dans un contexte où un autre type est attendu. Une conversion de type devient alors nécessaire. 7.1.1 Une conversion déjà familière Considérons : 1 2 int n = 5; double x = n; La variable n est de type int, tandis que x est de type double. La valeur contenue dans n doit donc être représentée sous une forme compatible avec le type de x. Le compilateur effectue ici automatiquement une conversion : int −→ double Nous pouvons nous représenter l’opération ainsi : 5 −→ 5.0 Aucune instruction particulière n’a été demandée au compilateur. Cette conversion est dite implicite. Dans cette situation, la conversion est possible parce qu’une valeur entière telle que 5 peut être représentée comme une valeur de type double. 3 2026 – Partie II C++ Conversions de types et transtypage Le C++ définit de nombreuses conversions entre ses types fondamentaux. Elles permettent notamment d’utiliser ensemble des valeurs dont les types ne sont pas strictement identiques. Dans l’expression : 1 2 3 4 int n = 5; double x = 2.5; double resultat = n + x; les deux opérandes de l’addition ne possèdent pas le même type. Le C++ doit déterminer comment effectuer cette opération. Dans ce cas, la valeur entière est convertie vers un type permettant l’opération avec le double. Nous pouvons schématiser : n : int ↓ double x : double L’addition peut alors être effectuée avec des opérandes compatibles. 7.1.2 Toutes les conversions ne sont pas équivalentes Considérons maintenant la situation inverse : 1 2 double x = 8.7; int n = x; Le compilateur doit cette fois convertir une valeur de type double vers le type int. Or un int ne permet pas de représenter la partie fractionnaire de la valeur. Après conversion, nous obtenons : 8.7 −→ 8 Une partie de l’information a donc été perdue. Lors d’une conversion d’un nombre réel vers un type entier, la partie fractionnaire est supprimée. Il ne s’agit pas d’un arrondi. Par exemple : 8.9 −→ 8 et −8.9 −→ −8. La conversion vers l’entier effectue ici une troncature vers zéro. 23/08/2026
Accueil4/42 2026 – Partie II C++ 7.1.3 Conversions de types et transtypage Qui décide de la conversion ? Dans les exemples précédents, les conversions ont été déclenchées automatiquement par les règles du langage. Le programmeur n’a écrit aucune instruction particulière pour demander : « transforme cette valeur en double » ou : « transforme cette valeur en int ». On parle alors de conversion implicite. Il existe cependant des situations dans lesquelles le programmeur souhaite indiquer explicitement qu’une valeur doit être considérée ou convertie selon un autre type. Nous parlerons alors de conversion explicite ou de transtypage. conversion implicite : décidée automatiquement selon les règles du langage conversion explicite : demandée explicitement par le programmeur 7.1.4 Pourquoi demander explicitement une conversion ? Une conversion explicite peut être utile lorsque le programmeur souhaite, par exemple : • utiliser ensemble des valeurs dont les types sont différents ; • imposer le type utilisé dans une opération ; • convertir volontairement une valeur réelle en valeur entière ; • appeler une fonction exigeant un type particulier ; • rendre clairement visible dans le programme qu’un changement de type est intentionnel. Une conversion explicite ne doit cependant pas être considérée comme un moyen de contourner le système de types. Elle exprime au contraire une décision du programmeur dont celui-ci doit comprendre les conséquences. À retenir • Le C++ est un langage fortement typé, mais il permet certaines conversions entre types. • Une conversion de type intervient lorsqu’une valeur d’un type doit être utilisée dans un contexte nécessitant un autre type. • Certaines conversions sont effectuées automatiquement par le compilateur : ce sont les conversions implicites. • Une conversion peut modifier la représentation d’une valeur et parfois entraîner une perte d’information. • La conversion d’une valeur réelle vers un type entier supprime sa partie fractionnaire ; elle n’effectue pas un arrondi. • Une conversion peut également être demandée explicitement par le programmeur. On parle alors de conversion explicite ou de transtypage. • Demander explicitement une conversion suppose d’en comprendre les conséquences. 23/08/2026
Accueil5/42 2026 – Partie II C++ 7.2 Conversions de types et transtypage Les conversions implicites Une conversion est dite implicite lorsqu’elle est effectuée automatiquement par le compilateur, sans qu’une conversion soit explicitement demandée dans le programme. Nous en avons déjà rencontré un exemple : 1 2 int entier = 5; double reel = entier; La valeur contenue dans entier est de type int, alors que la variable reel est de type double. Le compilateur effectue automatiquement la conversion nécessaire. 7.2.1 Conversion lors d’une affectation Une conversion implicite apparaît fréquemment lorsqu’une valeur est affectée à une variable d’un autre type. Considérons : 1 2 int entier = 12; double reel = entier; Le type de la destination est connu : 1 double reel Le compilateur convertit donc la valeur de entier en double avant de l’affecter à reel. Nous pouvons représenter conceptuellement cette opération par : 12int −→ 12.0double . La conversion inverse est également possible : 1 2 double reel = 12.8; int entier = reel; Cette fois, la valeur doit être convertie de double vers int : 12.8double −→ 12int . La conversion est toujours implicite, mais elle entraîne maintenant une perte d’information. 7.2.2 Conversion lors d’un appel de fonction Une conversion implicite peut également avoir lieu lorsqu’un argument ne possède pas exactement le type attendu par un paramètre. Considérons : void afficher(double valeur) { 3 std::cout << valeur << std::endl; 4 } 1 2 Nous pouvons appeler cette fonction avec : 1 int n = 5; 2 3 afficher(n); 23/08/2026 https://cpp-iot-etc.ch 6/42 2026 - Partie II C++ Conversions de types et transtypage Le paramètre valeur est de type double, alors que l’argument n est de type int. Le compilateur effectue automatiquement la conversion : int −→ double. 7.2.3 Expressions contenant plusieurs types Les conversions implicites interviennent également dans les expressions arithmétiques. Considérons : 1 2 3 int entier = 5; double reel = 2.5; 4 double resultat = entier + reel; L’opérateur + reçoit ici deux opérandes de types différents. Le C++ applique ses règles de conversions arithmétiques afin de déterminer un type commun approprié pour effectuer l’opération. Dans cet exemple, la valeur entière est convertie en double : 5int −→ 5.0double . L’addition devient alors conceptuellement : 5.0double + 2.5double = 7.5double . 7.2.4 Les promotions Certaines conversions implicites portent plus précisément le nom de promotions. Une promotion convertit notamment certains petits types entiers vers un type entier permettant d’effectuer les opérations arithmétiques usuelles. Considérons par exemple : 1 2 char lettre = ’A’; 3 int code = lettre; Dans les jeux de caractères usuels compatibles avec ASCII, le caractère ’A’ correspond à la valeur numérique 65. La valeur peut donc être utilisée sous forme entière : 1 std::cout << code << std::endl; qui affichera alors : 65 Cette expérience montre que le contexte dans lequel une valeur est utilisée est important. Dans : 1 std::cout << lettre; 23/08/2026 https://cpp-iot-etc.ch 7/42 2026 - Partie II C++ Conversions de types et transtypage la valeur est traitée comme un caractère. Mais dans : 1 lettre + 1 une opération arithmétique est demandée. Le char subit alors une promotion entière avant l’addition. 7.2.5 Le type de destination n’agit pas rétroactivement Considérons : 1 2 3 int a = 5; int b = 2; 4 double resultat = a / b; Les deux opérandes de la division sont de type int. La division effectuée est donc une division entière : 5/2 = 2. Ce n’est qu’ensuite que le résultat est converti en double pour être affecté à resultat : 2int −→ 2.0double . La variable resultat contient donc 2.0, et non 2.5. Si l’un des opérandes est déjà de type double : 1 double resultat = a / 2.0; les règles de conversion conduisent ici à effectuer la division avec des valeurs de type double. Nous obtenons alors : 5.0/2.0 = 2.5. 7.2.6 Conversion possible et conservation de l’information Le fait que le compilateur puisse effectuer automatiquement une conversion ne signifie pas que celleci conserve nécessairement toute l’information. Par exemple : 1 2 double x = 3.14159; int n = x; est une conversion autorisée, mais la partie fractionnaire est perdue. De manière générale, il faut donc distinguer deux questions : 1. la conversion est-elle autorisée par le langage ? 2. la valeur obtenue conserve-t-elle l’information qui nous intéresse ? Ces deux questions ne sont pas équivalentes. 23/08/2026 https://cpp-iot-etc.ch 8/42 2026 - Partie II C++ Conversions de types et transtypage À retenir • Une conversion implicite est effectuée automatiquement selon les règles du langage, sans transtypage écrit par le programmeur. • Une conversion implicite peut intervenir lors d’une affectation, d’un appel de fonction ou de l’évaluation d’une expression. • Lorsque plusieurs types numériques interviennent dans une expression, le C++ applique des règles de conversion afin de déterminer comment effectuer l’opération. • Certaines conversions implicites sont appelées des promotions. • Le type de la variable recevant le résultat ne modifie pas rétroactivement les opérations déjà effectuées. • Dans : 1 double resultat = 5 / 2; la division entière produit d’abord 2, qui est ensuite converti en double. • Une conversion implicite autorisée peut néanmoins entraîner une perte d’information. 7.3 Conversions et pertes d’information Une conversion entre deux types numériques ne garantit pas que toute l’information contenue dans la valeur initiale puisse être conservée. Certains types permettent de représenter des ensembles de valeurs très différents. Lorsqu’une valeur est convertie vers un type incapable de représenter exactement cette valeur, une partie de l’information peut être perdue. Il est donc essentiel de distinguer : conversion autorisée et conversion sans perte d’information. Ces deux notions ne sont pas équivalentes. 7.3.1 Perte de la partie fractionnaire Considérons : 1 2 double x = 8.7; int n = x; La variable x contient une valeur possédant une partie fractionnaire. Le type int ne permet pas de conserver cette partie. Lors de la conversion : 8.7double −→ 8int la partie fractionnaire est supprimée. 23/08/2026 https://cpp-iot-etc.ch 9/42 2026 - Partie II C++ Conversions de types et transtypage Cette conversion n’effectue pas un arrondi au nombre entier le plus proche. Par exemple : 8.9 −→ 8 et −8.9 −→ −8. La partie fractionnaire est supprimée : la conversion s’effectue donc vers zéro. 7.3.2 Le compilateur peut accepter une perte d’information L’écriture : 1 2 double x = 8.7; int n = x; est autorisée par le langage. Cela ne signifie pas que la conversion préserve la valeur initiale. Le compilateur applique les règles du langage, mais il ne peut pas déterminer si la perte de la partie fractionnaire correspond réellement à l’intention du programmeur. 7.3.3 Conversion d’un entier vers un réel Une conversion de int vers double paraît généralement moins problématique : 1 2 int n = 90; double x = n; La valeur 90 peut être représentée exactement sous forme de double. La conversion conserve donc ici la valeur : 90int −→ 90.0double . Il faut cependant éviter d’en déduire que toute conversion d’un type entier vers un type à virgule flottante est nécessairement exacte. Les types à virgule flottante possèdent une précision finie. Certaines valeurs entières suffisamment grandes peuvent donc ne pas être représentables exactement dans le type de destination. 7.3.4 Conversion entre types entiers Les différents types entiers ne possèdent pas nécessairement la même capacité de représentation. Lorsqu’une valeur est convertie vers un type dont l’ensemble des valeurs représentables est plus restreint, la valeur initiale peut ne pas être représentable dans le type de destination. Par exemple, une conversion vers un type entier plus petit doit être considérée avec attention. En cas de nécessité on peut utiliser numeric_limits<...> 7.3.5 Types signés et non signés Une attention particulière est également nécessaire lors des conversions entre types entiers signés et non signés. Un type signé peut représenter des valeurs négatives : 1 int n = -5; alors qu’un type non signé tel que : 1 unsigned int n; 23/08/2026
Accueil10/42 2026 – Partie II C++ Conversions de types et transtypage ne représente pas de valeurs négatives. Une conversion entre ces catégories peut donc produire une valeur très différente de celle que le programmeur aurait intuitivement attendue. 7.3.6 Les accolades et les conversions réductrices Le C++ moderne fournit une forme d’initialisation qui permet d’interdire certaines conversions susceptibles de perdre de l’information. Comparons : int a = 8.7; int b(8.7); 3 int c{8.7}; 1 2 Les deux premières initialisations autorisent la conversion de double vers int. Nous obtenons alors : a =8 et b = 8. La troisième écriture est différente : 1 int c{8.7}; Elle provoque une erreur de compilation. L’initialisation par accolades interdit certaines conversions dites réductrices, ou narrowing conversions. Dans notre exemple, convertir 8.7 en int supprimerait la partie fractionnaire. Le compilateur refuse donc cette initialisation. L’écriture avec accolades ne constitue pas une nouvelle manière de convertir la valeur. Elle impose au contraire des règles plus strictes lors de l’initialisation et permet ainsi de détecter certaines conversions potentiellement dangereuses dès la compilation. Fig. 7.1 – 7.3.7 La taille du type n’est pas le seul critère Il serait tentant de décider si une conversion est sûre uniquement en comparant les valeurs retournées par sizeof. Ce raisonnement est insuffisant. Deux types peuvent utiliser le même nombre d’octets tout en représentant des ensembles de valeurs très différents. Par exemple, un entier et un nombre à virgule flottante n’utilisent pas leurs bits de la même manière. Pour étudier une conversion, il faut donc considérer non seulement la taille des types, mais surtout les valeurs et la précision qu’ils peuvent représenter. Nous pouvons maintenant distinguer trois situations : 23/08/2026
Accueil11/42 2026 – Partie II C++ Conversions de types et transtypage 1. la valeur peut être représentée dans le nouveau type sans perte pertinente ; 2. la conversion est autorisée, mais une partie de l’information est perdue ; 3. la forme d’initialisation utilisée interdit la conversion et provoque une erreur de compilation. À retenir • Une conversion de type peut entraîner une perte d’information. • Lors d’une conversion d’un nombre à virgule flottante vers un type entier, la partie fractionnaire est supprimée ; il ne s’agit pas d’un arrondi. • Une conversion implicite peut être autorisée par le langage tout en produisant une valeur différente de celle que le programmeur souhaitait. • Les conversions entre types entiers de capacités différentes ainsi qu’entre types signés et non signés doivent être examinées avec attention. • Les types à virgule flottante possèdent une précision finie : une conversion numérique n’est donc pas nécessairement exacte. • L’initialisation par accolades interdit certaines conversions réductrices : 1 int n{8.7}; // erreur • Une conversion autorisée n’est pas nécessairement une conversion sans perte d’information. 7.4 Le transtypage : conversion explicite Jusqu’à présent, nous avons principalement rencontré des conversions effectuées automatiquement par le compilateur. Par exemple : 1 2 int entier = 5; double reel = entier; Le programmeur ne demande explicitement aucune conversion. Le compilateur constate que la valeur de type int doit être utilisée pour initialiser une variable de type double et applique la conversion prévue par le langage. Il s’agit d’une conversion implicite. 7.4.1 Exprimer explicitement son intention Considérons maintenant : 1 2 double mesure = 8.7; int valeur = mesure; Le compilateur accepte cette conversion. La partie fractionnaire est supprimée et nous obtenons : 8.7double −→ 8int . Cette écriture ne permet cependant pas de savoir immédiatement si cette perte d’information est réellement voulue par le programmeur ou si elle résulte d’une erreur. 23/08/2026
Accueil12/42 2026 – Partie II C++ Conversions de types et transtypage Le compilateur peut autoriser une opération qui n’est pas celle que nous voulions. Le programmeur peut donc souhaiter indiquer explicitement qu’il demande une conversion et qu’il en accepte les conséquences. On parle alors de conversion explicite ou de transtypage. 7.4.2 Deux situations différentes Nous devons maintenant distinguer clairement deux mécanismes. Dans une conversion implicite, le programmeur fournit des valeurs de types différents et laisse le compilateur appliquer les règles de conversion du langage. Dans une conversion explicite, le programmeur indique dans le code le type vers lequel il souhaite effectuer la conversion. Nous pouvons résumer : conversion implicite : le compilateur applique automatiquement une conversion conversion explicite : le programmeur demande explicitement une conversion 7.4.3 Pourquoi utiliser un transtypage ? Le transtypage peut remplir plusieurs fonctions. Il permet tout d’abord de rendre visible l’intention du programmeur. Lorsqu’une conversion susceptible de modifier une valeur est écrite explicitement, le lecteur du programme sait immédiatement qu’elle a été demandée volontairement. Le transtypage peut également être nécessaire pour imposer le type utilisé dans une expression ou pour fournir à une fonction un argument du type attendu. 7.4.4 Modifier le type avant une opération Le moment auquel une conversion intervient peut modifier le résultat d’un calcul. Nous avons vu que : 1 2 3 4 int a = 5; int b = 2; double resultat = a / b; effectue d’abord une division entière. Nous obtenons donc : 5/2 = 2 avant que le résultat soit converti en double. Si nous demandons au contraire que l’un des opérandes soit converti en double avant la division, la nature de l’opération change : 5.0/2 = 2.5. Un transtypage peut donc servir non seulement à déterminer le type d’une valeur obtenue, mais également à contrôler le type avec lequel une opération sera effectuée. 23/08/2026
Accueil13/42 2026 – Partie II C++ 7.4.5 Conversions de types et transtypage Le type de la variable originale ne change pas Lorsqu’une valeur est explicitement convertie vers un autre type, cela ne signifie pas que le type de la variable dont elle provient est modifié. Considérons une variable : 1 int a = 5; Si nous utilisons la valeur de a après l’avoir explicitement convertie en double, la variable a reste elle-même de type int. La conversion produit une valeur adaptée au contexte dans lequel elle est utilisée mais ne transforme pas la déclaration originale : 1 int a en une déclaration de type double. 7.4.6 Un transtypage n’autorise pas n’importe quelle opération Demander explicitement une conversion ne signifie pas que le compilateur acceptera nécessairement cette conversion. Les conversions possibles dépendent des types concernés et du mécanisme de transtypage utilisé. Le transtypage ne constitue donc pas une instruction signifiant au compilateur : « transforme cette valeur coûte que coûte ». Il constitue une demande explicite de conversion qui reste soumise aux règles du langage. 7.4.7 Plusieurs formes de transtypage Le C++ possède plusieurs mécanismes permettant d’exprimer explicitement une conversion. Nous rencontrerons notamment : 1 (int)valeur qui correspond à une syntaxe héritée du langage C, ainsi que les mécanismes spécifiques au C++ : 1 2 3 4 static_cast dynamic_cast const_cast reinterpret_cast Ces différents transtypages n’ont pas tous le même rôle. Le choix du mécanisme utilisé fournit donc également une information sur la nature de la conversion demandée. Nous pouvons déjà retenir leur rôle général : 23/08/2026 static_cast conversions ordinaires connues à la compilation dynamic_cast conversions liées à certaines hiérarchies de classes const_cast modification des qualifications const ou volatile reinterpret_cast réinterprétation de bas niveau
Accueil14/42 2026 – Partie II C++ Conversions de types et transtypage Nous étudierons séparément ces mécanismes afin de comprendre pourquoi le C++ moderne préfère distinguer explicitement plusieurs catégories de transtypages. À retenir • Une conversion explicite est une conversion demandée volontairement dans le code par le programmeur. On parle également de transtypage. • Rendre une conversion explicite permet notamment d’indiquer clairement qu’un changement de type est intentionnel. • Un transtypage peut modifier le type utilisé pour effectuer une opération et donc modifier le résultat de cette opération. • Convertir la valeur d’une variable ne change pas le type de la variable originale. • Un transtypage ne permet pas d’effectuer arbitrairement n’importe quelle conversion : les règles du langage continuent de s’appliquer. • Le C++ possède plusieurs mécanismes de transtypage ayant des rôles différents. • La syntaxe héritée du C existe toujours, mais le C++ fournit également des opérateurs de transtypage spécifiques : static_cast, dynamic_cast, const_cast et reinterpret_cast. 7.5 Le transtypage de style C Le C++ conserve une syntaxe de transtypage héritée du langage C. Elle consiste à placer entre parenthèses le type souhaité devant l’expression à convertir. La forme générale est : 1 (type)expression Par exemple : 1 2 double x = 8.7; int n = (int)x; L’expression : 1 (int)x demande explicitement une conversion de la valeur de x vers le type int. 7.5.1 Conversion de double vers int Considérons : 1 2 double x = 8.7; int n = (int)x; La conversion est cette fois explicitement demandée par le programmeur. Nous obtenons : 8.7double −→ 8int . Comme lors de la conversion implicite étudiée précédemment, la partie fractionnaire est supprimée. 23/08/2026
Accueil15/42 2026 – Partie II C++ Conversions de types et transtypage La présence du transtypage ne modifie donc pas la règle de conversion mais rend explicite la volonté de l’effectuer. 7.5.2 Le transtypage porte sur une expression Le transtypage ne change pas le type de la variable originale. Considérons : 1 2 3 double x = 8.7; int n = (int)x; La variable x reste de type double et conserve sa valeur. Le transtypage : 1 (int)x produit une valeur de type int à partir de la valeur de x. 7.5.3 Transtyper avant une opération Le transtypage peut être effectué avant une opération afin de modifier les types avec lesquels cette opération sera évaluée. Reprenons : 1 2 3 4 int a = 5; int b = 2; double resultat = a / b; La division est effectuée entre deux int : 5/2 = 2. Nous obtenons donc finalement : resultat = 2.0. Nous pouvons maintenant écrire : 1 double resultat = (double)a / b; Le transtypage : 1 (double)a produit une valeur de type double avant que la division soit effectuée, conceptuellement on a : 5int −→ 5.0double . L’expression devient alors : 5.0/2. Les règles de conversion arithmétique conduisent à effectuer la division avec des valeurs de type double et nous obtenons finalement : resultat = 2.5 Soit 23/08/2026
Accueil16/42 2026 – Partie II C++ 1 2 3 4 5 6 7 8 Conversions de types et transtypage int a = 5; int b = 2; double x = a / b; double y = (double)a / b; std::cout << x << std::endl; std::cout << y << std::endl; dont la sortie est : 1 2 2 2.5 Dans : 1 (double)a les parenthèses entourant double appartiennent à la syntaxe du transtypage. Il ne faut donc pas confondre cette écriture avec l’utilisation habituelle des parenthèses pour contrôler l’ordre d’évaluation d’une expression. 7.5.4 Une syntaxe héritée du langage C La syntaxe : 1 (int)x provient du langage C. Le C++ ayant été conçu historiquement à partir du C, une grande quantité de code et de pratiques utilisant cette forme de transtypage existait déjà. Le C++ conserve donc cette syntaxe, qui reste valide. Nous pouvons ainsi rencontrer très fréquemment des expressions telles que : 1 2 3 (int)x (double)n (char)code dans des programmes C et C++. Le C++ permet également certaines conversions explicites sous une forme ressemblant à l’appel d’une fonction : 1 int n = int(x); Cette écriture ne signifie pas que int est une classe possédant un constructeur. int reste un type fondamental. Nous privilégierons cependant par la suite les opérateurs de transtypage spécifiques au C++ moderne. 7.5.5 Une syntaxe peu descriptive Le principal problème du transtypage de style C en C++ est qu’il exprime peu précisément la nature de la conversion demandée. Lorsque nous rencontrons : 23/08/2026 https://cpp-iot-etc.ch 17/42 2026 - Partie II C++ 1 Conversions de types et transtypage (int)x nous savons que le programmeur souhaite obtenir une valeur de type int, mais la syntaxe elle-même n’indique pas quelle catégorie de conversion est effectuée. Un autre avantage des opérateurs de transtypage du C++ est leur visibilité dans le code. Il est très facile de rechercher toutes les occurrences de : 1 static_cast dans un projet. La recherche systématique des transtypages de style C est beaucoup moins simple, car les parenthèses sont utilisées partout dans un programme C++. 7.5.6 Une syntaxe toujours valide Le transtypage de style C n’est pas interdit en C++. L’écriture : 1 int n = (int)x; est parfaitement valide lorsque la conversion demandée est autorisée. Nous la rencontrerons donc encore dans de nombreux programmes. En C++ moderne, on préfère cependant généralement utiliser les opérateurs de transtypage propres au C++, car ils expriment plus précisément l’intention du programmeur et permettent de mieux distinguer différentes catégories de conversions. À retenir • Le C++ conserve une syntaxe de transtypage héritée du langage C : 1 (type)expression • Par exemple : 1 int n = (int)x; demande explicitement une conversion de la valeur de x vers le type int. • Le transtypage agit sur une expression ; il ne change pas le type de la variable originale. • Un transtypage effectué avant une opération peut modifier le type avec lequel cette opération est évaluée et donc son résultat. • La syntaxe de style C reste parfaitement valide en C++. • Elle indique le type souhaité, mais exprime peu précisément la nature de la conversion effectuée. • Le C++ fournit des opérateurs de transtypage spécifiques qui permettent de distinguer différentes catégories de conversions. • Dans du code C++ moderne, ces opérateurs sont généralement préférés au transtypage de style C. 23/08/2026 https://cpp-iot-etc.ch 18/42 2026 - Partie II C++ 7.6 Conversions de types et transtypage static_cast Le C++ fournit plusieurs opérateurs de transtypage spécialisés. Le plus couramment utilisé pour les conversions ordinaires est : 1 static_cast Sa syntaxe générale est : 1 static_cast
Accueil19/42 2026 – Partie II C++ 7.6.4 Conversions de types et transtypage Modifier le type utilisé dans une expression Reprenons : 1 2 3 4 5 int a = 5; int b = 2; double resultat = static_cast
Accueil20/42 2026 – Partie II C++ 7.6.7 Conversions de types et transtypage Une conversion visible dans le programme L’écriture : 1 static_cast
Accueil22/42 2026 – Partie II C++ 4 5 6 7 8 9 10 11 12 13 14 Conversions de types et transtypage virtual ~Forme() = default; }; class Carre : public Forme { }; class Cercle : public Forme { }; La présence d’au moins une fonction virtuelle rend la classe Forme polymorphe. Cette propriété permettra notamment à dynamic_cast de déterminer le type réel de certains objets pendant l’exécution. 7.7.2 Type du pointeur et type réel de l’objet Considérons : 1 2 3 Carre carre; Forme* forme = &carre; La variable forme est un pointeur de type : 1 Forme* mais elle contient l’adresse d’un objet dont le type réel est Carre. Nous devons donc distinguer : type du pointeur : Forme* type réel de l’objet : Carre 7.7.3 Vérifier le type réel de l’objet Nous pouvons tenter de retrouver un pointeur vers le type dérivé : 1 2 Carre* carre2 = dynamic_cast
Accueil23/42 2026 – Partie II C++ 7.7.4 Conversions de types et transtypage Échec du transtypage d’un pointeur Considérons maintenant : 1 2 3 4 5 6 Cercle cercle; Forme* forme = &cercle; Carre* carre = dynamic_cast
Accueil24/42 2026 – Partie II C++ 22 23 24 25 26 Forme* forme1 = &carre; Forme* forme2 = &cercle; Carre* resultat1 = dynamic_cast
Accueil27/42 2026 – Partie II C++ Conversions de types et transtypage 1 2 std::cout << *p << std::endl; // autorise 3 *p = 10; // erreur La qualification const concerne ici l’accès fourni par p. 7.8.1 Retirer une qualification const Nous pouvons demander explicitement un accès non constant à l’objet : 1 2 int* q = const_cast
Accueil28/42 2026 – Partie II C++ Conversions de types et transtypage nous essayons de modifier un objet qui a réellement été créé const. Le programme présente alors un comportement indéfini (undefined behavior ). Il ne faut donc pas effectuer cette opération. Objet original Accès Modification après const_cast int a = 5; const int* possible const int a = 5; const int* comportement indéfini La question essentielle n’est donc pas seulement : « le pointeur contient-il const dans son type ? » mais également : « l’objet original a-t-il réellement été déclaré const ? » 7.8.3 const_cast et les références Le même principe s’applique aux références. Considérons : 1 2 3 4 int a = 5; 5 6 7 8 int& autreRef = const_cast
Accueil29/42 2026 – Partie II C++ 7.8.5 Conversions de types et transtypage Pourquoi utiliser const_cast ? Dans du code C++ moderne correctement conçu, retirer une qualification const doit rester une opération exceptionnelle. const_cast peut cependant être nécessaire lors de l’interaction avec une interface ancienne dont la déclaration ne respecte pas correctement la constance des données. Supposons par exemple qu’une ancienne fonction soit déclarée : 1 void ancienneFonction(char* texte); alors que cette fonction ne modifie en réalité jamais les caractères désignés par son paramètre. Une interface moderne aurait probablement été déclarée : 1 void fonction(const char* texte); Dans certaines situations bien contrôlées, const_cast peut alors servir d’adaptateur entre ces deux conceptions. Une telle utilisation n’est sûre que si l’on sait que la fonction appelée ne tentera effectivement pas de modifier un objet qui doit rester constant. const_cast ne doit donc pas être utilisé simplement pour faire disparaître une erreur du compilateur liée à const. 7.8.6 La qualification volatile Malgré son nom, const_cast ne concerne pas uniquement const. Il permet également certaines modifications des qualifications volatile. Nous ne développerons pas ici les utilisations de volatile, qui apparaissent notamment dans certains contextes de programmation de bas niveau. Nous retiendrons pour l’instant que const_cast est l’opérateur C++ destiné à modifier les qualifications const et volatile. Illustration : 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 #include
Accueil31/42 2026 – Partie II C++ 1 Conversions de types et transtypage reinterpret_cast
Accueil32/42 2026 – Partie II C++ Conversions de types et transtypage l’objet situé à l’adresse considérée reste un int. Tenter d’y accéder comme s’il s’agissait réellement d’un objet double peut violer les règles du langage et conduire à un comportement indéfini. reinterpret_cast exige donc une connaissance précise de la représentation des objets et des règles d’accès à la mémoire. 7.9.3.1 Convertir ou réinterpréter Il faut distinguer fondamentalement une conversion de valeur d’une réinterprétation de bas niveau. Considérons : 1 2 3 int n = 90; double x = static_cast
Accueil33/42 2026 – Partie II C++ 4 5 6 Conversions de types et transtypage std::uintptr_t adresse = reinterpret_cast
Accueil34/42 2026 – Partie II C++ 5 6 7 8 9 int main() { int n = 90; int* p = &n; 10 11 12 13 14 15 std::uintptr_t adresse = reinterpret_cast
Accueil36/42 2026 – Partie II C++ Conversions de types et transtypage Le type souhaité apparaît entre les chevrons et l’expression concernée entre les parenthèses. C’est donc principalement le nom de l’opérateur qui indique la nature du transtypage demandé. 7.10.2 static_cast : effectuer une conversion connue static_cast est utilisé pour de nombreuses conversions dont la validité peut être déterminée à la compilation. Nous l’avons notamment utilisé pour les conversions numériques : 1 double x = 8.7; 2 3 4 int n = static_cast
Accueil37/42 2026 – Partie II C++ Conversions de types et transtypage nous permet, lorsque std::uintptr_t est disponible, de convertir une valeur de pointeur sous une forme entière capable de la représenter. Ce mécanisme ne doit pas être confondu avec une conversion numérique ordinaire. 7.10.4.2 Tableau comparatif Opérateur Rôle principal Exemple static_cast Conversion vérifiable statiquement Vérification de type dans une hiérarchie polymorphe Modification des qualifications const ou volatile Certaines conversions de bas niveau static_cast
Accueil38/42 2026 – Partie II C++ 7.10.7 Conversions de types et transtypage Des responsabilités différentes Tous les transtypages exigent que le programmeur comprenne la conversion demandée, mais certains nécessitent une vigilance particulière. Une conversion numérique avec static_cast peut, par exemple, entraîner une perte d’information : 1 static_cast
Accueil39/42 2026 – Partie II C++ 1 2 Conversions de types et transtypage int n = 5; double x = n; mais elles peuvent également entraîner une perte d’information : 1 2 double x = 8.7; int n = x; Nous avons donc appris qu’une conversion autorisée n’est pas nécessairement une conversion exacte ni une conversion souhaitable. L’initialisation par accolades fournit par ailleurs une protection supplémentaire contre certaines conversions réductrices : 1 int n{8.7}; // erreur Le compilateur peut ainsi détecter certaines pertes d’information dès la compilation. Lorsqu’une conversion doit être explicitement demandée, le C++ moderne fournit quatre opérateurs spécialisés : static_cast −→ conversion statiquement vérifiable dynamic_cast −→ vérification dynamique dans une hiérarchie polymorphe const_cast −→ modification de qualifications reinterpret_cast −→ conversion de bas niveau Cette séparation permet d’exprimer beaucoup plus précisément l’intention du programmeur que l’ancienne syntaxe de transtypage héritée du C. Le système de types ne doit donc pas être considéré comme un obstacle que le transtypage permettrait de contourner. Au contraire, lorsqu’un cast devient nécessaire, son choix doit préciser la nature de l’opération que nous demandons au compilateur. Un transtypage bien choisi constitue ainsi une information supplémentaire dans le programme. Il indique non seulement vers quel type nous souhaitons aller, mais également, dans une large mesure, pourquoi et de quelle manière nous effectuons cette conversion. À retenir • Le C++ permet de convertir des valeurs entre différents types, mais toutes les conversions n’ont pas les mêmes conséquences. • Une conversion peut être implicite ou explicitement demandée par le programmeur. • Une conversion autorisée peut entraîner une perte d’information. • Les quatre opérateurs de transtypage du C++ correspondent à des intentions différentes. • Le choix d’un cast fait partie de la conception et de la lisibilité du programme. • Avant d’imposer une conversion, il faut toujours comprendre pourquoi elle est nécessaire.
AccueilP2-Chap-07- Conversions de types et transtypage 23/08/2026
Accueil40/42 2026 – Partie II C++ 23/08/2026 Conversions de types et transtypage
Accueil41/42 Termes à ajouter au glossaire 42