<?xml version="1.0" encoding="UTF-8"?><rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	>

<channel>
	<title>blog.freelan.org &#187; &#187; dynamic_cast</title>
	<atom:link href="https://blog.freelan.org/tag/dynamic_cast/feed/" rel="self" type="application/rss+xml" />
	<link>https://blog.freelan.org</link>
	<description>De l&#039;informatique, des octets et des poneys.</description>
	<lastBuildDate>Fri, 04 Apr 2014 17:34:59 +0000</lastBuildDate>
	<language>fr-FR</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
	<generator>https://wordpress.org/?v=4.1.42</generator>
	<item>
		<title>Les casts en C++</title>
		<link>https://blog.freelan.org/2011/01/17/les-casts-en-cpp/</link>
		<comments>https://blog.freelan.org/2011/01/17/les-casts-en-cpp/#comments</comments>
		<pubDate>Mon, 17 Jan 2011 17:30:05 +0000</pubDate>
		<dc:creator><![CDATA[Julien Kauffmann]]></dc:creator>
				<category><![CDATA[C++]]></category>
		<category><![CDATA[Développement]]></category>
		<category><![CDATA[c++]]></category>
		<category><![CDATA[cast]]></category>
		<category><![CDATA[const_cast]]></category>
		<category><![CDATA[conversion]]></category>
		<category><![CDATA[conversions]]></category>
		<category><![CDATA[dynamic_cast]]></category>
		<category><![CDATA[reinterpret_cast]]></category>
		<category><![CDATA[static_cast]]></category>

		<guid isPermaLink="false">http://blog.freelan.org/?p=196</guid>
		<description><![CDATA[Nombreux sont les programmeurs C++ qui ont d'abord été confrontés au C. Les deux langages partagent en effet bien des fonctionnalités... mais ont également de grandes différences.

Parmi ces différences, on trouve les opérateurs de conversion C++. Ils sont certainement l'un des points les plus mal compris par les développeurs C qui voient souvent en eux un verbiage inutile. L'objectif de cet article est de (dé)montrer l'utilité des opérateurs de conversion C++, en comparaison avec les conversions classiques, dites : "à la C" et de comprendre ce qu'ils peuvent apporter au programmeur en termes de maintenabilité et de sécurité.]]></description>
				<content:encoded><![CDATA[<p>Nombreux sont les programmeurs C++ qui ont d&#8217;abord été confrontés au C. Les deux langages partagent en effet bien des fonctionnalités&#8230; mais ont également de grandes différences.</p>
<p>Parmi ces différences, on trouve les opérateurs de conversion C++. Ils sont certainement l&#8217;un des points les plus mal compris par les développeurs C qui voient souvent en eux un verbiage inutile. L&#8217;objectif de cet article est de (dé)montrer l&#8217;utilité des opérateurs de conversion C++, en comparaison avec les conversions classiques, dites : &#8220;à la C&#8221; et de comprendre ce qu&#8217;ils peuvent apporter au programmeur en termes de maintenabilité et de sécurité.</p>
<h1>Un petit mot sur les conversions</h1>
<p>Les conversions (ou &#8220;cast&#8221; en anglais) sont un des outils incontournables du programmeur C++. Mais comme tout outil, il faut savoir les utiliser à bon escient.</p>
<p>Dans l&#8217;idéal, un programme doit contenir le moins possible de &#8220;casts&#8221; : les types doivent s&#8217;interfacer naturellement les uns avec les autres. Cela garantit un <strong>découplage</strong> du code et donc une meilleure maintenabilité. Cela ne signifie pas qu&#8217;il faille à tout prix éviter les &#8220;casts&#8221; mais simplement qu&#8217;il faut les utiliser avec parcimonie.</p>
<p>Dans les sections qui suivent, nous allons expliquer le rôle de chaque opérateur de conversion. Pour l&#8217;ensemble des sections, nous considérerons les classes suivantes lorsqu&#8217;il sera question de hiérarchie :</p><pre class="crayon-plain-tag">class Base { public: virtual ~Base() {} };
class Derived : public Base {};
class Derived2 : public Base {};</pre><p></p>
<h1>static_cast&lt;&gt;</h1>
<p>Il permet plusieurs choses :</p>
<ul>
<li>Expliciter les conversions implicites, supprimant du même fait <strong>tout avertissement</strong> que donnerait le compilateur si la conversion peut entraîner un risque. Exemple : <strong>double</strong> vers <strong>int</strong>.</li>
<li>Convertir vers et depuis n&#8217;importe quel type pointé à partir d&#8217;un <strong>void*</strong>. Exemple : <strong>void*</strong> vers <strong>unsigned char*</strong>.</li>
<li>Convertir au travers d&#8217;une hiérarchie de classe, <strong>sans effectuer de vérification préalable</strong>. Exemple : <strong>Base*</strong> vers <strong>Derived*</strong> ou <strong>Base&amp;</strong> vers <strong>Derived&amp;</strong>.</li>
<li>Ajouter l&#8217;attribut constant au type converti. Exemple : <strong>char*</strong> vers <strong>const char*</strong>.</li>
</ul>
<p>Dans le dernier cas, notez que puisqu&#8217;il n&#8217;y a <strong>aucune vérification</strong> et que <strong>static_cast&lt;&gt;</strong> n&#8217;échoue <strong>jamais</strong>, le code suivant a un <strong>comportement indéfini</strong> (communément nommé en anglais &#8220;<em>undefined behavior</em>&#8221; ou &#8220;<em>UB</em>&#8220;) :</p><pre class="crayon-plain-tag">void foo()
{
Base* base = new Derived();

// Ce code est valide et correct car base pointe en fait vers une instance de Derived.
Derived* derived = static_cast&amp;lt;Derived*&amp;gt;(base);

// Ce code compile mais &agrave; un comportement ind&eacute;fini (Undefined Behavior)
// car base ne pointe pas vers une instance de Derived2.
Derived2* derived2 = static_cast&amp;lt;Derived2*&amp;gt;(base);
}</pre><p>Notez que la notion de <strong>comportement indéfini</strong> n&#8217;offre par définition <strong>aucune garantie</strong> : le code peut avoir le comportement espéré, faire crasher le programme ou provoquer l&#8217;envoi d&#8217;un missile nucléaire sur Cuba.</p>
<p>Il ne permet <strong>pas</strong> de :</p>
<ul>
<li>Convertir vers ou depuis un type pointé à partir d&#8217;un autre type pointé <strong>autre que void*</strong>. Exemple : <strong>unsigned char*</strong> vers <strong>char*</strong>.</li>
<li>Tester qu&#8217;une instance est celle d&#8217;un type dérivé. Exemple : tester qu&#8217;un <strong>Base*</strong> est en fait un <strong>Derived*</strong>.</li>
<li>Supprimer l&#8217;attribut <strong>constant</strong> du type converti. Exemple : <strong>const char*</strong> vers <strong>char*</strong>.</li>
</ul>
<h2>En bref</h2>
<p><strong>static_cast&lt;&gt;</strong> est sans doute l&#8217;opérateur de conversion que vous serez amené à utiliser le plus. Il ne permet que de réaliser des conversions sûres et à pour rôle principal celui d&#8217;expliciter les conversions implicites.</p>
<p>Dans le cas du polymorphisme, il est à préférer à <strong>dynamic_cast&lt;&gt;</strong> lorsque l&#8217;on a <strong>la garantie</strong> que la conversion va réussir.</p>
<h1>dynamic_cast&lt;&gt;</h1>
<p>Le seul rôle de <strong>dynamic_cast&lt;&gt;</strong> est de tester à l&#8217;exécution si un pointeur d&#8217;un type de base est en fait un pointeur vers un type dérivé.</p>
<p>Exemple :</p><pre class="crayon-plain-tag">void foo()
{
Base* base = new Derived();

// Apr&egrave;s l'appel, derived pointe vers l'instance de Derived
// car base pointe en fait vers une instance de Derived.
Derived* derived = dynamic_cast&amp;lt;Derived*&amp;gt;(base);

// Apr&egrave;s l'appel, derived2 vaut 0
// car base ne pointe pas vers une instance de Derived2.
Derived2* derived2 = dynamic_cast&amp;lt;Derived2*&amp;gt;(base);

// Dans le cas d'une r&eacute;f&eacute;rence, si le cast n'est pas possible
// Une exception de type std::bad_alloc est lanc&eacute;e.
Derived2&amp;amp; derived2_bis = dynamic_cast&amp;lt;Derived2&amp;amp;&amp;gt;(*base);
}</pre><p>Note : pour que <strong>dynamic_cast&lt;&gt;</strong> fonctionne, le type de base doit posséder <strong>au moins une</strong> méthode virtuelle.</p>
<p>Un appel à <strong>dynamic_cast&lt;&gt;</strong> est plus coûteux qu&#8217;un appel à <strong>static_cast&lt;&gt;</strong>car <strong>dynamic_cast&lt;&gt;</strong> effectue une recherche dans la &#8220;<em>v-table</em>&#8221; de l&#8217;instance <strong>à l&#8217;exécution</strong> pour déterminer son type exact.</p>
<p>On veillera donc à n&#8217;utiliser <strong>dynamic_cast&lt;&gt;</strong> que lorsqu&#8217;il n&#8217;y a aucune autre solution.</p>
<h2>En bref</h2>
<p><strong>dynamic_cast&lt;&gt;</strong> est le seul opérateur de conversion à avoir un effet &#8220;indéterminé&#8221; jusqu&#8217;à l&#8217;exécution. Son utilisation n&#8217;a de sens que lorsque confronté à du polymorphisme. Dans les cas où la conversion est assurée de réussir, on lui préfèrera <strong>static_cast&lt;&gt;</strong> plus rapide et ne nécessitant pas que les classes possèdent une méthode virtuelle.</p>
<h1>const_cast&lt;&gt;</h1>
<p><strong>const_cast&lt;&gt;</strong> permet de <strong>supprimer</strong> l&#8217;attribut <em>constant</em> ou <em>volatile</em> d&#8217;une <strong>référence</strong> ou d&#8217;un <strong>type pointé</strong>. Exemple : <strong>const char*</strong> vers <strong>char*</strong> ou <strong>volatile int</strong> vers <strong>int</strong>.</p>
<p>C&#8217;est notamment <strong>le seul</strong> opérateur de conversion à pouvoir le faire : même <strong>reinterpret_cast&lt;&gt;</strong> n&#8217;a pas ce pouvoir.</p><pre class="crayon-plain-tag">void foo()
{
char* buf = new char[16];

// L'ajout de l'attribut const ne n&eacute;cessite pas de cast
// Il est implicite
const char* cbuf = buf;

// Le retrait de l'attribut const n&eacute;cessite const_cast&amp;lt;&amp;gt;.
char* buf2 = const_cast&amp;lt;char*&amp;gt;(cbuf);
}</pre><p></p>
<h2>L&#8217;importance d&#8217;écrire un code &#8220;const-correct&#8221;</h2>
<p>Directement relié aux opérateurs de conversion, l&#8217;écriture d&#8217;un code const-correct est un autre aspect du C++ souvent mal perçu par les programmeurs C. Le C est plus ancien et le mot clé <strong>const</strong> n&#8217;y a pas toujours existé; il a été emprunté au C++ par la suite.</p>
<p>Le fait d&#8217;indiquer qu&#8217;une variable est constante est un outil puissant permettant au compilateur de nous signaler certaines de nos erreurs qui auraient autrement passé la barrière de la compilation.</p>
<p>Qui ne s&#8217;est jamais trompé dans l&#8217;ordre des arguments d&#8217;un <strong>memcpy()</strong> ?</p><pre class="crayon-plain-tag">void foo()
{
const char* source = &quot;blog.freelan.org&quot;;
char* destination = new char[16];

// Oups ! Je me suis tromp&eacute; dans l'ordre des arguments...
// ... heureusement, puisque memcpy sp&eacute;cifie que le premier param&egrave;tre est un void*
// et pas un const void*, le compilateur m'indique une erreur.
memcpy(source, destination, strnlen(source));
}</pre><p></p>
<h2>Les mots clé &#8220;const&#8221; ou &#8220;volatile&#8221; appliqués aux classes</h2>
<p>En C++, les mots clé <strong>const</strong> et <strong>volatile</strong> s&#8217;appliquent évidemment aussi aux instances de classes mais ont des sémantiques différentes :</p>
<p>Le caractère <strong>const</strong> ou <strong>volatile</strong> s&#8217;applique récursivement aux membres de l&#8217;instance.</p>
<p>Il n&#8217;est possible d&#8217;appeler une méthode d&#8217;une classe que dans les cas suivants :</p>
<ul>
<li>l&#8217;instance n&#8217;est pas <strong>const</strong>.</li>
<li>l&#8217;instance est <strong>const</strong> et la méthode est déclarée <strong>const</strong>.</li>
<li>l&#8217;instance est déclarée <strong>volatile</strong> et la méthode est déclarée <strong>volatile</strong>.</li>
<li>l&#8217;instance est déclarée <strong>const</strong> et <strong>volatile</strong> et la méthode est elle aussi déclarée <strong>const</strong> et <strong>volatile</strong>.</li>
</ul>
<h2>À propos de &#8220;volatile&#8221;</h2>
<p>Certains lecteurs peuvent être perdus à la lecture du mot clé <strong>volatile</strong> qui, il faut bien l&#8217;avouer, n&#8217;est pas utilisé très souvent. Décrire précisément le rôle de <strong>volatile</strong> mériterait un article bien à part mais je vais tout de même dire en deux mots à quoi il sert :</p>
<p>Lorsqu&#8217;une variable est déclarée <strong>volatile</strong>, le compilateur n&#8217;a pas le droit d&#8217;optimiser sa valeur (mise en cache processeur) lors de tests.</p>
<p>Ainsi sans <strong>volatile</strong> sur la variable <strong>do_loop</strong>, le code suivant :</p><pre class="crayon-plain-tag">void foo()
{
bool do_loop = true;
while (do_loop) { doSomething(); }
}</pre><p>Risquerait d&#8217;être optimisé en tant que :</p><pre class="crayon-plain-tag">void foo()
{
while (true) { doSomething(); }
}</pre><p>Ce qui est correct dans la plupart des cas&#8230; sauf si <strong>do_loop</strong> peut être modifié par un autre <strong>thread</strong>. C&#8217;est principalement dans ce genre de cas que <strong>volatile</strong> trouve son utilité.</p>
<h2>Erreurs courantes</h2>
<p>Une erreur courante concernant <strong>const_cast&lt;&gt;</strong> consiste à supposer que l&#8217;on peut <em>toujours</em> supprimer le caractère <strong>constant</strong> d&#8217;une variable.</p>
<p>Ceci est évidemment faux : on ne peut supprimer le caractère constant (respectivement volatile) d&#8217;une variable que lorsque celle-ci a été déclarée <strong>non-const</strong> (respectivement <strong>non-volatile</strong>).</p>
<p>Ainsi le code suivant a un comportement indéfini :</p><pre class="crayon-plain-tag">void foo()
{
const char* cbuf = &quot;blog.freelan.org&quot;;

// L'utilisation de const_cast&amp;lt;&amp;gt; ici a un comportement ind&eacute;fini (undefined behavior)
// car cbuf a &eacute;t&eacute; d&eacute;clar&eacute; const.
char* buf = const_cast&amp;lt;char*&amp;gt;(cbuf);
}</pre><p>Un autre cas courant est celui des variables membres qui servent à mettre en cache un résultat :</p><pre class="crayon-plain-tag">class MyClass
{
public:

MyClass() : m_value_cache(0) {}

int getValue() const
{
if (m_value_cache == 0)
const_cast&amp;lt;int&amp;amp;&amp;gt;(m_value_cache) = computeValue();

return m_value_cache;
}

private:

static int computeValue();

int m_value_cache;
};</pre><p>L&#8217;utilisation de <strong>const_cast&lt;&gt;</strong> ici est erronée : si on déclare une instance <strong>const</strong> de MyClass, m_value_cache est aussi <strong>const</strong> lors de sa définition. L&#8217;utilisation de <strong>const_cast&lt;&gt;</strong> est la même que dans l&#8217;exemple précédent et a <strong>comportement indéfini</strong>.</p>
<p>La bonne solution est d&#8217;utiliser le mot clé <strong>mutable</strong>, qui permet à une variable membre de ne pas avoir les mêmes contraintes <strong>const</strong>/<strong>volatile</strong> que son instance parente :</p><pre class="crayon-plain-tag">class MyClass
{
public:

MyClass() : m_value_cache(0) {}

int getValue() const
{
// m_value_cache est d&eacute;clar&eacute; mutable
// il peut donc changer, m&ecirc;me dans une m&eacute;thode const
if (m_value_cache == 0)
m_value_cache = computeValue();

return m_value_cache;
}

private:

static int computeValue();

// Utilisation du mot cl&eacute; &quot;mutable&quot;
mutable int m_value_cache;
};</pre><p></p>
<h2>En bref</h2>
<p><strong>const_cast&lt;&gt;</strong> est le seul opérateur de conversion à pouvoir supprimer le caractère <strong>const</strong> ou <strong>volatile</strong> d&#8217;une variable. L&#8217;utilisation de <strong>const_cast&lt;&gt;</strong> doit rester très rare : le contraire indique souvent une importante erreur de design. Son seul usage habituellement toléré est l&#8217;interfaçage avec des bibliothèques historiques qui ne sont pas <strong>const-correct</strong>.</p>
<h1>reinterpret_cast&lt;&gt;</h1>
<p>Il s&#8217;agit de l&#8217;opérateur de conversion le plus dangereux, et du plus mal utilisé. Son rôle est de dire au compilateur : &#8220;réinterprète-moi la représentation binaire de ce type en tant qu&#8217;un autre type&#8221;.</p>
<p>Il permet :</p>
<ul>
<li>De convertir <strong>n&#8217;importe quel</strong> type pointé en une autre, même lorsque ceux-ci n&#8217;ont <strong>aucun rapport</strong>. Exemple : <strong>int*</strong> vers <strong>double*</strong>.</li>
<li>De convertir un type pointé en sa <strong>représentation intégrale</strong> et vice et versa. Exemple : <strong>int*</strong> vers <strong>int</strong>.</li>
</ul>
<p>Il est à noter que ces conversions sont <strong>dépendantes de l&#8217;implémentation</strong>. En d&#8217;autres termes, le compilateur est libre de faire ce qu&#8217;il veut concernant la conversion basée sur <strong>reinterpret_cast&lt;&gt;</strong> mais ce comportement doit être constant : il ne s&#8217;agit <strong>pas</strong> de comportement indéfini; le comportement est bien défini, simplement pas par le standard C++ mais votre version du compilateur. Si vous vous basez sur cette dépendance de l&#8217;implémentation, votre code est donc <strong>non-portable</strong>.</p>
<p>La seule garantie délivrée par le standard C++ concernant <strong>reinterpret_cast&lt;&gt;</strong> est que si vous convertissez un type A en un type B, puis de nouveau en un type A, le comportement est bien défini et vous récupérez bien la valeur de départ.</p>
<p>On comprend dès lors facilement le danger que peut représenter <strong>reinterpret_cast&lt;&gt;</strong>.</p>
<p>Voici un exemple d&#8217;utilisation :</p><pre class="crayon-plain-tag">void foo()
{
int a = 5;

// Le contenu de b d&eacute;pend du compilateur utilis&eacute;
// et n'est pas d&eacute;fini par le standard
double* b = reinterpret_cast&amp;lt;double*&amp;gt;(&amp;amp;a);

// Ici, on a la garantie que *c vaudra a, c'est &agrave; dire 5.
int* c = reinterpret_cast&amp;lt;int*&amp;gt;(b);
}</pre><p></p>
<h2>Cas particuliers</h2>
<p>Le peu de garanties associées à <strong>reinterpret_cast&lt;&gt;</strong> rendent celui-ci quasiment inutile dans la plupart des cas. Il y a cependant certaines exceptions de fait qui justifient une utilisation de <strong>reinterpret_cast&lt;&gt;</strong> sans nuire à la portabilité :</p>
<p>Les conversions entre les types <strong>char*</strong> et <strong>unsigned char*</strong> bien que non spécifiées par le standard, sont en pratique supportées par tous les compilateurs et produisent le comportement attendu. Le compilateurs ont par ailleurs de plus fortes contraintes à leur égard (spécifiquement au niveau de leur représentation) pour des raisons de compatibilité ascendante avec le C.</p>
<p>Vous pouvez donc clairement supposer qu&#8217;un <strong>reinterpret_cast&lt;&gt;</strong> entre un <strong>char*</strong> et un <strong>unsigned char*</strong> sera à la fois portable et défini.</p>
<h2>Polymorphisme</h2>
<p><strong>reinterpret_cast&lt;&gt;</strong> utilisé dans le cadre d&#8217;une conversion faisant intervenir du polymorphisme a un <strong>comportement non défini</strong>. Il n&#8217;est ainsi pas correct d&#8217;effectuer un <strong>reinterpret_cast&lt;&gt;</strong> entre par exemple un <strong>Base*</strong> et un <strong>Derived*</strong>.</p>
<h2>En bref</h2>
<p><strong>reinterpret_cast&lt;&gt;</strong> est l&#8217;opérateur de conversion le plus dangereux : permettant de faire ce qu&#8217;aucun autre ne peut faire (des conversions entres des types non liés) il convient de l&#8217;utiliser avec la plus grande prudence. En pratique, on lui préfèrera <strong>static_cast&lt;&gt;</strong> qui permet d&#8217;effectuer des conversions <strong>plus sûres</strong>, y compris vers et depuis des types pointés génériques (<strong>void*</strong>). Son seul usage toléré est l&#8217;interfaçage avec du code C ancien qui utilise pour ses paramètres de &#8220;buffer&#8221; des <strong>char*</strong> ou <strong>unsigned char*</strong> au lieu des <strong>void*</strong>.</p>
<h1>Old-school : les conversions &#8220;à la C&#8221;</h1>
<p>Le C++ supporte toujours l&#8217;ancienne syntaxe concernant les conversions &#8220;à la façon C&#8221;. Cependant, le standard précise clairement l&#8217;effet d&#8217;une telle conversion :</p>
<p>Le &#8220;cast&#8221; suivant : <strong>(Type)valeur</strong> ou <strong>Type(valeur)</strong></p>
<p>Sera équivalent à, par ordre de préférence :</p>
<ol>
<li>un <strong>const_cast&lt;&gt;</strong></li>
<li>un <strong>static_cast&lt;&gt;</strong></li>
<li>un <strong>static_cast&lt;&gt;</strong> suivi d&#8217;un <strong>const_cast&lt;&gt;</strong></li>
<li>un <strong>reinterpret_cast&lt;&gt;</strong></li>
<li>un <strong>reinterpret_cast&lt;&gt;</strong> suivi d&#8217;un <strong>const_cast&lt;&gt;</strong></li>
</ol>
<p>Les bonnes pratiques indiquent souvent que l&#8217;utilisation de ce type de conversion est à bannir, principalement parce qu&#8217;il peut résulter <em>silencieusement</em> en un <strong>reinterpret_cast&lt;&gt;</strong>, qui comme nous l&#8217;avons vu, peut se révéler <strong>extrêmement dangereux</strong>. De plus, l&#8217;usage des alternatives modernes aux opérateurs de conversion permet de <em>spécifier clairement l&#8217;intention du programmeur</em> et de <em>protéger contre les erreurs involontaires</em> (comme celles que nous avons vu avec <strong>const_cast&lt;&gt;</strong>).</p>
<h2>Une autre utilité</h2>
<p>Les &#8220;casts&#8221; à la C offrent également une possibilité qui n&#8217;est permise par <strong>aucun autre</strong> opérateur de conversion : celle de convertir vers une classe de base au travers d&#8217;un <strong>héritage privé</strong>. Ce type d&#8217;héritage est très souvent critiqué et fortement déconseillé. Je ne détaillerai pas ici les conséquences et les raisons de ce type d&#8217;héritage; c&#8217;est un sujet qui mérite son propre article.</p>
<h1>Conclusion</h1>
<p>Il y a beaucoup à dire sur les opérateurs de conversion et encore plus à apprendre. Nous avons vu que bien utilisés, ils sont un outil puissant et un allié du programmeur. Protégeant contre les erreurs involontaires et révélant les erreurs de conception, ils restent pour certains dangereux et sont tout de même à utiliser avec la plus grande précaution.</p>
<p>Une bonne connaissance de ces opérateurs de conversion et de leurs limites reste indispensable à la réalisation de programmes maintenables en C++.</p>
<h1>Références</h1>
<p>Voici une série de liens (en anglais, pour la plupart) qui m&#8217;ont inspiré dans la rédaction de cet article.</p>
<ul>
<li><a href="http://stackoverflow.com/questions/28002/regular-cast-vs-static-cast-vs-dynamic-cast">http://stackoverflow.com/questions/28002/regular-cast-vs-static-cast-vs-dynamic-cast</a></li>
<li><a href="http://stackoverflow.com/questions/332030/when-should-static-cast-dynamic-cast-and-reinterpret-cast-be-used">http://stackoverflow.com/questions/332030/when-should-static-cast-dynamic-cast-and-reinterpret-cast-be-used</a></li>
<li><a href="http://stackoverflow.com/questions/4708444/is-there-a-good-way-to-convert-from-unsigned-char-to-char">http://stackoverflow.com/questions/4708444/is-there-a-good-way-to-convert-from-unsigned-char-to-char</a></li>
<li><a href="http://msdn.microsoft.com/en-us/library/5f6c9f8h%28v=VS.80%29.aspx">http://msdn.microsoft.com/en-us/library/5f6c9f8h%28v=VS.80%29.aspx</a></li>
</ul>
<p>N&#8217;hésitez pas à les consulter pour obtenir d&#8217;autres informations. Je vous recommande également de vous inscrire sur Stack Overflow qui est à mon sens le meilleur site de questions/réponses concernant la programmation : le niveau des questions et surtout des réponses y est vraiment très élevé.</p>
<p>Comme toujours bien sûr, vous pouvez également utiliser les commentaires pour obtenir des précisions sur un point ou l&#8217;autre.</p>
<p>Merci pour votre lecture !</p>
]]></content:encoded>
			<wfw:commentRss>https://blog.freelan.org/2011/01/17/les-casts-en-cpp/feed/</wfw:commentRss>
		<slash:comments>11</slash:comments>
		</item>
	</channel>
</rss>
