<?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; c++</title>
	<atom:link href="https://blog.freelan.org/tag/c/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>Développement Web en C++</title>
		<link>https://blog.freelan.org/2012/11/11/developpement-web-en-c/</link>
		<comments>https://blog.freelan.org/2012/11/11/developpement-web-en-c/#comments</comments>
		<pubDate>Sun, 11 Nov 2012 13:13:17 +0000</pubDate>
		<dc:creator><![CDATA[Damien Buhl]]></dc:creator>
				<category><![CDATA[C++]]></category>
		<category><![CDATA[Développement]]></category>
		<category><![CDATA[c++]]></category>
		<category><![CDATA[CppCms]]></category>
		<category><![CDATA[web]]></category>

		<guid isPermaLink="false">http://blog.freelan.org/?p=457</guid>
		<description><![CDATA[En attendant MeetingCpp j&#8217;ai commencé cet article, car j&#8217;étais étonné qu&#8217;il n&#8217;y ait aucune session prévue au sujet du développement web en C++. Je le finalise ce soir en rentrant de cette magnifique conférence, afin de me donner le temps de faire de mes nombreuses notes de véritables articles sur les sujets abordés et discutés. [&#8230;]]]></description>
				<content:encoded><![CDATA[<p>En attendant MeetingCpp j&#8217;ai commencé cet article, car j&#8217;étais étonné qu&#8217;il n&#8217;y ait aucune session prévue au sujet du développement web en C++. Je le finalise ce soir en rentrant de cette magnifique conférence, afin de me donner le temps de faire de mes nombreuses notes de véritables articles sur les sujets abordés et discutés.</p>
<p>En effet on ne trouve pas des masses de tutoriaux, ni de solutions pour le développement web en C++, du fait de la prédominances des langages tels que Php, Spring, Django, Ruby on Rails etc. dans ce domaine.</p>
<p>J&#8217;aimerai présenter dans cet article une des solutions existantes en tant que framework de développement web, permettant de parvenir très rapidement à de bons résultats, comme on peut y être habitué avec CodeIgniter, Zend, Django ou Ruby on Rails, mais avec un gain de performance.</p>
<h1>Pourquoi du développement web en C++ ?</h1>
<p>Avant de rentrer dans des détails d&#8217;implémentation, il est possible de se poser la question pourquoi du dévéloppement web en C++ ? En effet avec la pléthore de langages et de frameworks existants destinés à ce problème, on pourrait penser que cela n&#8217;a pas d&#8217;autre intérêt que la préférence de ce langage.</p>
<p>En réalité, il y a trois raisons qui peuvent mener à choisir de développer une application web ou un site internet en C++ :</p>
<ul>
<li>Hautes performances &amp; haute disponibilité : Benchmark <a href="http://cppcms.com/wikipp/en/page/benchmarks_all">CppCms vs Java, C#, PHP</a></li>
<li>Réduction du nombre de serveurs, ayant pour conséquence la réduction des coûts et de l&#8217;impact sur l&#8217;environnement : <a href="https://developers.facebook.com/blog/post/2010/02/02/hiphop-for-php--move-fast/">HipHop for Php: Move Fast</a></li>
<li>Ajout d&#8217;une interface web (html ou web service) pour une base C++ existante</li>
</ul>
<h1>CppCms parmi d&#8217;autres solutions</h1>
<p>J&#8217;ai eu le loisir de tester et de comparer différentes solutions (<em>i.e.</em> POCO HttpServer, CppCms, FastCgiQt, WebToolkit, QtWebApp, inetd&#8230;) et bien qu&#8217;il y ait différents avantages et inconvénients pour chaque solution, la librairie la plus flexible et la plus riche qu&#8217;il m&#8217;ait été donnée de trouver est CppCms.</p>
<p>CppCms est bel et bien un framework et non un système de gestion de contenu comme son nom souhaiterait l&#8217;indiquer, il est très semblable au framework Django en Python ou encore à CodeIgniter en PHP, n&#8217;ayant pas grand chose à envier à ces derniers en matières de fonctionnalités disponibles (<em>i.e.</em> Moteur de template statique/dynamique, systèmes de cache, json, jsonrpc, url mapping, génération/validation de forms HTML, modules multilingues/multiencodage, validation des entrées, fonctions cryptographiques/hash, gestion des sessions, gestion des vues, logging, accès aux bases de données avec cppdb, connexion avec apache/lighttpd/nginx via SCGI/FCGI ou HTTP&#8230;)</p>
<p>En addition le code et la documentation de CppCms est très claire, à tel point que <a href="http://www.boost.org/doc/libs/1_52_0/libs/locale/doc/html/index.html">Boost.Locale</a> qui provient de CppCms a été accepté très rapidement.</p>
<h1>Boost ou booster ?</h1>
<p>CppCms peut laisser un peu sceptique au premier abord, car ce dernier contient une bibliothèque : booster, qui correspond à une petite partie de boost sur lequel le framework se base en addition à des extensions. Il est donc possible d&#8217;utiliser boost ou directement booster dans le code client ou de mélanger les deux sans que cela ne pose problème. Il y a des parties de booster qui font double emploi avec boost tel que <em>booster::shared_ptr</em> qu&#8217;il m&#8217;est impossible de justifier, mais d&#8217;autres qui sont très justifiées tel que <em>booster::aio</em> et qui se différencie de <em>Boost.Asio</em> par différents points abordés plus après.</p>
<h1>CppCms : Télécharger &amp; Installer</h1>
<p>Je pars du principe que vous êtes dans un environnement unix, même si les étapes sont semblables sous windows.</p>
<ul>
<li>Récupérez le code source : <a href="http://sourceforge.net/projects/cppcms/files/">http://sourceforge.net/projects/cppcms/files/</a></li>
<li>Récupérez quelques dépendences :<br />
<pre class="crayon-plain-tag">apt-get install libpcre3-dev zlib1g-dev libgcrypt11-dev libicu-dev python</pre></li>
<li>Compilez :<br />
<pre class="crayon-plain-tag">tar xf cppcms-1.0.2.tar.bz2</pre><br />
<pre class="crayon-plain-tag">cd cppcms-1.0.2/</pre><br />
<pre class="crayon-plain-tag">mkdir build</pre><br />
<pre class="crayon-plain-tag">cd build/</pre><br />
<pre class="crayon-plain-tag">cmake ..</pre><br />
<pre class="crayon-plain-tag">make -jX</pre> (Où X correspond à votre nombre de coeurs processeur + 1)<br />
<pre class="crayon-plain-tag">sudo make install</pre></li>
</ul>
<h1>Hello World</h1>
<p>Nous allons pour ce premier article visant à présenter CppCms, implémenter l&#8217;infatigable &#8220;Hello World&#8221;.</p>
<p>Un design pattern que l&#8217;on retrouve de nos jours dans la quasi-totalité des frameworks webs est le <strong>MVC</strong>, utile dans le cas de sites webs, il permet de séparer les données ou la logique (<em>i.e.</em> le <strong>M</strong>odèle) de l&#8217;interface graphique (<em>i.e.</em>la <strong>V</strong>ue) à l&#8217;aide d&#8217;un <em>glue code</em> traitant les interactions utilisateurs (<em>i.e.</em> le <strong>C</strong>ontrôleur).</p>
<p>Bien que pour ce premier &#8220;Hello World&#8221; nous n&#8217;allons pas utiliser cette organisation, CppCms ne fait pas exception et met à disposition le concept de contrôleur à l&#8217;aide de la classe mère <em>cppcms::application</em>, le modèle avec <em>cppcms::base_content</em> et les vues à l&#8217;aide du compilateur de fichier <em>.tmpl</em> : <em>cppcms_tmpl_cc</em> qui permet de mélanger C++ et le format de sortie : JSON, HTML&#8230;</p>
<h2>Une cppcms::application synchrone simple</h2>
<p>CppCms propose différents modèles de programmation, celui auquel un développeur web connaissant PHP, Django, Ruby on Rails ou Java est habitué est le modèle synchrone usant différents threads afin de traiter les requêtes reçues. C&#8217;est très simple à comprendre et scalable verticalement comme horizontalement via les systèmes de load balancing proposés avec FCGI ou SCGI (<em>e.g.</em> lighttpd mod_fcgi permet de définir plusieurs processus de gestion des requêtes, locaux ou distants).</p>
<p>Ici nous allons utiliser le serveur web intégré à CppCms en créant un petit projet organisé de la façon suivante:</p><pre class="crayon-plain-tag">hello_world/
        config.js
        CMakeLists.txt
        src/
            CMakeLists.txt
            main.cpp
            SomeController.hpp</pre><p>hello_world/config.js :</p><pre class="crayon-plain-tag">{
	&quot;service&quot; : {
		&quot;api&quot; : &quot;http&quot;,
        &quot;port&quot; : 8080,
        &quot;worker_threads&quot; : 10
	},
	&quot;http&quot; : {
		&quot;script&quot; : &quot;/&quot;
	}
}</pre><p>hello_world/CMakeLists.txt :</p><pre class="crayon-plain-tag">cmake_minimum_required (VERSION 2.8.8)
project (hello_world)

# We want binaries be compiled at the root of build folder
set (EXECUTABLE_OUTPUT_PATH ${CMAKE_BINARY_DIR})

# We want always all warnings but no sign comparison ones. :D
set (CMAKE_CXX_FLAGS &quot;${CMAKE_CXX_FLAGS} -Wall -Wno-sign-compare&quot;)

# Find booster
find_library(LIB_BOOSTER booster)
find_path(INC_BOOSTER booster/config.h)
include_directories(${INC_BOOSTER})

# Find cppcms
find_library(LIB_CPPCMS cppcms)
find_path(INC_CPPCMS cppcms/config.h)
include_directories(${INC_CPPCMS})

add_subdirectory(src)</pre><p>Et dans le dossier src, le CMakeLists qui actuellement produit l&#8217;executable, hello_world/src/CMakeLists.txt</p><pre class="crayon-plain-tag"># Build our application
include_directories(${CMAKE_CURRENT_LIST_DIR})
file(GLOB_RECURSE HELLO_WORLD_SOURCE_FILES *.cpp)

add_executable(hello_world ${HELLO_WORLD_SOURCE_FILES})
target_link_libraries(hello_world
    ${LIB_BOOSTER}
    ${LIB_CPPCMS})</pre><p></p>
<p>Et enfin le code de notre application, hello_world/src/SomeController.hpp :</p>
<div class="cpp" style="font-size:12px;font-family:monospace;color: #006;border: 1px solid #d0d0d0;background-color: #f0f0f0">
<ol>
<li>
<div style="font: normal normal 1em/1.2em monospace;margin:0;padding:0;background:none;vertical-align:top;color: #000020"><span style="color: #339900">#ifndef SOMECONTROLLER_HPP</span></div>
</li>
<li>
<div style="font: normal normal 1em/1.2em monospace;margin:0;padding:0;background:none;vertical-align:top;color: #000020"><span style="color: #339900">#define SOMECONTROLLER_HPP</span></div>
</li>
<li>
<div style="font: normal normal 1em/1.2em monospace;margin:0;padding:0;background:none;vertical-align:top;color: #000020">&nbsp;</div>
</li>
<li>
<div style="font: normal normal 1em/1.2em monospace;margin:0;padding:0;background:none;vertical-align:top;color: #000020"><span style="color: #339900">#include &lt;cppcms/application.h&gt;</span></div>
</li>
<li>
<div style="font: normal normal 1em/1.2em monospace;margin:0;padding:0;background:none;vertical-align:top;color: #000020"><span style="color: #339900">#include &lt;cppcms/http_response.h&gt;</span></div>
</li>
<li>
<div style="font: normal normal 1em/1.2em monospace;margin:0;padding:0;background:none;vertical-align:top;color: #000020"><span style="color: #339900">#include &lt;cppcms/url_dispatcher.h&gt;</span></div>
</li>
<li>
<div style="font: normal normal 1em/1.2em monospace;margin:0;padding:0;background:none;vertical-align:top;color: #000020">&nbsp;</div>
</li>
<li>
<div style="font: normal normal 1em/1.2em monospace;margin:0;padding:0;background:none;vertical-align:top;color: #000020"><span style="color: #0000ff">class</span> SomeController <span style="color: #008080">:</span> <span style="color: #0000ff">public</span> cppcms<span style="color: #008080">::</span><span style="color: #007788">application</span> <span style="color: #008000">&#123;</span></div>
</li>
<li>
<div style="font: normal normal 1em/1.2em monospace;margin:0;padding:0;background:none;vertical-align:top;color: #000020">&nbsp; &nbsp; <span style="color: #0000ff">public</span><span style="color: #008080">:</span></div>
</li>
<li>
<div style="font: normal normal 1em/1.2em monospace;margin:0;padding:0;background:none;vertical-align:top;color: #000020">&nbsp; &nbsp; &nbsp; &nbsp; SomeController<span style="color: #008000">&#040;</span>cppcms<span style="color: #008080">::</span><span style="color: #007788">service</span> <span style="color: #000040">&amp;</span>srv<span style="color: #008000">&#041;</span> <span style="color: #008080">:</span> cppcms<span style="color: #008080">::</span><span style="color: #007788">application</span><span style="color: #008000">&#040;</span>srv<span style="color: #008000">&#041;</span> <span style="color: #008000">&#123;</span></div>
</li>
<li>
<div style="font: normal normal 1em/1.2em monospace;margin:0;padding:0;background:none;vertical-align:top;color: #000020">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; dispatcher<span style="color: #008000">&#040;</span><span style="color: #008000">&#041;</span>.<span style="color: #007788">assign</span><span style="color: #008000">&#040;</span><span style="color: #FF0000">&quot;/hello&quot;</span>,<span style="color: #000040">&amp;</span>SomeController<span style="color: #008080">::</span><span style="color: #007788">hello</span>,<span style="color: #0000dd">this</span><span style="color: #008000">&#041;</span><span style="color: #008080">;</span></div>
</li>
<li>
<div style="font: normal normal 1em/1.2em monospace;margin:0;padding:0;background:none;vertical-align:top;color: #000020">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; dispatcher<span style="color: #008000">&#040;</span><span style="color: #008000">&#041;</span>.<span style="color: #007788">assign</span><span style="color: #008000">&#040;</span><span style="color: #FF0000">&quot;/bye&quot;</span>,<span style="color: #000040">&amp;</span>SomeController<span style="color: #008080">::</span><span style="color: #007788">bye</span>,<span style="color: #0000dd">this</span><span style="color: #008000">&#041;</span><span style="color: #008080">;</span></div>
</li>
<li>
<div style="font: normal normal 1em/1.2em monospace;margin:0;padding:0;background:none;vertical-align:top;color: #000020">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; dispatcher<span style="color: #008000">&#040;</span><span style="color: #008000">&#041;</span>.<span style="color: #007788">assign</span><span style="color: #008000">&#040;</span><span style="color: #FF0000">&quot;.*&quot;</span>,<span style="color: #000040">&amp;</span>SomeController<span style="color: #008080">::</span><span style="color: #007788">redirect</span>,<span style="color: #0000dd">this</span><span style="color: #008000">&#041;</span><span style="color: #008080">;</span></div>
</li>
<li>
<div style="font: normal normal 1em/1.2em monospace;margin:0;padding:0;background:none;vertical-align:top;color: #000020">&nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #008000">&#125;</span></div>
</li>
<li>
<div style="font: normal normal 1em/1.2em monospace;margin:0;padding:0;background:none;vertical-align:top;color: #000020">&nbsp;</div>
</li>
<li>
<div style="font: normal normal 1em/1.2em monospace;margin:0;padding:0;background:none;vertical-align:top;color: #000020">&nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #0000ff">void</span> redirect<span style="color: #008000">&#040;</span><span style="color: #008000">&#041;</span> <span style="color: #008000">&#123;</span></div>
</li>
<li>
<div style="font: normal normal 1em/1.2em monospace;margin:0;padding:0;background:none;vertical-align:top;color: #000020">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; response<span style="color: #008000">&#040;</span><span style="color: #008000">&#041;</span>.<span style="color: #007788">set_redirect_header</span><span style="color: #008000">&#040;</span><span style="color: #FF0000">&quot;/hello&quot;</span><span style="color: #008000">&#041;</span><span style="color: #008080">;</span></div>
</li>
<li>
<div style="font: normal normal 1em/1.2em monospace;margin:0;padding:0;background:none;vertical-align:top;color: #000020">&nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #008000">&#125;</span></div>
</li>
<li>
<div style="font: normal normal 1em/1.2em monospace;margin:0;padding:0;background:none;vertical-align:top;color: #000020">&nbsp;</div>
</li>
<li>
<div style="font: normal normal 1em/1.2em monospace;margin:0;padding:0;background:none;vertical-align:top;color: #000020">&nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #0000ff">void</span> hello<span style="color: #008000">&#040;</span><span style="color: #008000">&#041;</span> <span style="color: #008000">&#123;</span></div>
</li>
<li>
<div style="font: normal normal 1em/1.2em monospace;margin:0;padding:0;background:none;vertical-align:top;color: #000020">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; response<span style="color: #008000">&#040;</span><span style="color: #008000">&#041;</span>.<span style="color: #007788">out</span><span style="color: #008000">&#040;</span><span style="color: #008000">&#041;</span> <span style="color: #000080">&lt;&lt;</span></div>
</li>
<li>
<div style="font: normal normal 1em/1.2em monospace;margin:0;padding:0;background:none;vertical-align:top;color: #000020">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #FF0000">&quot;&lt;html&gt;&quot;</span></div>
</li>
<li>
<div style="font: normal normal 1em/1.2em monospace;margin:0;padding:0;background:none;vertical-align:top;color: #000020">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #FF0000">&quot;&lt;body&gt;&quot;</span></div>
</li>
<li>
<div style="font: normal normal 1em/1.2em monospace;margin:0;padding:0;background:none;vertical-align:top;color: #000020">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #FF0000">&quot; &lt;h1&gt;Hello World&lt;/h1&gt;&quot;</span></div>
</li>
<li>
<div style="font: normal normal 1em/1.2em monospace;margin:0;padding:0;background:none;vertical-align:top;color: #000020">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #FF0000">&quot;&lt;/body&gt;&quot;</span></div>
</li>
<li>
<div style="font: normal normal 1em/1.2em monospace;margin:0;padding:0;background:none;vertical-align:top;color: #000020">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #FF0000">&quot;&lt;/html&gt;<span style="color: #000099;font-weight: bold">\n</span>&quot;</span><span style="color: #008080">;</span></div>
</li>
<li>
<div style="font: normal normal 1em/1.2em monospace;margin:0;padding:0;background:none;vertical-align:top;color: #000020">&nbsp;</div>
</li>
<li>
<div style="font: normal normal 1em/1.2em monospace;margin:0;padding:0;background:none;vertical-align:top;color: #000020">&nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #008000">&#125;</span></div>
</li>
<li>
<div style="font: normal normal 1em/1.2em monospace;margin:0;padding:0;background:none;vertical-align:top;color: #000020">&nbsp;</div>
</li>
<li>
<div style="font: normal normal 1em/1.2em monospace;margin:0;padding:0;background:none;vertical-align:top;color: #000020">&nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #0000ff">void</span> bye<span style="color: #008000">&#040;</span><span style="color: #008000">&#041;</span> <span style="color: #008000">&#123;</span></div>
</li>
<li>
<div style="font: normal normal 1em/1.2em monospace;margin:0;padding:0;background:none;vertical-align:top;color: #000020">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; response<span style="color: #008000">&#040;</span><span style="color: #008000">&#041;</span>.<span style="color: #007788">out</span><span style="color: #008000">&#040;</span><span style="color: #008000">&#041;</span> <span style="color: #000080">&lt;&lt;</span></div>
</li>
<li>
<div style="font: normal normal 1em/1.2em monospace;margin:0;padding:0;background:none;vertical-align:top;color: #000020">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #FF0000">&quot;&lt;html&gt;&quot;</span></div>
</li>
<li>
<div style="font: normal normal 1em/1.2em monospace;margin:0;padding:0;background:none;vertical-align:top;color: #000020">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #FF0000">&quot;&lt;body&gt;&quot;</span></div>
</li>
<li>
<div style="font: normal normal 1em/1.2em monospace;margin:0;padding:0;background:none;vertical-align:top;color: #000020">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #FF0000">&quot; &lt;h1&gt;Bye&lt;/h1&gt;&quot;</span></div>
</li>
<li>
<div style="font: normal normal 1em/1.2em monospace;margin:0;padding:0;background:none;vertical-align:top;color: #000020">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #FF0000">&quot;&lt;/body&gt;&quot;</span></div>
</li>
<li>
<div style="font: normal normal 1em/1.2em monospace;margin:0;padding:0;background:none;vertical-align:top;color: #000020">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #FF0000">&quot;&lt;/html&gt;<span style="color: #000099;font-weight: bold">\n</span>&quot;</span><span style="color: #008080">;</span></div>
</li>
<li>
<div style="font: normal normal 1em/1.2em monospace;margin:0;padding:0;background:none;vertical-align:top;color: #000020">&nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #008000">&#125;</span></div>
</li>
<li>
<div style="font: normal normal 1em/1.2em monospace;margin:0;padding:0;background:none;vertical-align:top;color: #000020"><span style="color: #008000">&#125;</span><span style="color: #008080">;</span></div>
</li>
<li>
<div style="font: normal normal 1em/1.2em monospace;margin:0;padding:0;background:none;vertical-align:top;color: #000020">&nbsp;</div>
</li>
<li>
<div style="font: normal normal 1em/1.2em monospace;margin:0;padding:0;background:none;vertical-align:top;color: #000020"><span style="color: #339900">#endif</span></div>
</li>
</ol>
</div>
<p></p>
<p>Afin de démarrer le service web et monter notre application à une url particulière il nous faut un point d&#8217;entrée, hello_world/src/main.cpp :</p>
<div class="cpp" style="font-size:12px;font-family:monospace;color: #006;border: 1px solid #d0d0d0;background-color: #f0f0f0">
<ol>
<li>
<div style="font: normal normal 1em/1.2em monospace;margin:0;padding:0;background:none;vertical-align:top"><span style="color: #339900">#include &lt;cppcms/applications_pool.h&gt;</span></div>
</li>
<li>
<div style="font: normal normal 1em/1.2em monospace;margin:0;padding:0;background:none;vertical-align:top"><span style="color: #339900">#include &lt;cppcms/service.h&gt;</span></div>
</li>
<li>
<div style="font: normal normal 1em/1.2em monospace;margin:0;padding:0;background:none;vertical-align:top"><span style="color: #339900">#include &lt;iostream&gt;</span></div>
</li>
<li>
<div style="font: normal normal 1em/1.2em monospace;margin:0;padding:0;background:none;vertical-align:top">&nbsp;</div>
</li>
<li>
<div style="font: normal normal 1em/1.2em monospace;margin:0;padding:0;background:none;vertical-align:top"><span style="color: #339900">#include &lt;SomeController.hpp&gt;</span></div>
</li>
<li>
<div style="font: normal normal 1em/1.2em monospace;margin:0;padding:0;background:none;vertical-align:top">&nbsp;</div>
</li>
<li>
<div style="font: normal normal 1em/1.2em monospace;margin:0;padding:0;background:none;vertical-align:top"><span style="color: #0000ff">int</span> main<span style="color: #008000">&#040;</span><span style="color: #0000ff">int</span> argc, <span style="color: #0000ff">char</span> <span style="color: #000040">**</span>argv<span style="color: #008000">&#041;</span> <span style="color: #008000">&#123;</span></div>
</li>
<li>
<div style="font: normal normal 1em/1.2em monospace;margin:0;padding:0;background:none;vertical-align:top">&nbsp;</div>
</li>
<li>
<div style="font: normal normal 1em/1.2em monospace;margin:0;padding:0;background:none;vertical-align:top">&nbsp; &nbsp; <span style="color: #0000ff">try</span> <span style="color: #008000">&#123;</span></div>
</li>
<li>
<div style="font: normal normal 1em/1.2em monospace;margin:0;padding:0;background:none;vertical-align:top">&nbsp; &nbsp; &nbsp; &nbsp; cppcms<span style="color: #008080">::</span><span style="color: #007788">service</span> srv<span style="color: #008000">&#040;</span>argc,argv<span style="color: #008000">&#041;</span><span style="color: #008080">;</span></div>
</li>
<li>
<div style="font: normal normal 1em/1.2em monospace;margin:0;padding:0;background:none;vertical-align:top">&nbsp; &nbsp; &nbsp; &nbsp; srv.<span style="color: #007788">applications_pool</span><span style="color: #008000">&#040;</span><span style="color: #008000">&#041;</span>.<span style="color: #007788">mount</span><span style="color: #008000">&#040;</span>cppcms<span style="color: #008080">::</span><span style="color: #007788">applications_factory</span><span style="color: #000080">&lt;</span>SomeController<span style="color: #000080">&gt;</span><span style="color: #008000">&#040;</span><span style="color: #008000">&#041;</span><span style="color: #008000">&#041;</span><span style="color: #008080">;</span></div>
</li>
<li>
<div style="font: normal normal 1em/1.2em monospace;margin:0;padding:0;background:none;vertical-align:top">&nbsp; &nbsp; &nbsp; &nbsp; srv.<span style="color: #007788">run</span><span style="color: #008000">&#040;</span><span style="color: #008000">&#041;</span><span style="color: #008080">;</span></div>
</li>
<li>
<div style="font: normal normal 1em/1.2em monospace;margin:0;padding:0;background:none;vertical-align:top">&nbsp; &nbsp; <span style="color: #008000">&#125;</span> <span style="color: #0000ff">catch</span><span style="color: #008000">&#040;</span>std<span style="color: #008080">::</span><span style="color: #007788">exception</span> <span style="color: #0000ff">const</span> <span style="color: #000040">&amp;</span>e<span style="color: #008000">&#041;</span> <span style="color: #008000">&#123;</span></div>
</li>
<li>
<div style="font: normal normal 1em/1.2em monospace;margin:0;padding:0;background:none;vertical-align:top">&nbsp; &nbsp; &nbsp; &nbsp; std<span style="color: #008080">::</span><span style="color: #0000dd">cerr</span> <span style="color: #000080">&lt;&lt;</span> e.<span style="color: #007788">what</span><span style="color: #008000">&#040;</span><span style="color: #008000">&#041;</span> <span style="color: #000080">&lt;&lt;</span> std<span style="color: #008080">::</span><span style="color: #007788">endl</span><span style="color: #008080">;</span></div>
</li>
<li>
<div style="font: normal normal 1em/1.2em monospace;margin:0;padding:0;background:none;vertical-align:top">&nbsp; &nbsp; <span style="color: #008000">&#125;</span></div>
</li>
<li>
<div style="font: normal normal 1em/1.2em monospace;margin:0;padding:0;background:none;vertical-align:top">&nbsp;</div>
</li>
<li>
<div style="font: normal normal 1em/1.2em monospace;margin:0;padding:0;background:none;vertical-align:top">&nbsp; &nbsp; <span style="color: #0000ff">return</span> <span style="color: #0000dd">0</span><span style="color: #008080">;</span></div>
</li>
<li>
<div style="font: normal normal 1em/1.2em monospace;margin:0;padding:0;background:none;vertical-align:top"><span style="color: #008000">&#125;</span></div>
</li>
</ol>
</div>
<p></p>
<h3>Configuration et mount()</h3>
<p>Ici l&#8217;instance de <em>cppcms::service</em> que nous créons au sein de la fonction <em>int main(int argc, char **argv)</em> de l&#8217;application va justement définir sa configuration en fonction du fichier config.js que l&#8217;on passe à l&#8217;application. Ce fichier respecte un format JSON avec la possibilité en plus de commenter des lignes à l&#8217;aide de <em>//</em>.</p>
<p>Il est possible de configurer à l&#8217;aide de la clé <em>&#8220;service&#8221;</em> la façon dont CppCms doit servir des requêtes. Pour cet exemple nous resterons sur la configuration présente, mais pour une mise en production un petit changement vers fcgi ou scgi sera nécessaire (<em>c.f.</em> <a href="http://cppcms.com/wikipp/en/page/cppcms_1x_tut_web_server_config">Configurer CppCms avec des serveurs webs</a>).</p>
<p>Avec cette configuration, CppCms instancie un serveur http utilisant le nombre de threads donnés par <em>worker_threads</em> pour traiter les requêtes, il utilise ainsi la fabrique : <em>cppcms::applications_factory()</em> pour créer SomeController une fois par worker thread qui traite ce type de requêtes. La méthode <em>mount()</em> permet de définir sous quel chemin racine la cppcms::application sera servie, sans second paramètre, <em>mount()</em> utilise SomeController pour répondre à n&#8217;importe quelle requête entrante.</p>
<p>L&#8217;appel un peu plus loin à <em>srv.run()</em> lance le serveur HTTP ou FCGI/SCGI selon la configuration et démarre une event loop qui distribue les différentes requêtes au threads sur la base du reactor pattern (<em>i.e.</em> Il est possible de configurer quel backend utiliser via la clé <em>&#8220;reactor&#8221;</em>, avec l&#8217;une des valeurs suivantes : <em>&#8220;default&#8221;, &#8220;select&#8221;, &#8220;poll&#8221;, &#8220;epoll&#8221;, &#8220;devpoll&#8221;, &#8220;kqueue&#8221;</em>, cependant cela n&#8217;a rien de nécessaire sur les plateformes communes parce que default choisi toujours la meilleure option pour la plateforme en cours. Vous noterez que l&#8217;option <em>iocp</em> est manquante, cela résulte dans l&#8217;utilisation de select() sur windows).</p>
<p>Plutôt que des threads il est possible d&#8217;utiliser des processus pre-forkés en spécifiant la clé : <em>worker_processes</em>. Cela a deux principaux avantages : un crash d&#8217;une des instance de <em>SomeController</em> n&#8217;affecte que l&#8217;unique requête servie par ce dernier et sous la plupart des systèmes d&#8217;exploitations, au dessus un certain nombre de thread la gestion de ces derniers devient si complexe que leur coût en performance devient exponentiel (<em>c.f.</em> <a href="http://bulk.fefe.de/scalable-networking.pdf">Scalable Network Programming, Or: The Quest For A Good Web Server (That Survives Slashdot)</a>).</p>
<p>Cependant en restant sous un nombre réaliste de threads, la rapidité sera meilleure qu&#8217;avec fork, tout dépends de combien de clients simultanés doivent pouvoir être supportés et de la longueur du traitement de chaque requête, dans cet exemple nous n&#8217;utilisons que 10 threads.</p>
<p>Pour exécuter cet exemple sur votre pc, il vous suffit de taper les commandes suivantes :</p>
<ul>
<li><pre class="crayon-plain-tag">cd hello_world/</pre></li>
<li><pre class="crayon-plain-tag">mkdir build</pre></li>
<li><pre class="crayon-plain-tag">cd build/</pre></li>
<li><pre class="crayon-plain-tag">cmake .. &amp;&amp; make</pre></li>
<li><pre class="crayon-plain-tag">./hello_world -c ../config.js</pre></li>
<li>Puis dans votre navigateur : <a href="http://127.0.0.1:8080/">http://127.0.0.1:8080/</a> et <a href="http://127.0.0.1:8080/bye">http://127.0.0.1:8080/bye</a></li>
</ul>
<h3>Assignement d&#8217;url</h3>
<p>Comme il est possible de le voir dans le fichier SomeController.hpp lors de l&#8217;instanciation de ce dernier il est possible de définir quelle méthode doit être appellée à quelle instance à l&#8217;aide du header : <em>cppcms/url_dispatcher.h</em>.</p>
<p>Ce dernier ne se limite pas à cette utilisation simpliste, en effet le premier paramètre est une expression régulière, il est ainsi possible de mapper des éléments capturés de l&#8217;url en tant que paramètre de la méthode à appeller, de telle sorte que l&#8217;on pourrait écrire pour une méthode avec la signature <em>SomeController::getArticle(string categoryName, string articleId)</em>:<br />
<pre class="crayon-plain-tag">dispatcher().assign("/getArticle/(s+)/(d+)", &amp;SomeController::getArticle,1,2);</pre><br />
<br />
Ainsi la méthode chargée de traiter la requête n&#8217;est appellé que si le format de l&#8217;url correspond. Cela n&#8217;empêche pas pour autant d&#8217;accèder directement à l&#8217;url complète ou aux paramètres GET, POST etc. à l&#8217;aide de la méthode <em>request()</em> retournant un objet de type cppcms::http::request représentant la requête.</p>
<h3>Ecriture de la réponse</h3>
<p>Comme il est possible de le voir dans les méthodes <em>redirect()</em>, <em>hello()</em> &amp; <em>bye</em> on manipule la réponse http à l&#8217;aide de la méthode <em>response()</em> qui retourne un object de type cppcms::http::response et qui possède une API très riche pour manipuler les réponses, avec <a href="http://cppcms.com/cppcms_ref/latest/classcppcms_1_1http_1_1response.html">des méthodes confortables</a>. Vous trouverez également une méthode <em>io_mode()</em> qui peut être définie sur <em>normal</em>, <em>nogzip</em>, <em>raw</em>, <em>asynchronous</em> ou <em>asynchronous_raw</em>.</p>
<h1>De nombreuses autres fonctionallités à découvrir</h1>
<p>Comme vous avez pu le constater il y a différents modes d&#8217;entrées/sorties possibles dans cppcms. Un mode très intéressant, mais peut-être le moins commun pour les personnes ne connaissant pas boost::asio est le mode asynchrone.</p>
<p>Chaque thread qui fait de l&#8217;entrée/sortie a la problèmatique de devoir attendre sur l&#8217;achèvement d&#8217;une entrée ou d&#8217;une sortie pour pouvoir continuer les traitements. On peut résoudre ce problème d&#8217;entrées/sorties bloquants les thread la majorité du temps, en délégant le transfert des données aux drivers et au matériel. Laissant ces derniers effectuer les entrées/sorties lorsque c&#8217;est actuellement le moment ou possible, et répondre ainsi à d&#8217;autres entrées/sorties avec le même thread. Cela décuple de façon très importante le nombre de requêtes pouvant être traitées avec le même nombre de threads, cela implique cependant plus de complexité et nécessite de gérer soit-même le nombre de connexions par thread, afin de rendre l&#8217;application scalable.</p>
<p>Pour ceux connaissant boost::asio il y a cependant certaines différences dans la façon avec laquelle CppCms implémente les mêmes principes avec sa librairie booster::aio. En effet <em>io_service::run()</em> ne peut être appellée par plusieurs threads à la fois et laisse tourner sa boucle d&#8217;évènement jusqu&#8217;à ce que<em> stop()</em> soit appellée et non pas lorsqu&#8217;il n&#8217;y a plus de tâches postées.</p>
<p>booster::aio à l&#8217;instar de boost::asio n&#8217;utilise pas iocp sur Windows, parce qu&#8217;il utilise toujours le Reactor pattern. Un autre point est qu&#8217;il y a moins de fonctionnalités que dans boost::asio et est orienté objet plutôt que concepts.</p>
<p>Je posterai sous peu un article expliquant cela plus en détails et présenterai dans quels cas avec CppCms les applications webs asynchrones sont intéressantes, cela ne ferait aucun sens pour notre hello_world, mais plutôt dans le cas d&#8217;implémentation de server-push ou de long-polling à l&#8217;aide de la classe : <em>cppcms::http::context</em> permettant de conserver une requête en cours sur le serveur et de la servir partiellement sans bloquer un thread par utilisateur, à l&#8217;aide de fonctions telles qu&#8217;<em>async_flush_output(handler)</em>.</p>
<h1>Conclusion</h1>
<p>Développer des applications webs en C++ n&#8217;est plus un problème et a différents avantages, je n&#8217;ai présenté ici que la base la plus simple de ce framework, mais il y a de nombreuses fonctionnalités qui méritent d&#8217;être connues comme le support de Json::Rpc, le compilateur de vues/templates, les mécanismes de cache intégrés, les classes de sérialisation/désérialisation, la gestion des sessions, des formulaires et de l&#8217;internationalisation.</p>
<p>Si vous souhaitez en savoir plus n&#8217;hésitez pas à visiter les exemples et la documentation officielle : <a href="http://cppcms.com/wikipp/en/page/cppcms_1x">CppCMS 1.x.x — Stable</a>. Je serai également ravi de vous répondre ou de vous aider.</p>
]]></content:encoded>
			<wfw:commentRss>https://blog.freelan.org/2012/11/11/developpement-web-en-c/feed/</wfw:commentRss>
		<slash:comments>4</slash:comments>
		</item>
		<item>
		<title>Boost::Python, dates et conversions</title>
		<link>https://blog.freelan.org/2011/08/09/boostpython-dates-et-conversions/</link>
		<comments>https://blog.freelan.org/2011/08/09/boostpython-dates-et-conversions/#comments</comments>
		<pubDate>Tue, 09 Aug 2011 17:54:20 +0000</pubDate>
		<dc:creator><![CDATA[Julien Kauffmann]]></dc:creator>
				<category><![CDATA[Boost]]></category>
		<category><![CDATA[C++]]></category>
		<category><![CDATA[Développement]]></category>
		<category><![CDATA[Python]]></category>
		<category><![CDATA[boost]]></category>
		<category><![CDATA[boost::posix_time]]></category>
		<category><![CDATA[boost::python]]></category>
		<category><![CDATA[c++]]></category>
		<category><![CDATA[conversion]]></category>
		<category><![CDATA[date]]></category>
		<category><![CDATA[datetime]]></category>
		<category><![CDATA[heure]]></category>
		<category><![CDATA[python]]></category>
		<category><![CDATA[time]]></category>

		<guid isPermaLink="false">http://blog.freelan.org/?p=354</guid>
		<description><![CDATA[Ceux qui ont déjà joué avec Boost::Python le savent : cette API est très complète mais malheureusement trop peu documentée. Si elle permet de rendre accessible du code C++ depuis un environnement Python avec parfois une déconcertante simplicité, certaines tâches triviales sont en revanche plus difficiles à réaliser qu'on aurait pu l'imaginer.
Si vous êtes sur cette page, c'est très probablement parce que vous aussi devez jouer avec des dates et des durées, de C++ vers Python, inversement ou bien les deux et que vous vous êtes vous aussi heurté à la complexité de Boost::Python.
L'article qui suit est le résultat de mes recherches en la matière, et la synthèse de la solution à laquelle je suis parvenu.]]></description>
				<content:encoded><![CDATA[<p>Ceux qui ont déjà joué avec Boost::Python le savent : cette API est très complète mais malheureusement trop peu documentée. Si elle permet de rendre accessible du code C++ depuis un environnement Python avec parfois une déconcertante simplicité, certaines tâches triviales sont en revanche plus difficiles à réaliser qu&#8217;on aurait pu l&#8217;imaginer.</p>
<p>Si vous êtes sur cette page, c&#8217;est très probablement parce que vous aussi devez jouer avec des dates et des durées, de C++ vers Python, inversement ou bien les deux et que vous vous êtes vous aussi heurté à la complexité de Boost::Python.</p>
<p>L&#8217;article qui suit est le résultat de mes recherches en la matière, et la synthèse de la solution à laquelle je suis parvenu.</p>
<h1>Le code de base</h1>
<p>Pour l&#8217;ensemble de l&#8217;article, nous partirons du principe que vous utilisez la classe <code>boost::posix_time::ptime</code> côté C++, et <code>datetime.datetime</code> côté Python.</p>
<p><em>Remarque : Si jamais vous utilisiez une autre classe pour vos dates (quelle soit &#8220;maison&#8221; ou issue d&#8217;une autre bibliothèque), vous devriez pouvoir adapter le principe sans trop de problèmes.</em></p>
<p>Le code minimal pour un module Python avec Boost::Python dont nous partirons est le suivant :</p>
<p></p><pre class="crayon-plain-tag">/**
* \file module.cpp
* \author Julien Kauffmann
* \brief The Python module file.
*/

#include &lt;boost/python/module.hpp&gt;

BOOST_PYTHON_MODULE(module)
{
}</pre><p></p>
<p>Rien de fou donc, pour l&#8217;instant.</p>
<p>Ajoutons une fonction qui prend en paramètre et retourne un <code>boost::posix_time::ptime</code> :</p><pre class="crayon-plain-tag">/**
 * \file module.cpp
 * \author Julien Kauffmann
 * \brief The Python module file.
 */

#include &lt;boost/python/module.hpp&gt;
#include &lt;boost/python/def.hpp&gt;

#include &lt;boost/date_time/posix_time/posix_time.hpp&gt;

boost::posix_time::ptime add_five_seconds(boost::posix_time::ptime ptime)
{
  if (!ptime.is_special())
  {
    return ptime + boost::posix_time::seconds(5);
  }

  return ptime;
}

BOOST_PYTHON_MODULE(module)
{
  boost::python::def(&quot;add_five_seconds&quot;, &amp;add_five_seconds, boost::python::args(&quot;ptime&quot;), &quot;Add five seconds to a datetime then return the result&quot;);
}</pre><p>Cette fonction ajoute bêtement 5 secondes à toute date qui lui est passée, sauf si celle-ci n&#8217;est pas une date valide.</p>
<p>Si le code actuel compile et donne une bibliothèque Python valide, l&#8217;appel de <code>add_five_seconds()</code> depuis l&#8217;interpréteur Python provoque la levée d&#8217;une exception :</p><pre class="crayon-plain-tag">Python 2.4.3 (#1, Apr 14 2011, 20:41:59)
Type &quot;copyright&quot;, &quot;credits&quot; or &quot;license&quot; for more information.

In [1]: import datetime, module

In [2]: module.add_five_seconds(datetime.datetime.today())
---------------------------------------------------------------------------
ArgumentError                             Traceback (most recent call last)

/home/ereon/workbench/pythondate/

ArgumentError: Python argument types in
    module.add_five_seconds(datetime.datetime)
did not match C++ signature:
    add_five_seconds(boost::posix_time::ptime ptime)</pre><p>En effet : à aucun moment nous n&#8217;avons indiqué à Boost::Python comment convertir une date Python en date C++, ni même que cette conversion était possible.</p>
<p>Pour que ceci fonctionne, il faut ajouter deux &#8220;converters&#8221; : un de C++ vers Python, et l&#8217;autre de Python vers C++.</p>
<h2>Conversion de C++ vers Python</h2>
<p>Si Boost::Python ne prend pas nativement en charge la conversion de date, il fournit néanmoins des outils puissants pour nous permettre d&#8217;y arriver.</p>
<p>Ajoutons le code de conversion à notre exemple précédent :</p><pre class="crayon-plain-tag">/**
 * \file module.cpp
 * \author Julien Kauffmann &lt;julien.kauffmann@freelan.org&gt;
 * \brief The Python module file.
 */

#include &lt;boost/python/module.hpp&gt;
#include &lt;boost/python/def.hpp&gt;
#include &lt;boost/python/class.hpp&gt;

#include &lt;boost/date_time/posix_time/posix_time.hpp&gt;

#include &lt;datetime.h&gt;

boost::posix_time::ptime add_five_seconds(boost::posix_time::ptime ptime)
{
  if (!ptime.is_special())
  {
    return ptime + boost::posix_time::seconds(5);
  }

  return ptime;
}

struct date_to_python_converter
{
  static PyObject* convert(boost::posix_time::ptime value)
  {
    if (value.is_not_a_date_time())
      return Py_None;

    PyDateTime_IMPORT;

    return PyDateTime_FromDateAndTime(
      static_cast&lt;int&gt;(value.date().year()),
      static_cast&lt;int&gt;(value.date().month()),
      static_cast&lt;int&gt;(value.date().day()),
      static_cast&lt;int&gt;(value.time_of_day().hours()),
      static_cast&lt;int&gt;(value.time_of_day().minutes()),
      static_cast&lt;int&gt;(value.time_of_day().seconds()),
      static_cast&lt;int&gt;(value.time_of_day().total_microseconds() - value.time_of_day().total_seconds() * 1000000L)
      );
  }
};

BOOST_PYTHON_MODULE(module)
{
  boost::python::to_python_converter&lt;boost::posix_time::ptime, date_to_python_converter&gt;();

  boost::python::def(&quot;add_five_seconds&quot;, &amp;add_five_seconds, boost::python::args(&quot;ptime&quot;), &quot;Add five seconds to a datetime then return the result&quot;);
}</pre><p></p>
<h3>Analyse</h3>
<p>Regardons ligne par ligne les changements apportés.</p><pre class="crayon-plain-tag">#include &lt;boost/python/class.hpp&gt;
#include &lt;datetime.h&gt;</pre><p>Le premier include est nécessaire pour utiliser <code>boost::python::to_python_converter</code>; le second pour rendre disponibles les types Python natifs, tels que <code>PyObject</code> ou <code>PyDateTime</code>.</p><pre class="crayon-plain-tag">struct date_to_python_converter
{
  static PyObject* convert(boost::posix_time::ptime value)
  {
    if (value.is_not_a_date_time())
      return Py_None;

    PyDateTime_IMPORT;

    return PyDateTime_FromDateAndTime(
      static_cast&lt;int&gt;(value.date().year()),
      static_cast&lt;int&gt;(value.date().month()),
      static_cast&lt;int&gt;(value.date().day()),
      static_cast&lt;int&gt;(value.time_of_day().hours()),
      static_cast&lt;int&gt;(value.time_of_day().minutes()),
      static_cast&lt;int&gt;(value.time_of_day().seconds()),
      static_cast&lt;int&gt;(value.time_of_day().total_microseconds() - value.time_of_day().total_seconds() * 1000000L)
      );
  }
};</pre><p>Ici nous déclarons un &#8220;converter&#8221;. Au sens de Boost::Python, un &#8220;converter&#8221; est une simple structure ou classe qui contient une méthode statique nommée <code>convert()</code> qui prend un paramètre le type natif C++ à convertir, et qui retourne un <code>PyObject*</code>.</p>
<p>Dans le cas où notre date n&#8217;est pas une date valide, nous choisissons ici de renvoyer <code>None</code>. Libre à vous de modifier ce comportement pour satisfaire vos propres besoins.</p>
<p>Remarque : La valeur retournée <strong>doit</strong> avoir un compteur de référence <strong>strictement positif</strong>.</p><pre class="crayon-plain-tag">boost::python::to_python_converter&lt;boost::posix_time::ptime, date_to_python_converter&gt;();</pre><p>Enfin nous déclarons notre &#8220;converter&#8221; en spécifiant le type natif et la structure/classe à utiliser pour la conversion.</p>
<p>À partir de ce moment là, notre module Python sera capable de convertir implicitement tout <code>boost::posix_time::ptime</code> en <code>datetime.datetime</code> Python.</p>
<h2>Conversion de Python vers C++</h2>
<p>La conversion dans l&#8217;autre sens demande un peu plus de travail :</p><pre class="crayon-plain-tag">/**
 * \file module.cpp
 * \author Julien Kauffmann &lt;julien.kauffmann@freelan.org&gt;
 * \brief The Python module file.
 */

#include &lt;boost/python/module.hpp&gt;
#include &lt;boost/python/def.hpp&gt;
#include &lt;boost/python/class.hpp&gt;

#include &lt;boost/date_time/posix_time/posix_time.hpp&gt;

#include &lt;datetime.h&gt;

boost::posix_time::ptime add_five_seconds(boost::posix_time::ptime ptime)
{
  if (!ptime.is_special())
  {
    return ptime + boost::posix_time::seconds(5);
  }

  return ptime;
}

struct date_to_python_converter
{
  static PyObject* convert(boost::posix_time::ptime value)
  {
    if (value.is_not_a_date_time())
      return Py_None;

    PyDateTime_IMPORT;

    return PyDateTime_FromDateAndTime(
        static_cast&lt;int&gt;(value.date().year()),
        static_cast&lt;int&gt;(value.date().month()),
        static_cast&lt;int&gt;(value.date().day()),
        static_cast&lt;int&gt;(value.time_of_day().hours()),
        static_cast&lt;int&gt;(value.time_of_day().minutes()),
        static_cast&lt;int&gt;(value.time_of_day().seconds()),
        static_cast&lt;int&gt;(value.time_of_day().total_microseconds() - value.time_of_day().total_seconds() * 1000000L)
        );
  }
};

struct date_from_python_converter
{
  static void* is_convertible(PyObject* obj_ptr)
  {
    assert(obj_ptr);

    if (obj_ptr == Py_None)
      return obj_ptr;

    PyDateTime_IMPORT;

    if (PyDateTime_Check(obj_ptr))
      return obj_ptr;

    return NULL;
  }

  static void convert(PyObject* obj_ptr, boost::python::converter::rvalue_from_python_stage1_data* data)
  {
    assert(obj_ptr);

    void* const storage = reinterpret_cast&lt;boost::python::converter::rvalue_from_python_storage&lt;boost::posix_time::ptime&gt;*&gt;(data)-&gt;storage.bytes;

    if (obj_ptr == Py_None)
    {
      new (storage) boost::posix_time::ptime();
    } else
    {
      PyDateTime_IMPORT;
      PyDateTime_DateTime* dt_ptr = reinterpret_cast&lt;PyDateTime_DateTime*&gt;(obj_ptr);

      const int year = PyDateTime_GET_YEAR(dt_ptr);
      const int month = PyDateTime_GET_MONTH(dt_ptr);
      const int day = PyDateTime_GET_DAY(dt_ptr);
      const int hour  = PyDateTime_DATE_GET_HOUR(dt_ptr);
      const int minute  = PyDateTime_DATE_GET_MINUTE(dt_ptr);
      const int second = PyDateTime_DATE_GET_SECOND(dt_ptr);
      const int microsecond = PyDateTime_DATE_GET_MICROSECOND(dt_ptr);

      new (storage) boost::posix_time::ptime(boost::gregorian::date(year, month, day), boost::posix_time::time_duration(hour, minute, second, 0) + boost::posix_time::microseconds(microsecond));
    }

    data-&gt;convertible = storage;
  }
};

BOOST_PYTHON_MODULE(module)
{
  boost::python::to_python_converter&lt;boost::posix_time::ptime, date_to_python_converter&gt;();

  boost::python::converter::registry::push_back(&amp;date_from_python_converter::is_convertible, &amp;date_from_python_converter::convert, boost::python::type_id&lt;boost::posix_time::ptime&gt;());  

  boost::python::def(&quot;add_five_seconds&quot;, &amp;add_five_seconds, boost::python::args(&quot;ptime&quot;), &quot;Add five seconds to a datetime then return the result&quot;);
}</pre><p></p>
<h3>Analyse</h3>
<p>Regardons encore une fois, ligne par ligne les modifications apportées :</p><pre class="crayon-plain-tag">struct date_from_python_converter</pre><p>Nous ajoutons une structure qui va contenir les routines de conversions. Contrairement à tout à l&#8217;heure, et comme nous le verrons plus tard, ceci n&#8217;est pas indispensable. Pour effectuer des conversions de Python vers C++, Boost::Python a juste besoin de deux fonctions. Que celles-ci soient statiques au sein d&#8217;une classe ou libres n&#8217;a aucune incidence.</p><pre class="crayon-plain-tag">static void* is_convertible(PyObject* obj_ptr)
  {
    assert(obj_ptr);

    if (obj_ptr == Py_None)
      return obj_ptr;

    PyDateTime_IMPORT;

    if (PyDateTime_Check(obj_ptr))
      return obj_ptr;

    return NULL;
  }</pre><p>La fonction <code>is_convertible()</code> sera utilisée par Boost::Python pour déterminer si l&#8217;instance Python à convertir peut l&#8217;être.</p>
<p>Dans notre cas nous acceptons tout d&#8217;abord <code>None</code> comme valeur &#8220;valide&#8221; pour respecter la symétrie, puis nous testons si l&#8217;instance est de type <code>datetime.datetime</code> grâce à la fonction <code>PyDateTime_Check()</code>.</p>
<p>En cas de succès, nous renvoyons la valeur passée en paramètre telle quelle. En cas d&#8217;erreur, nous renvoyons <code>NULL</code>.</p><pre class="crayon-plain-tag">static void convert(PyObject* obj_ptr, boost::python::converter::rvalue_from_python_stage1_data* data)
  {
    assert(obj_ptr);

    void* const storage = reinterpret_cast&lt;boost::python::converter::rvalue_from_python_storage&lt;boost::posix_time::ptime&gt;*&gt;(data)-&gt;storage.bytes;

    if (obj_ptr == Py_None)
    {
      new (storage) boost::posix_time::ptime();
    } else
    {
      PyDateTime_IMPORT;
      PyDateTime_DateTime* dt_ptr = reinterpret_cast&lt;PyDateTime_DateTime*&gt;(obj_ptr);

      const int year = PyDateTime_GET_YEAR(dt_ptr);
      const int month = PyDateTime_GET_MONTH(dt_ptr);
      const int day = PyDateTime_GET_DAY(dt_ptr);
      const int hour  = PyDateTime_DATE_GET_HOUR(dt_ptr);
      const int minute  = PyDateTime_DATE_GET_MINUTE(dt_ptr);
      const int second = PyDateTime_DATE_GET_SECOND(dt_ptr);
      const int microsecond = PyDateTime_DATE_GET_MICROSECOND(dt_ptr);

      new (storage) boost::posix_time::ptime(boost::gregorian::date(year, month, day), boost::posix_time::time_duration(hour, minute, second, 0) + boost::posix_time::microseconds(microsecond));
    }

    data-&gt;convertible = storage;
  }</pre><p>C&#8217;est ici que se passe le gros du travail : lorsque cette fonction est appelée, cela signifie que l&#8217;instance <code>obj_ptr</code> a passé l&#8217;appel à <code>is_convertible()</code> et est prête à être convertie.</p>
<p>Le paramètre <code>data</code> lui contient entre autres l&#8217;adresse de la zone mémoire où nous devons instancier notre résultat de conversion. Notez que pour ce faire, nous utilisons le &#8220;placement new&#8221; qui permet de construire une instance à un emplacement mémoire donné. Le <code>delete</code> correspondant sera automatiquement appelé par Boost::Python au besoin.</p>
<p>Pour finir, nous renseignons le champ <code>convertible</code> du paramètre <code>data</code> pour y indiquer où nous avons alloué notre résultat.</p><pre class="crayon-plain-tag">boost::python::converter::registry::push_back(&amp;date_from_python_converter::is_convertible, &amp;date_from_python_converter::convert, boost::python::type_id&lt;boost::posix_time::ptime&gt;());</pre><p>Comme auparavant, la dernière étape consiste à enregistrer le &#8220;converter&#8221; pour le faire connaître de Boost::python.<br />
On remarque ici que comme énoncé précédemment, l&#8217;appel prend en paramètre deux fonctions qui n&#8217;ont pas nécessairement besoin de faire partie d&#8217;une classe ou d&#8217;une structure.</p>
<h1>Résultat</h1>
<p>Compilez le code ci-dessus (voir le script <em>SConstruct</em> en annexe), puis chargez votre module au sein de l&#8217;interpreteur Python :</p><pre class="crayon-plain-tag">Python 2.4.3 (#1, Apr 14 2011, 20:41:59)
Type &quot;copyright&quot;, &quot;credits&quot; or &quot;license&quot; for more information.

In [1]: import datetime, module

In [2]: d = datetime.datetime.now()

In [3]: print d
2011-08-09 11:30:43.239460

In [4]: print module.add_five_seconds(d)
2011-08-09 11:30:48.239460</pre><p>Ça y est ! La conversion <code>boost::posix_time::ptime</code> &lt;=&gt; <code>datetime.datetime</code> fonctionne parfaitement. <img src="https://blog.freelan.org/wp-includes/images/smilies/icon_smile.gif" alt=":)" class="wp-smiley" /></p>
<h1>Conclusion</h1>
<p>Boost::Python est définitivement une bibliothèque très puissante. On peut certes regretter la qualité de sa documentation, mais fort heureusement les ressources à son sujet sur l&#8217;Internet ne manquent pas. Son extensibilité la rend utilisable dans toutes les situations et facilite grandement la vie du développeur.</p>
<p>J&#8217;espère que cet article vous aura aidé et/ou donné envie de découvrir/utiliser Boost::Python. Comme toujours, n&#8217;hésitez pas à me signaler toute coquille, erreur ou optimisation qui m&#8217;aurait échappé.</p>
<h1>Annexe</h1>
<p>Voici le script SConstruct que j&#8217;ai utilisé pour la compilation :</p><pre class="crayon-plain-tag">import os

env = Environment(ENV = os.environ.copy())
env['CPPPATH'] = ['/usr/include/python2.4']

module = env.SharedLibrary(source = Glob('*.cpp'), target = 'python/module.so', SHLIBPREFIX='', LIBS = ['boost_python', 'python2.4'])</pre><p></p>
<h1>Sources</h1>
<p>Ces pages m&#8217;ont été très utiles lors de la rédaction de cet article :</p>
<ul>
<li>L&#8217;API datetime sur <a href="http://docs.python.org/c-api/datetime.htmlhttp://docs.python.org/c-api/datetime.html">python.org</a> (en Anglais);</li>
<li>l&#8217;API Boost::Posix Time sur <a href="http://www.boost.org/doc/libs/1_47_0/doc/html/date_time/posix_time.html">boost.org</a> (en Anglais);</li>
<li>l&#8217;API de Boost::Python sur <a href="http://www.boost.org/doc/libs/1_46_0/libs/python/doc/index.html">boost.org</a> (en Anglais);</li>
<li>cet <a href="http://misspent.wordpress.com/2009/09/27/how-to-write-boost-python-converters/">article</a> de misspent (en Anglais).</li>
</ul>
]]></content:encoded>
			<wfw:commentRss>https://blog.freelan.org/2011/08/09/boostpython-dates-et-conversions/feed/</wfw:commentRss>
		<slash:comments>4</slash:comments>
		</item>
		<item>
		<title>L&#8217;héritage en C++</title>
		<link>https://blog.freelan.org/2011/03/08/lheritage-en-c/</link>
		<comments>https://blog.freelan.org/2011/03/08/lheritage-en-c/#comments</comments>
		<pubDate>Tue, 08 Mar 2011 17:40:01 +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[conversion]]></category>
		<category><![CDATA[héritage]]></category>
		<category><![CDATA[inheritance]]></category>
		<category><![CDATA[privé]]></category>
		<category><![CDATA[protégé]]></category>
		<category><![CDATA[public]]></category>
		<category><![CDATA[virtuel]]></category>

		<guid isPermaLink="false">http://blog.freelan.org/?p=327</guid>
		<description><![CDATA[Tous les langages modernes offrent aujourd'hui, par leur nature orientée objet, un moyen puissant de réutiliser du code existant : l'héritage. La plupart des programmeurs sont bien entendu déjà familiers avec le principe de dériver d'une classe pour en étendre les possibilités (ou les restreindre) dans une classe fille.
Cependant, dans ce domaine, C++ va un peu plus loin que les autres langages en proposant différentes notions d'héritage public, privé, protégé et virtuel. Nous allons tenter, dans cet article, d'expliquer en détails leurs rôles et en quoi elles peuvent se rendre utiles.]]></description>
				<content:encoded><![CDATA[<p>Tous les langages modernes offrent aujourd&#8217;hui, par leur nature orientée objet, un moyen puissant de concevoir des hiérarchies : l&#8217;héritage. La plupart des programmeurs sont bien entendu déjà familiers avec le principe de dériver d&#8217;une classe pour en étendre les possibilités (ou les restreindre) dans une classe fille. Cependant, dans ce domaine, C++ va un peu plus loin que les autres langages en proposant différentes notions d&#8217;héritage public, privé, protégé et virtuel. Nous allons tenter, dans cet article, d&#8217;expliquer en détails leurs rôles et en quoi elles peuvent se rendre utiles.</p>
<h1>Un cas classique</h1>
<p></p><pre class="crayon-plain-tag">class Base
{
  public:
    int x() const { return m_x; }
  protected:
    void set_x(int value) { m_x = value; }
  private:
    int m_x;
};

class Derived : public Base
{
  public:
    void foo() { set_x(5); }
};</pre><p>Ce code n&#8217;évoque probablement rien de nouveau pour la plupart d&#8217;entre vous : nous déclarons une classe <code>Base</code>, qui possède une méthode <em>publique</em>, une méthode <em>protégée</em> et une variable membre <em>privée</em>. Nous déclarons également une classe <code>Derived</code>, qui <em>dérive</em> de <code>Base</code> au travers d&#8217;un <strong>héritage public</strong>. Ce principe d&#8217;héritage public est généralement simple à comprendre et il est présent dans pratiquement tous les langages objets : lorsque <code>Derived</code> dérive de <code>Base</code> au travers d&#8217;un <em>héritage public</em>, on dit aussi que <code>Derived</code> &#8220;<em>est un&#8221;</em> <code>Base</code>. Toute instance de <code>Derived</code> peut être considérée comme une instance de <code>Base</code>. Comme nous l&#8217;avions vu, <a href="http://blog.freelan.org/2011/01/17/les-casts-en-cpp/">dans un article précédent</a>, il est également possible de tester si une instance de <code>Base</code> est une instance de <code>Derived</code> grâce à un <code>dynamic_cast<></code>. De façon résumée, un héritage publique offre les garanties suivantes :</p>
<ul>
<li>Toutes les membres (variables et méthodes) <strong>publics</strong> dans la classe de base le sont aussi dans la classe dérivée.</li>
<li>Toutes les membres <strong>protégés</strong> dans la classe de base le sont aussi dans la classe dérivée.</li>
<li>Les membres <strong>privés</strong> de la classe de base ne sont pas accessibles à la classe dérivée.</li>
<li>On peut convertir <em>implicitement</em> un pointeur (respectivement une référence) sur la classe dérivée vers un pointeur (respectivement une référence) sur la classe de base.</li>
<li>On peut convertir <em>explicitement</em> un pointeur (respectivement une référence) sur la classe de base vers un pointeur (respectivement une référence) sur la classe dérivée.</li>
</ul>
<p>Ainsi dans notre exemple, <code>Derived</code> peut, dans sa méthode <code>foo()</code> (et <strong>indépendamment de la visibilité de cette méthode</strong>), appeler la méthode protégée de son parent, <code>set_x()</code>. Elle ne peut pas en revanche, directement accéder à <code>m_x</code> qui est dans une <strong>section privée</strong> de la classe de base.</p>
<h2>Le rôle de l&#8217;héritage public</h2>
<p>Une concept erroné va généralement de pair avec l&#8217;utilisation de l&#8217;héritage public : il consiste à dire que ce type d&#8217;héritage est utilisé principalement pour favoriser la <strong>réutilisation de code</strong>. Ceci n&#8217;est pas (ou ne devrait pas) être la raison : en C++, il existe beaucoup de moyens de réutiliser son code, la façon la plus efficace étant la <strong>composition</strong>. Le fait de d&#8217;utiliser un héritage public <em>doit</em> être une <strong>décision fonctionnelle</strong>, et pas une <strong>décision technique</strong> : ainsi, la classe <code>Table</code> dérive de la classe <code>Meuble</code> parce qu&#8217;une table <em>&#8220;est un&#8221;</em> meuble, et pas parce qu&#8217;en faisant ainsi on évite de retaper du code. L&#8217;héritage (public ou non) s&#8217;il apporte quelque-chose, c&#8217;est principalement de la <strong>flexibilité</strong>.</p>
<h2>Bonnes pratiques</h2>
<p>Certains auront peut être pensé la chose suivante : &#8220;La méthode <code>set_x()</code> ne sert à rien. Autant déclarer <code>m_x</code> <em>protégé</em> directement : il y aura moins de code&#8221;. Si cette remarque part surement d&#8217;une bonne intention (après tout, avoir moins de code est en général une très bonne idée), elle risque ici d&#8217;avoir des conséquences fâcheuses : En procédant de la même façon que dans l&#8217;exemple, nous ajoutons certes une méthode, mais nous réduisons également le <strong>couplage</strong>. En optant pour la solution &#8220;simplifiée&#8221;, si pour une raison ou pour un autre, je suis amené à modifier l&#8217;implémentation de <code>Base</code> et à renommer par exemple <code>m_x</code> en <code>m_first_x</code>, je devrais alors modifier non seulement tout le code de <code>Base</code> mais aussi tout le code de <code>Derived</code> (puisque nous y faisons référence à <code>m_x</code> directement). Le fait d&#8217;ajouter une méthode protégée à <code>Base</code> permet de figer son interface &#8220;publique&#8221; et réduit donc drastiquement le couplage. Il en résulte un code bien plus maintenable. En règle générale, on retiendra que les variables au sein d&#8217;une classe seront toujours soit <strong>publiques</strong>, soit <strong>privées</strong>, mais très rarement <strong>protégées</strong>. Et si dans un cas particulier vous sentez avoir vraiment besoin d&#8217;un accès à un membre privé, préférez la directive <code>friend</code> qui augmentera bien moins le couplage.</p>
<p>Cette règle n&#8217;est évidemment pas absolue et vous risquez de rencontrer un scénario où déclarer une variable membre <strong>protégée</strong> est la bonne chose à faire. Cependant, ça ne devrait logiquement pas être votre premier réflexe.</p>
<h1>L&#8217;héritage privé : une alternative à la composition</h1>
<p>Qui n&#8217;a jamais écrit par erreur, au cours d&#8217;une soirée (nuit ?) un peu trop longue quelque-chose de ce genre :</p><pre class="crayon-plain-tag">class Derived : Base
{
};</pre><p>Il en résulte en général de longues minutes très agaçantes où l&#8217;on tente de comprendre pourquoi le compilateur refuse systématiquement d&#8217;utiliser les variables de la classe parente. La raison est plutôt simple : en l&#8217;absence d&#8217;un attribut de visibilité, l&#8217;héritage par défaut en C++ est <strong>privé</strong>. Le code précédent est donc équivalent à :</p><pre class="crayon-plain-tag">class Derived : private Base
{
};</pre><p>Voilà une bonne occasion d&#8217;expliquer à quoi sert ce type d&#8217;héritage. L&#8217;héritage privé offre les garanties suivantes :</p>
<ul>
<li>Tous les membres <strong>publics</strong> dans la classe de base sont <strong>privés</strong> dans la classe dérivée.</li>
<li>Tous les membres <strong>protégés</strong> dans la classe de base sont <strong>privés</strong> dans la classe dérivée.</li>
<li>Les membres <strong>privés</strong> de la classe de base ne sont pas accessibles à la classe dérivée.</li>
<li>La classe dérivée peut redéfinir les méthodes <strong>virtuelles</strong> de la classe de base.</li>
<li>Toutes les méthodes de la classe dérivée peuvent convertir un pointeur (respectivement une référence) sur <code>Derived</code> en pointeur (respectivement une référence) sur <code>Base</code>. <strong>Ceci n&#8217;est en revanche normalement pas possible en dehors de la classe dérivée.</strong> (Voir tout de même la remarque).</li>
</ul>
<p>Là où un héritage <em>public</em> traduit une relation de type &#8220;est un&#8221;, un héritage <em>privé</em> lui traduit une relation de type &#8220;est implémenté en tant que&#8221;. En pratique, un héritage privé est comparable à une composition de type 1-vers-1. Prenons un exemple plus parlant :</p><pre class="crayon-plain-tag">class Engine
{
  public:
    void start();
};

class Car : private Engine
{
  public:
    using Engine::start;
};</pre><p>Nous avons déclaré une classe <code>Engine</code> (moteur) et <code>Car</code> (voiture) qui en dérive de façon privée. Dans la déclaration de <code>Car</code>, nous indiquons, au sein d&#8217;une section publique et grâce au mot clé <code>using</code>, que nous <em>utilisons</em> la méthode <code>start()</code> de la classe parente. Celle-ci devient donc publique pour la classe fille et en dehors. Dans ce cas, on voit bien qu&#8217;un héritage public n&#8217;aurait aucun sens puisqu&#8217;une voiture &#8220;n&#8217;est pas&#8221; un moteur, elle &#8220;possède un moteur&#8221;. Certains se demandent peut être si une composition n&#8217;est pas plus indiquée dans ce cas et la réponse n&#8217;est pas évidente :</p>
<ul>
<li>En règle générale, oui, préférez la composition à l&#8217;héritage&#8230;</li>
<li>&#8230; mais dans le cas que nous présentons ici, la composition est assez &#8220;forte&#8221; : une voiture ne peut toujours avoir <strong>qu&#8217;un seul</strong> moteur, et le fait de démarrer la voiture <em>revient à</em> démarrer le moteur.</li>
</ul>
<p>Les cas où l&#8217;on peut légitimement accepter un héritage privé en lieu et place d&#8217;une composition restent très limités. Et personne ne vous blâmera si même dans ce cas, vous optez pour la composition. L&#8217;héritage privé est surtout une facilité du langage pour éviter au programmeur de saisir du code inutile : dans notre exemple, en utilisant une composition, on aurait obtenu quelque-chose de ce genre :</p><pre class="crayon-plain-tag">class Engine
{
  public:
    void start();
};

class Car
{
  public:
    void start() { m_engine.start(); }
  private:
    Engine m_engine;
};</pre><p>Pas vraiment plus difficile à comprendre, mais un peu plus long à taper. Et si ce n&#8217;était pas une mais vingt méthodes de <code>Engine</code> qu&#8217;il avait fallu &#8220;transporter&#8221; dans l&#8217;interface publique de <code>Car</code>, je vous laisse imaginer le temps perdu à saisir toutes les méthodes triviales qui ne font qu&#8217;appeler la &#8220;vraie&#8221; méthode du sous-objet. Dans tous les cas, notez qu&#8217;en t&#8217;en qu&#8217;utilisateur de la classe <code>Car</code>, vous ne <strong>devez jamais</strong> prendre en compte la présence d&#8217;un héritage privé dans sa définition : cet héritage est privé et <strong>relève de l&#8217;implémentation</strong> : l&#8217;auteur de la classe peut à tout moment décider de réécrire sa classe pour utiliser une composition classique, ou encore de redéfinir à la main chacune des méthodes, sans vous en notifier !</p>
<h2>Remarque</h2>
<p>Un lecteur assidu aura peut être remarqué une contradiction avec <a href="http://blog.freelan.org/2011/01/17/les-casts-en-cpp/">un de mes articles précédents</a> : en effet, si j&#8217;ai indiqué un peu plus haut qu&#8217;il n&#8217;était pas possible de convertir un <code>Car*</code> en <code>Engine*</code> en dehors des méthodes de <code>Car</code>, ce n&#8217;était pas tout à fait vrai : cela est possible en C++, par l’intermédiaire d&#8217;une &#8220;conversion à la façon C&#8221;. Évidemment, si on respecte la clause énoncée précédemment de ne <strong>jamais</strong> se baser sur le détail d&#8217;implémentation que représente l&#8217;<em>héritage privé</em>, il ne s&#8217;agit en fait que d&#8217;un argument supplémentaire contre l&#8217;utilisation de ce type de conversion. En un mot : faites-le une fois pour vous amuser, puis plus jamais !</p>
<h2>À propos du mot clé using</h2>
<p>S&#8217;il est très courant de rencontrer le mot clé <code>using</code> lors de l&#8217;utilisation d&#8217;héritage privé, il est également possible de l&#8217;utiliser lors d&#8217;un héritage &#8220;classique&#8221; public :</p><pre class="crayon-plain-tag">class Base
{
  public:
    int x() const { return m_x; }
  protected:
    void set_x(int value) { m_x = value; }
  private:
    int m_x;
};

class Derived : public Base
{
  public:
    using Base::set_x;
};</pre><p>Ici, nous avons <strong>augmenté la visibilité</strong> de la méthode <code>set_x()</code> en la rendant <strong>publique</strong> dans la classe dérivée, alors qu&#8217;elle n&#8217;était que <strong>protégée</strong> dans la classe de base. Bien que peu courante, cette syntaxe n&#8217;en demeure pas moins tout à fait correcte.</p>
<h1>L&#8217;héritage protégé</h1>
<p>L&#8217;héritage <strong>protégé</strong> ressemble énormément à l&#8217;héritage <strong>privé</strong>. En fait, sa seule différence est la suivante :</p>
<ul>
<li>Tout membre <strong>public</strong> ou <strong>protégé</strong> hérité au travers d&#8217;un <strong>héritage protégé</strong> est également accessible de façon <strong>protégée</strong> aux <strong>classes filles</strong> de la classe dérivée.</li>
</ul>
<p>Ce qui se traduit par :</p><pre class="crayon-plain-tag">class Engine
{
  protected:
    void start() {};
};

class Car : protected Engine {};

class Robot : protected Car
{
  public:
    using Engine::start;
};</pre><p>Ici <code>Robot</code> peut accéder à la méthode protégée de <code>Engine</code> parce que <code>Car</code> hérite de <code>Engine</code> au travers d&#8217;un <strong>héritage protégé</strong>. On voit que si l&#8217;héritage privé peut s&#8217;avérer utile dans certains cas, l&#8217;héritage protégé lui a un intérêt beaucoup plus limité, car le fait de pouvoir accéder aux méthodes de sa classe <em>grand-parente</em> ne fait qu&#8217;<strong>augmenter le couplage</strong>.</p>
<p>Je n&#8217;ai encore jamais rencontré ou eu besoin d&#8217;un héritage protégé depuis que je développe en C++.</p>
<h1>L&#8217;héritage virtuel</h1>
<p>Pour expliquer en quoi consiste l&#8217;héritage virtuel, replaçons avant tout dans le contexte quelques lieux communs :</p>
<h2>L&#8217;héritage multiple</h2>
<p>C++ est l&#8217;un des rares langages à autoriser l&#8217;héritage multiple là où les autres langages préfèrent imposer la notion d&#8217;interfaces. La légitimité de l&#8217;une ou de l&#8217;autre de ces techniques est un sujet à part entière et sort du cadre de cet article. Si vous vous intéressez à ce débat, il existe sur l&#8217;Internet <a href="http://www.artima.com/intv/abcs.html">bien des discussions</a> à ce sujet.</p>
<h3>La minute &#8220;rebelle&#8221;</h3>
<p>Vous avez certainement déjà entendu quelqu&#8217;un dire une chose du genre : &#8220;L&#8217;héritage multiple c&#8217;est toujours une hérésie, ça n&#8217;aurait jamais du exister ! Je n&#8217;ai jamais réussi à en faire quoi que ce soit d&#8217;utile.&#8221;</p>
<p>Face à ce genre de remarque simpliste, j&#8217;ai tendence à avoir la même réaction que <a title="www.parashift.com/" href="http://www.parashift.com/" target="_blank">Marshall Cline</a> : les gens qui vous disent ça ne <strong>connaissent</strong> à priori <strong>pas votre problème</strong> ou vos besoins, et pourtant ils prétendent y répondre : comment le pourraient-ils ? Comment peuvent-ils savoir que dans <strong>votre situation</strong>, l&#8217;héritage multiple n&#8217;est pas la meilleure solution ? Si vous rencontrez ce genre de personnes, soyez prudents : le manque d&#8217;ouverture d&#8217;esprit et de réflexion fait en général de bien piètres programmeurs. Une phrase que j&#8217;aime bien citer dans cette situation est celle-ci : &#8220;Toutes les phrases qui dénoncent un principe de façon absolue et générale sont absolument et généralement fausses&#8221;. Si l&#8217;héritage multiple semble être la solution à votre problème, n&#8217;hésitez pas à l&#8217;utiliser.</p>
<p>Dans tous les cas, réfléchissez toujours bien à ce que vous faites : si l&#8217;héritage multiple est tant victime d&#8217;à priori négatifs, c&#8217;est qu&#8217;il est parfois difficile de comprendre son utilisation.</p>
<h2>La démonstration par l&#8217;exemple</h2>
<p>Pour illustrer les notions d&#8217;héritage multiple et virtuel, créons tout d&#8217;abord une hiérarchie de classes :</p>
<div id="attachment_341" style="width: 434px" class="wp-caption aligncenter"><a href="http://blog.freelan.org/wp-content/uploads/2011/03/shapes.png"><img class="size-full wp-image-341" title="Hiérarchie de classe à héritage multiple" src="http://blog.freelan.org/wp-content/uploads/2011/03/shapes.png" alt="" width="424" height="365" /></a><p class="wp-caption-text">Hiérarchie de classe à héritage multiple</p></div>
<p>Comme nous le voyons ici, nous partons d&#8217;une classe <code>Shape</code> (&#8220;forme&#8221; en anglais), de laquelle dérivent deux classes <code>Rectangle</code> et <code>Diamond</code> (&#8220;losange&#8221; en anglais). Une quatrième classe, <code>Square</code> (&#8220;carré&#8221; en anglais) hérite à la fois de <code>Rectangle</code> et de <code>Diamond</code>.</p>
<p>Une implémentation naïve de cette hiérarchie en C++ pourrait ressembler à :</p><pre class="crayon-plain-tag">class Shape
{
  public:
    int identifier() const { return m_identifier; }
    virtual void draw() = 0;
  private:
    int m_identifier;
};

class Rectangle : public Shape
{
  public:
    void draw() { /* ... */ }
};

class Diamond : public Shape
{
  public:
    void draw() { /* ... */ }
};

class Square : public Rectangle, public Diamond
{
  public:
    void draw() { /* ... */ }
};</pre><p>Cela a du sens : un carré (si on s&#8217;en réfère aux lois de la géométrie) est à la fois un rectangle et un losange, et il est aussi une forme.</p>
<p>Cependant, ce code n&#8217;a en pratique pas la structure souhaitée :</p>
<p>En effet, en utilisant un héritage classique (non virtuel) <code>Square</code> hérite en pratique deux fois de <code>Shape</code> : une fois par la branche de gauche (<code>Rectangle</code>), et une fois par la branche de droite (<code>Diamond</code>). Il en résulte que chaque instance de <code>Square</code> possède deux instances de <code>m_identifier</code>. Lorsqu&#8217;on souhaite utiliser <code>identifier()</code> ou <code>m_identifier</code> dans ou en dehors de la classe <code>Square</code>, il faut préciser par quelle branche on passe :</p>
<ul>
<li>Soit en préfixant m_identifier par <code>Diamond</code> ou <code>Rectangle</code> (&#8220;<code>Rectangle::m_identifier</code>&#8220;);</li>
<li>soit en effectuant auparavant une conversion de <code>this</code> vers <code>Rectangle*</code> ou <code>Diamond*</code> (&#8220;<code>static_cast<Rectangle*>(this)->m_identifier</code>&#8220;)</li>
</ul>
<p>Ce n&#8217;est généralement pas ce qui est souhaité.</p>
<p>Pour résoudre ce problème, nous avons besoin de l&#8217;<strong>héritage virtuel</strong> :</p><pre class="crayon-plain-tag">class Shape
{
  public:
    int identifier() const { return m_identifier; }
    virtual void draw() = 0;
  private:
    int m_identifier;
};

class Rectangle : public virtual Shape // Notez la pr&eacute;sence de &quot;virtual&quot; ici
{
  public:
    void draw() { /* ... */ }
};

class Diamond : public virtual Shape // Notez la pr&eacute;sence de &quot;virtual&quot; ici
{
  public:
    void draw() { /* ... */ }
};

class Square : public Rectangle, public Diamond
{
  public:
    void draw() { /* ... */ }
};</pre><p>En spécifiant que <code>Rectangle</code> et <code>Diamond</code> héritent tous deux virtuellement de <code>Shape</code>, nous empêchons la <em>multiple instanciation</em> du type de base : il n&#8217;y a alors plus qu&#8217;une seule instance de <code>m_identifier</code> et on peut y référer directement sans avoir recours à des conversions.</p>
<h2>Bonnes pratiques</h2>
<p>L&#8217;utilisation de l&#8217;héritage virtuel peut se faire conjointement avec tout autre type d&#8217;héritage (privé, protégé et public), mais est habituellement rencontré principalement avec l&#8217;<strong>héritage public</strong>.</p>
<p>Indépendamment de l&#8217;utilisation de l&#8217;héritage virtuel, on constate assez logiquement que les classes les plus en haut de la hiérarchie devraient dans l&#8217;idéal être virtuelles pures. Si c&#8217;est le cas, cela ne signifie <strong>pas forcément</strong> qu&#8217;il faille supprimer l&#8217;héritage virtuel : outre le fait de ne pas dupliquer inutilement les instances des membres, l&#8217;héritage virtuel permet également de s&#8217;assurer que la classe de base n&#8217;a qu&#8217;<strong>une seule adresse</strong> dans les instances filles. Il est en pratique très probable que vous deviez user d&#8217;héritage virtuel lorsque vous utilisez l&#8217;héritage multiple.</p>
<h1>Conclusion</h1>
<p>Nous avons vu au travers des différentes sections que C++ est très complet en matière d&#8217;héritage. Élément incontournable de la programmation orientée objet moderne, c&#8217;est un principe qu&#8217;il convient de manier avec la plus grande précaution et une bonne réflexion : si l&#8217;héritage peut résoudre bien des problèmes, il n&#8217;est de loin pas la solution universelle. Que vous optiez pour l&#8217;héritage, la composition ou autre chose pour la résolution de vos problèmes, réfléchissez toujours et <strong>envisagez chacune des possibilités</strong>.</p>
<p>Comme toujours, n&#8217;hésitez pas à me faire part de vos remarques, questions ou corrections dans les commentaires.</p>
<h1>Sources</h1>
<p>Voici une série de liens en anglais qui m&#8217;ont inspiré pour la rédaction de cet article. N&#8217;hésitez pas à les consulter, ils sont extrêmement intéressants :</p>
<ul>
<li><a href="http://www.parashift.com/c++-faq-lite/private-inheritance.html">L&#8217;héritage privé/protégé sur parashift</a></li>
<li><a href="http://stackoverflow.com/questions/4605556/when-virtual-inheritance-is-a-good-design">StackOverflow</a></li>
<li><a href="http://en.allexperts.com/q/C-1040/virtual-inheritance.htm">L&#8217;héritage virtuel sur allexperts</a></li>
<li><a href="http://www.parashift.com/c++-faq-lite/multiple-inheritance.html">L&#8217;héritage virtuel sur parashift</a></li>
</ul>
]]></content:encoded>
			<wfw:commentRss>https://blog.freelan.org/2011/03/08/lheritage-en-c/feed/</wfw:commentRss>
		<slash:comments>8</slash:comments>
		</item>
		<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>
		<item>
		<title>Découverte de libsystools 2.1</title>
		<link>https://blog.freelan.org/2010/12/10/decouverte-de-libsystools-2-1/</link>
		<comments>https://blog.freelan.org/2010/12/10/decouverte-de-libsystools-2-1/#comments</comments>
		<pubDate>Fri, 10 Dec 2010 16:06:51 +0000</pubDate>
		<dc:creator><![CDATA[Julien Kauffmann]]></dc:creator>
				<category><![CDATA[Développement]]></category>
		<category><![CDATA[Systools]]></category>
		<category><![CDATA[boost]]></category>
		<category><![CDATA[c++]]></category>
		<category><![CDATA[iconv]]></category>
		<category><![CDATA[libxml2]]></category>
		<category><![CDATA[linux]]></category>
		<category><![CDATA[mac osx]]></category>
		<category><![CDATA[openssl]]></category>
		<category><![CDATA[socket]]></category>
		<category><![CDATA[systools]]></category>
		<category><![CDATA[unix]]></category>
		<category><![CDATA[upnp]]></category>
		<category><![CDATA[windows]]></category>
		<category><![CDATA[xml]]></category>
		<category><![CDATA[xmlsec]]></category>

		<guid isPermaLink="false">http://blog.freelan.org/?p=111</guid>
		<description><![CDATA[Cette semaine, j'ai eu l'immense honneur d'effectuer la "release" de la version 2.1  de notre bibliothèque de base : libsystools. Cette version est le fruit de nombreuses heures de travail de l'équipe freelan et apporte un bon lot de nouveautés par rapport à la dernière version.

Cet article va tenter de vous faire découvrir ces nouveautés, d'expliquer certaines décisions de design et bien entendu de vous donner envie de l'essayer !]]></description>
				<content:encoded><![CDATA[<p>Cette semaine, j&#8217;ai eu l&#8217;immense honneur d&#8217;effectuer la &#8220;release&#8221; de la <a href="https://sourceforge.net/projects/libsystools/">version 2.1</a> de notre bibliothèque de base : <strong>libsystools</strong>. Cette version est le fruit de nombreuses heures de travail de l&#8217;équipe <strong>freelan</strong> et apporte un bon lot de nouveautés par rapport à la dernière version.</p>
<p>Cet article va tenter de vous faire découvrir ces nouveautés, d&#8217;expliquer certaines décisions de design et bien entendu de vous donner envie de l&#8217;essayer !</p>
<h1>Présentation</h1>
<p>Il y a 2 ans, le code de <strong>freelan</strong> commençait à être volumineux. Bon nombre de classes outils étaient écrites qui pouvaient intéresser d&#8217;autres projets. Nous avons donc décidé de rendre cet ensemble de classes autonome et c&#8217;est ainsi qu&#8217;est né <strong>libsystools</strong>.</p>
<p><strong>libsystools</strong> propose une interface C++ moderne pour un certain nombre de bibliothèques C mais aussi des classes nouvelles (notamment SmartBuffer).</p>
<p>Ses principaux domaines d&#8217;application sont :</p>
<ul>
<li>La gestion du xml (parsing, génération, modification, signature);</li>
<li>la gestion de la cryptographie (RSA, AES, SHA);</li>
<li>la gestion des certificats;</li>
<li>la gestion des ports série;</li>
<li>la gestion du SSL (TLS, DTLS);</li>
<li>la gestion du réseau (Socket, SocketAddress, SocketAddressResolver) en IPv4 <strong>et</strong> IPv6.</li>
<li>la gestion facilité de la mémoire (SmartBuffer);</li>
<li>une implémentation basique d&#8217;un client UPnP;</li>
<li>une implémentation basique d&#8217;un client HTTP;</li>
<li>une implémentation simple d&#8217;une classe de log;</li>
<li>la gestion de l&#8217;encodage (UTF-8, UTF-16, ISO-8859-1, etc.);</li>
<li>différentes méthodes pour calculer de checksum, compresser des flux, etc.</li>
</ul>
<p><strong>libsystools</strong> a été conçue dès le départ pour être extrêmement portable, qu&#8217;il s&#8217;agisse des systèmes d&#8217;exploitation ou des architectures. Elle est donc utilisable sur Windows (MinGW, Visual Studio 2010), Linux (gcc), Mac OSX (gcc), UNIX (gcc) aussi bien en 32 bits qu&#8217;en 64 bits.</p>
<p>L&#8217;ensemble de ses classes est documenté et différents exemples sont fournis qui traitent de chacun de ses domaines d&#8217;application.</p>
<p><strong>libsystools</strong> se base sur différentes bibliothèques :</p>
<ul>
<li>libxml2</li>
<li>libxmlsec1</li>
<li>openssl</li>
<li>libiconv</li>
<li>boost</li>
</ul>
<h2>Faciliter l&#8217;existant</h2>
<p>Les bibliothèques sur lesquelles se base <strong>libsystools</strong> sont bien écrites et fiables. Cependant, elles ne fournissent qu&#8217;une interface en C.</p>
<p>Lorsqu&#8217;on utilise que peu ces bibliothèques dans un projet, il est acceptable de se servir simplement de ces interfaces C. Cependant, lorsqu&#8217;un projet en fait un usage intensif, le code devient très rapidement très dur à maintenir.</p>
<p>Qui n&#8217;a jamais eu à écrire un code de ce style ?</p><pre class="crayon-plain-tag">#include &amp;lt;iostream&amp;gt;

#include &amp;lt;libfoo&amp;gt;

int main()
{
	FOOCONTEXT ctx = CreateFooContext();

	try
	{
		FOOHANDLER handler = CreateFooHandler(ctx);

		try
		{
			// Code
		}
		catch (...)
		{
			FreeFooHandler(handler);

			throw;
		}

		FreeFooHandler(handler);
	}
	catch (...)
	{
		FreeFooContext(ctx);

		throw;
	}

	FreeFooContext(ctx);

	return EXIT_SUCCESS;
}</pre><p>Bien sûr, un bon programmeur C++ simplifiera l&#8217;écriture de ce genre de code avec l&#8217;utilisation de classes conteneurs qui se chargent de libérer la ressource associée lors de leur destruction. Mais devoir refaire ce travail d&#8217;encapsulation à chaque utilisation est fastidieux, et ne règle qu&#8217;une partie du problème.</p>
<p>C&#8217;est dans cet esprit qu&#8217;on été développées les classes de <strong>libsystools</strong> : des wrappers simples, faciles à utiliser et efficaces.</p>
<p>En utilisant <strong>libsystools</strong>, le code précédent aurait plutôt ressemblé à :</p><pre class="crayon-plain-tag">#include &amp;lt;iostream&amp;gt;

#include &amp;lt;libfoo&amp;gt;

int main()
{
	FooContext ctx;
	FooHandler handler(ctx);

	// Code

	return EXIT_SUCCESS;
}</pre><p>Ce qui est bien plus lisible et maintenable, et présente l&#8217;avantage d&#8217;être &#8220;exception-safe&#8221;.</p>
<h1>Utilisation &amp; Exemples</h1>
<p>Nous pourrions exposer les différents aspects conceptuels qui ont motivé chaque décision pendant des heures et sur plusieurs pages, mais après tout, en programmation, il n&#8217;y a pas plus explicite que le code. Voici donc quelques exemples d&#8217;utilisation commentés.</p>
<h2>SmartBuffer, ou comment gérer la mémoire de façon intelligente</h2>
<p>S&#8217;il ne fallait garder qu&#8217;une seule classe, ce serait celle-ci : SmartBuffer est au coeur de <strong>libsystools</strong>. Utilisée partout, SmartBuffer représente un tableau d&#8217;octets à taille variable et dont les différentes instances peuvent partager leur mémoire.</p><pre class="crayon-plain-tag">#include &amp;lt;iostream&amp;gt;

#include &amp;lt;systools/smartbuffer.hpp&amp;gt;

int main()
{
	using systools::SmartBuffer;

	// On cr&eacute;e un buffer &agrave; partir d'une cha&icirc;ne C
	SmartBuffer buffer(&quot;Hello you&quot;);

	// On copie un buffer
	SmartBuffer copy = buffer; // copy et buffer partagent la m&ecirc;me m&eacute;moire.

	// On r&eacute;duit copy
	copy.resize(6); // copy a juste &eacute;t&eacute; r&eacute;duit, copy et buffer partagent toujours la m&ecirc;me m&eacute;moire.

	copy.append(&quot;me&quot;); // copy a &eacute;t&eacute; modifi&eacute;, copy et buffer ne partagent plus la m&ecirc;me m&eacute;moire.

	// On affiche les r&eacute;sultats
	std::cout &amp;lt;&amp;lt; &quot;buffer: &quot; &amp;lt;&amp;lt; buffer.toStdString() &amp;lt;&amp;lt; std::endl; // buffer: Hello you
	std::cout &amp;lt;&amp;lt; &quot;copy: &quot; &amp;lt;&amp;lt; copy.toStdString() &amp;lt;&amp;lt; std::endl; // copy: Hello me

	return EXIT_SUCCESS;
}

// On peut utiliser un SmartBuffer comme valeur de retour de fonction
systools::SmartBuffer getBuffer()
{
	// La m&eacute;thode-patron &quot;factory&quot; SmartBuffer::from permet de cr&eacute;er un buffer &agrave; partir de n'importe quel type.
	return systools::SmartBuffer::from&amp;lt;int&amp;gt;(4);
}</pre><p>Dans bon nombre de cas, l&#8217;utilisation de SmartBuffer permet de simplifier le code existant en remplaçant les paramètres de type :</p><pre class="crayon-plain-tag">void fonction(const char* inbuf, size_t inbuflen, char** outbuf, size_t&amp;amp; outbuflen);</pre><p>Par un simple :</p><pre class="crayon-plain-tag">SmartBuffer fonction(const SmartBuffer&amp;amp; inbuf);</pre><p>La lecture et la maintenance s&#8217;en trouvent tous deux grandement facilités.</p>
<h2>XML, les wrappers autour de libxml2</h2>
<p>Avec l&#8217;engouement de tous les domaines pour le web, il est rare aujourd&#8217;hui d&#8217;avoir du code à produire qui ne nécessite pas de manipuler du XML. En C++, plusieurs solutions existent.</p>
<p>Nous avons opté pour la libxml2 pour plusieurs raisons :</p>
<ul>
<li>C&#8217;est une bibliothèque mature, complète et quotidiennement maintenue;</li>
<li>elle est portable sur plusieurs architectures et plateformes;</li>
<li>elle s&#8217;interface très bien avec OpenSSL au sein de libxmlsec1 pour le support des signatures XML.</li>
</ul>
<p>Le module XML de libsystools se décompose en trois parties :</p>
<ul>
<li>Les éléments DOM, qui représentent de façon statique un arbre XML;</li>
<li>les &#8220;writers&#8221; qui permettent de générer du XML;</li>
<li>les objets XPath, qui permettent d&#8217;effectuer des requêtes dans les éléments DOM.</li>
</ul>
<p>Voyons un exemple d&#8217;utilisation :</p><pre class="crayon-plain-tag">#include &amp;lt;iostream&amp;gt;
#include &amp;lt;cstdlib&amp;gt;
#include &amp;lt;cstring&amp;gt;

#include &amp;lt;boost/shared_ptr.hpp&amp;gt;
#include &amp;lt;boost/foreach.hpp&amp;gt;

#include &amp;lt;systools/xml.hpp&amp;gt;
#include &amp;lt;systools/xml_document.hpp&amp;gt;
#include &amp;lt;systools/xml_node.hpp&amp;gt;
#include &amp;lt;systools/xml_xpath.hpp&amp;gt;
#include &amp;lt;systools/xml_buffer_writer.hpp&amp;gt;
#include &amp;lt;systools/xml_document_writer.hpp&amp;gt;

int main(int, char**)
{
	using namespace systools;

	// Initialization
	xml::Initializer xml;

	std::cout &amp;lt;&amp;lt; &quot;Initializing...: &quot; &amp;lt;&amp;lt; &quot;OK&quot; &amp;lt;&amp;lt; std::endl;

	try
	{
		// Generation

		xml::XmlDocumentWriter writer;

		writer.startDocument();
		writer.startElement(&quot;configuration&quot;);
		writer.writeAttribute(&quot;xmlns&quot;, &quot;namespace&quot;);
		writer.writeElement(&quot;key&quot;, &quot;value&quot;);
		writer.startElement(&quot;parent&quot;);
		writer.writeElement(&quot;child&quot;, &quot;anna&quot;);
		writer.writeElement(&quot;child&quot;, &quot;bobby&quot;);
		writer.endElement();
		writer.endDocument();

		xml::XmlDocument document = writer.getResultAsDocument();
		std::cout &amp;lt;&amp;lt; &quot;Generating XML document: &quot; &amp;lt;&amp;lt; &quot;OK&quot; &amp;lt;&amp;lt; std::endl;
		std::cout &amp;lt;&amp;lt; document.toString().toStdString() &amp;lt;&amp;lt; std::endl;

		// XPath

		xml::XPath xpath = document.xpath();

		if (!xpath.registerNamespace(&quot;fl&quot;, &quot;namespace&quot;))
		{
			std::cerr &amp;lt;&amp;lt; &quot;Warning ! Failed to register the namespace !&quot; &amp;lt;&amp;lt; std::endl;
		}

		std::list&amp;lt;xml::XmlNode&amp;gt; list = document.xpath().evaluate(&quot;/fl:configuration/fl:parent&quot;);

		if (list.size() &amp;gt; 0)
		{
			list = list.front().xpath().evaluate(&quot;fl:child&quot;);

			std::cout &amp;lt;&amp;lt; &quot;Results:&quot; &amp;lt;&amp;lt; std::endl;

			BOOST_FOREACH(const xml::XmlNode&amp;amp; node, list)
			{
				std::cout &amp;lt;&amp;lt; node.name().toStdString() &amp;lt;&amp;lt; &quot;: &quot; &amp;lt;&amp;lt; node.content().toStdString() &amp;lt;&amp;lt; std::endl;
			}
		}
	}
	catch (Exception&amp;amp; ex)
	{
		std::cout &amp;lt;&amp;lt; &quot;Exception caught: &quot; &amp;lt;&amp;lt; ex.toString() &amp;lt;&amp;lt; std::endl;
	}

	return EXIT_SUCCESS;
}</pre><p>Reprenons cet exemple point par point :</p>
<ul>
<li>Ligne 20 : nous déclarons un xml::Initializer qui existera pour toute la portée du main. Cet objet permet d&#8217;<strong>initialiser</strong> la libxml2 et de <strong>garantir sa libération</strong> au moment opportun, de façon automatique.</li>
<li>Ligne 28 : nous créons un XmlDocumentWriter. Cet objet permet une construction facilité d&#8217;un arbre XML en construisant l&#8217;un après l&#8217;autre ses différents éléments.</li>
<li>Lignes 30 à 38 : Nous créons chacun des noeuds XML. Les différentes fonctions prennent des systools::String en paramètre et supportent donc parfaitement la gestion des différents encodages.</li>
<li>Ligne 40 : Nous récupérons un arbre XML complet à partir du writer.</li>
<li>Ligne 46 : Nous récupérons l&#8217;instance XPath associé à l&#8217;arbre XML (cette instance est partagée par tous les noeuds d&#8217;un même arbre)</li>
<li>Ligne 48 : Nous associons un nom court au namespace nommé &#8220;namespace&#8221; dans l&#8217;instance XPath.</li>
<li>Ligne 53 : Nous effectuons une requête XPath sur la racine du document.</li>
<li>Ligne 57 : Nous effectuons une requête XPath sur un sous-noeud du document.</li>
</ul>
<p>La manipulation du XML est grandement facilitée. On voit que seules quelques instructions suffisent à construire un arbre, à y naviguer et à en extraire les informations utiles.</p>
<h2>Le module réseau</h2>
<p>Une autre partie importante de libsystools est son module réseau. La manipulation des différentes fonctions et structures réseau d&#8217;un système a toujours été la bête noire des programmeurs novices. Entre les spécificités propres à chaque système d&#8217;exploitation, et les fonctions dépréciées suite au prochain passage à IPv6 (ça approche, si si, croyez-moi !), il n&#8217;est pas toujours évident de produire un code propre et robuste.</p>
<p>Le module réseau de libsystools a été conçu pour résoudre cette problématique. Il propose :</p>
<ul>
<li>Une classe qui permet représenter une adresse de socket (IPv4, IPv6, etc.);</li>
<li>une classe pour effectuer des résolutions de nom ou d&#8217;adresse sur le réseau;</li>
<li>des classes Socket et SecureSocket qui encapsulent respectivement une socket classique et une socket SSL (en TLS ou DTLS);</li>
<li>une classe &#8220;Select&#8221; qui encapsule de façon objet les appels à la méthode &#8220;select()&#8221;;</li>
<li>une classe pour représenter les adresses Ethernet;</li>
<li>des outils de conversion entre adresse IP et représentation numérique.</li>
</ul>
<p>Démontrons la simplicité de son utilisation en montrant le code d&#8217;un example qui va successivement :</p>
<ol>
<li>Chercher l&#8217;adresse de socket associée à 127.0.0.1:34000 en TCP.</li>
<li>Créer une socket</li>
<li>Connecter cette socket sur le serveur TCP situé à l&#8217;adresse recherchée en 1.</li>
<li>Attendre la réception d&#8217;un message.</li>
<li>Se déconnecter et libérer la socket et toutes les ressources associées.</li>
</ol>
<p></p><pre class="crayon-plain-tag">#include &amp;lt;iostream&amp;gt;
#include &amp;lt;cstdlib&amp;gt;
#include &amp;lt;cstring&amp;gt;
#include &amp;lt;string&amp;gt;

#include &amp;lt;list&amp;gt;

#include &amp;lt;systools/network.hpp&amp;gt;
#include &amp;lt;systools/socket.hpp&amp;gt;
#include &amp;lt;systools/socket_address.hpp&amp;gt;
#include &amp;lt;systools/socket_address_resolver.hpp&amp;gt;

int main(int, char**)
{
	using namespace systools;

	network::Initializer network;

	SocketAddressResolver sar;

	try
	{
		sar.getAddrInfo(&quot;127.0.0.1&quot;, &quot;34000&quot;, IPPROTO_TCP, AF_UNSPEC);

		if (sar.size() &amp;lt;= 0)
		{
			std::cout &amp;lt;&amp;lt; &quot;No address information was returned.&quot; &amp;lt;&amp;lt; std::endl;
		} else
		{
			// Usually, one could choose to iterate trough the results and to keep only the first one to which a connection can be established.
			Socket socket(sar.front());
			SocketAddress address(sar.front());

			std::cout &amp;lt;&amp;lt; &quot;Connecting to: &quot; &amp;lt;&amp;lt; address.toNumericString() &amp;lt;&amp;lt; std::endl;

			socket.connect(address);

			SmartBuffer message;

			size_t recv_bytes = socket.recv(message);

			if (recv_bytes &amp;gt; 0)
			{
				std::cout &amp;lt;&amp;lt; &quot;Receiving message: &quot; &amp;lt;&amp;lt; std::string(message.constData(), message.size()) &amp;lt;&amp;lt; std::endl;
			}
		}
	}
	catch (Exception&amp;amp; ex)
	{
		std::cout &amp;lt;&amp;lt; &quot;Exception: &quot; &amp;lt;&amp;lt; ex.toString() &amp;lt;&amp;lt; std::endl;

		return EXIT_FAILURE;
	}

	return EXIT_SUCCESS;
}</pre><p>Pas si mal pour un code d&#8217;une cinquantaine de lignes qui gère correctement toutes les erreurs potentielles et la libération des ressources, non ?</p>
<h1>Pour conclure</h1>
<p>Vous n&#8217;avez eu ici qu&#8217;un très bref aperçu des possibilités offertes par la <strong>libsystools</strong>. Pour découvrir plus avant la bibliothèque, je vous invite à consulter sa <a href="http://www.freelan.org/doc-2.1">documentation en ligne</a>.</p>
<p>En tout cas, j&#8217;espère sincèrement que cette présentation aura attisé votre curiosité et vous aura donné envie d&#8217;essayer la bibliothèque lors de vos prochains développements. Bien entendu, si vous avez des questions générales sur la bibliothèque et des interrogations concernant son évolution future, n&#8217;hésitez pas à commenter cet article ou directement contacter l&#8217;équipe sur la <a href="mailto:libsystools-users@lists.sourceforge.net">mailing-list</a> (en anglais).</p>
<p>Bon code ! <img src="https://blog.freelan.org/wp-includes/images/smilies/icon_smile.gif" alt=":)" class="wp-smiley" /></p>
]]></content:encoded>
			<wfw:commentRss>https://blog.freelan.org/2010/12/10/decouverte-de-libsystools-2-1/feed/</wfw:commentRss>
		<slash:comments>4</slash:comments>
		</item>
		<item>
		<title>Développer avec Qt pour Android</title>
		<link>https://blog.freelan.org/2010/11/27/developper-avec-qt-pour-android/</link>
		<comments>https://blog.freelan.org/2010/11/27/developper-avec-qt-pour-android/#comments</comments>
		<pubDate>Sat, 27 Nov 2010 09:42:21 +0000</pubDate>
		<dc:creator><![CDATA[Damien Buhl]]></dc:creator>
				<category><![CDATA[Android]]></category>
		<category><![CDATA[Développement]]></category>
		<category><![CDATA[Qt]]></category>
		<category><![CDATA[android]]></category>
		<category><![CDATA[ant]]></category>
		<category><![CDATA[c++]]></category>
		<category><![CDATA[console]]></category>
		<category><![CDATA[java]]></category>
		<category><![CDATA[linux]]></category>
		<category><![CDATA[qt]]></category>

		<guid isPermaLink="false">http://blog.freelan.org/?p=63</guid>
		<description><![CDATA[C&#8217;est possible ? Dans ce petit article je vais vous parler du développement Android avec Qt et en C++, en effet, j&#8217;ai travaillé dernièrement dans une entreprise d&#8217;automatisation et de régulation des bâtiments où un des développeurs était en charge d&#8217;un projet d&#8217;application Android. La qualité de ses développements m&#8217;a donné envie de tenter l&#8217;aventure. [&#8230;]]]></description>
				<content:encoded><![CDATA[<h1>C&#8217;est possible ?</h1>
<p>Dans ce petit article je vais vous parler du développement Android avec Qt et en C++, en effet, j&#8217;ai travaillé dernièrement dans une entreprise d&#8217;automatisation et de régulation des bâtiments où un des développeurs était en charge d&#8217;un projet d&#8217;application Android. La qualité de ses développements m&#8217;a donné envie de tenter l&#8217;aventure. Malgré la magnifique API de Java pour android je voulais pouvoir déployer pour Windows, Linux, Mac, Symbian et Android la même application. Mon choix se portait donc sur mon framework préféré : Qt et naturellement mon langage préféré. Je ne serai jamais assez redevant à <a href="http://fr.wikipedia.org/wiki/Bjarne_Stroustrup">Bjarne Stroustrup</a> =D.</p>
<p>Développer des applications basées sur Qt pour android est possible via le projet <a href="http://code.google.com/p/android-lighthouse/" target="_blank">android-lighthouse</a>, qui <a href="http://taipan.blip.tv/" target="_blank">fonctionne très bien</a> ! En effet ce dernier rend possible l&#8217;exécution d&#8217;une application C++/Qt complète ou encore l&#8217;utilisation en Java des libraires écrites avec le framework.</p>
<p><a href="http://taipan.blip.tv/"><img class="aligncenter size-full wp-image-100" src="http://blog.freelan.org/wp-content/uploads/2010/11/introduction.png" alt="Qt Quick UI - BogDan Vatra" width="335" height="483" /></a></p>
<h2>Lighthouse</h2>
<p>Quant à lighthouse c&#8217;est un projet que l&#8217;équipe du Framework Qt a lancé avant la version 4.7 pour rendre le framework Qt portable à n&#8217;importe quelle plateforme facilement. En effet cela requiert très peu de code spécifique à la plateforme afin de faire fonctionner toutes les librairies Qt.</p>
<p>Depuis quelques semaines lighthouse est passé dans la branche stable de Qt. Grâce à android-lighthouse on peut d&#8217;ailleurs voir que le portage des bibliothèques est très rapide. Seulement quelques mois ont été nécessaires pour obtenir une version pleinement (ou presque) fonctionnelle: même les interfaces basées sur le QML fonctionnent! C&#8217;est grâce à BogDan Vatra, initiateur du projet, que le port de Qt pour android en est arrivé à cette maturité qui démontre ainsi que Qt peut être porté n&#8217;importe où: Code less, do more, deploy everywhere!</p>
<h2>Awesome!</h2>
<p>Cela rend le portage d&#8217;applications Qt sur Android très simple, écrire une application avec le framework Qt signifie que l&#8217;on peut désormais la compiler sans effort pour : Symbian, Windows, Mac, Linux &amp; Android ! <img src="https://blog.freelan.org/wp-includes/images/smilies/icon_smile.gif" alt=":)" class="wp-smiley" /> C&#8217;est à mon sens parfait pour construire une base de librairies réutilisables dans une entreprise. Dans cette idée il est également possible de développer des bibliothèques basées sur les fonctionnalités de Qt et de les lier avec JNI afin d&#8217;apporter des fonctionnalités natives aux applications Java Android existantes.</p>
<p>Je vous présenterai dans cet article les différentes versions d&#8217;Android supportées, les quelques limitations et clarifications nécessaires, ainsi que les procédures à suivre afin de compiler  pour et lancer sur Android votre application Qt.</p>
<h1>Les versions d&#8217;Android compatibles</h1>
<p>Lorsque le projet Qt android-lighthouse a été créé, seuls les périphériques Android 1.5 étaient supportés avec Qt lié en statique, ce qui n&#8217;est plus le cas aujourd&#8217;hui. En effet la branche actuelle du dépôt supporte seulement Qt lié dynamiquement (cela réduit l&#8217;utilisation de la mémoire &#8211; James Noble &amp; Charles Weir 2001 &#8211; Small Memory Software, puisque chacune des applications partagent les mêmes bibliothèques Qt). Cette dernière supporte aujourd&#8217;hui les versions d&#8217;Android actuelles du marché: 1.6, 2.0, 2.1 et 2.2. N&#8217;hésitez pas à essayer avec l&#8217;émulateur Android car il fonctionne comme les véritables périphériques, plus d&#8217;un développeur Android m&#8217;en a confirmé ses qualités. <img src="https://blog.freelan.org/wp-includes/images/smilies/icon_smile.gif" alt=":)" class="wp-smiley" /></p>
<h1>Quelques Limitations</h1>
<p>Il y a actuellement (25/11/2010) <a href="http://code.google.com/p/android-lighthouse/issues/list" target="_blank">quelques limitations</a>, par exemple le rendu est réalisé uniquement par le software, les accélérations matérielles Open GL ne sont pas utilisées. Toutefois ce n&#8217;est certainement qu&#8217;une question de jours, car jusqu&#8217;aujourd&#8217;hui le portage de Qt sur Android a été très rapide et est toujours aussi actif.</p>
<p>Une autre limitation qui sera bientôt fixée d&#8217;après les initiateurs du projet est que l&#8217;on ne peut utiliser QtMultimedia pour jouer des sons, il y a d&#8217;autres solutions pour y parvenir, toutefois le port de QtMultimedia sera bientôt fait, et d&#8217;après l&#8217;initiateur du projet cela devrait être <a href="http://code.google.com/p/android-lighthouse/issues/detail?id=5" target="_blank">&#8220;le correctif le plus facile&#8221;</a> qu&#8217;il lui reste à faire.</p>
<h1>Quelques Clarifications</h1>
<p>Vous n&#8217;avez pas besoin d&#8217;être &#8220;root&#8221; ou d&#8217;avoir accès au shell root sur votre périphérique pour déployer des applications Qt, cela signifie que vous pourriez envoyer l&#8217;application sur le Google Market. Toutefois actuellement il est plutôt déconseillé de le faire, il vaudrait mieux attendre que cela soit plus testé et utilisé (ce que fait actuellement une communauté grandissante: <a href="http://groups.google.com/group/android-qt/">http://groups.google.com/group/android-qt/</a>).</p>
<h1>Préparez votre environnement de développement</h1>
<p>J&#8217;ai écrit les instructions suivantes en m&#8217;inspirant de la page <a href="http://code.google.com/p/android-lighthouse/wiki/Compile">http://code.google.com/p/android-lighthouse/wiki/Compile</a> et de ma propre expérience sur Linux 32 bits. Si vous êtes sur Windows vous devriez jeter un oeil au problème suivant: <a href="http://code.google.com/p/android-lighthouse/issues/detail?id=11" target="_blank">Configure does not work with Cygwin on winxp</a> et appliquer le patch pour cygwin qui est proposé dans l&#8217;une des réponses. Enfin si vous êtes sur Mac OS X vous devriez simplement oublier pour le moment (ou bien trouver une solution :p): <a href="http://code.google.com/p/android-lighthouse/issues/detail?id=18" target="_blank">broken build on mac osx &#8211; x86</a>.</p>
<p>Linux semble être la meilleure plateforme pour développer avec Qt pour android actuellement, donc si vous n&#8217;utilisez pas cette plateforme, je vous conseille d&#8217;essayer avec une <a href="http://www.virtualbox.org/wiki/Downloads" target="_blank">Machine Virtuelle</a>, du moins c&#8217;est la solution dont je peux vous en assurer le fonctionnement. <img src="https://blog.freelan.org/wp-includes/images/smilies/icon_smile.gif" alt=":)" class="wp-smiley" /></p>
<p>Actuellement quelques éléments dits sur la page officielle traitant de la compilation de Qt et d&#8217;applications Qt pour android ne sont pas vraies, c&#8217;est pourquoi je vais vous guider dans la bonne direction pour faire fonctionner votre application Qt sur android, tel que Francisco Dalla Rosa Soares m&#8217;a montré cette semaine sur la mailing list d&#8217;android-lighthouse. Sans lui je n&#8217;aurai jamais pu lancer quoi que ce soit, si ce n&#8217;est mon pc portable&#8230;</p>
<h2>Téléchargement</h2>
<p>Avant tout il vous faut télécharger et décompresser <a href="http://code.google.com/p/android-lighthouse/wiki/QADK" target="_blank">QADK</a>, qui est un Kit de Développement natif non officiel pour android, basé sur l&#8217;officiel mais avec quelques bibliothèques non supportées en plus:</p><pre class="crayon-plain-tag">wget http://android-lighthouse.googlecode.com/files/qadk-r4-1.tar.bz2
tar xf qadk-r4-1.tar.bz2 .</pre><p>Après cela il vous faudra cloner le repository git de android-lighthouse qui lui même consiste en un clone du projet Qt lighthouse qui est officiellement fourni par Nokia:</p><pre class="crayon-plain-tag">git clone git://gitorious.org/~taipan/qt/android-lighthouse.git</pre><p></p>
<h2>Configurer &amp; Compiler</h2>
<p>Vous devrez compiler Qt pour la plateforme visée, il est nécessaire de définir la variable ANDROID_PLATFORM et de faire pointer NDK_ROOT vers le dossier où vous avez décompressé QADK.</p><pre class="crayon-plain-tag">mkspecs/android-g++/qmake.conf:12 -&amp;gt;
NDK_ROOT = /path/to/qadk-r4</pre><p></p><pre class="crayon-plain-tag">mkspecs/android-g++/qmake.conf:18 -&amp;gt;
ANDROID_PLATFORM = android-5</pre><p>La dernière ligne est présente pour cibler les plateformes android 2.0 &amp; 2.1, ce qui fonctionna sans problèmes pour ma part. Utilisez <em>android-4</em> afin de cibler les plateformes 1.6 et <em>android-8</em> pour cibler les plateformes 2.2.</p>
<p>Vous pouvez désormais lancer la partie de configuration (n&#8217;hésitez pas à aller voir votre petite amie pendant ce temps):</p><pre class="crayon-plain-tag">./androidconfig.sh</pre><p>Et enfin vous pouvez compiler le tout:</p><pre class="crayon-plain-tag">make -j3</pre><p>Changez 3 par le nombre de coeur de votre processeur + un, cela activera la compilation parallèle avec autant de processus.</p>
<p>Il y a une dépendance de Qt qui n&#8217;est pas incluse au projet, c&#8217;est <strong>libcloog-ppl-dev</strong>, lancez simplement:</p><pre class="crayon-plain-tag">sudo apt-get install libcloog-ppl-dev</pre><p><em>Pour ce que j&#8217;ai pu comprendre c&#8217;est une librarie utilisée pour l&#8217;optimisation de code, qui est destinée à générer du code permettant de passer sur chacun des points d&#8217;un Polyèdre. Je suppose que c&#8217;est utilisé dans qmake, mais je ne pourrai vous l&#8217;assurer. Plus de détails et un exemple <a href="http://www.cloog.org/" target="_blank">sur le site officiel</a>.</em></p>
<h2>Installez Qt sur le Périphérique</h2>
<p>Maintenant ce serait sympa d&#8217;avoir Qt sur le périphérique Android (ou dans l&#8217;émulateur), pour ce faire faites simplement ce que la page de wiki de google code conseille:</p><pre class="crayon-plain-tag">mkdir andlibs
cp -a lib/*.so* andlibs/
adb push andlibs /data/local/qt/lib</pre><p></p>
<h3>Connectez votre Périphérique</h3>
<p>Si vous recevez l&#8217;erreur <em>adb: command not found</em>, c&#8217;est parce que vous êtes nouveau au développement Android (tout comme moi). Vous devez simplement télécharger le dernier sdk d&#8217;Android, vous pouvez trouver les instructions détaillées <a href="http://blog.freelan.org/2010/11/20/installer-lenvironnement-de-developpement-pour-android/" target="_blank">ici</a> et le sdk <a href="http://developer.android.com/sdk/index.html" target="_blank">ici</a>.</p>
<p>Cependant à cette étape de l&#8217;article vous avez simplement besoin de télécharger le SDK, de définir le PATH et d&#8217;éxécuter:</p><pre class="crayon-plain-tag">tools/android update sdk</pre><p>Ensuite si vous voulez essayer sur votre véritable téléphone vous devrez activer la connexion avec ce dernier, pour y parvenir je vous invite à suivre la petite partie décrite <a href="http://developer.android.com/guide/developing/device.html#setting-up" target="_blank">sur le site d&#8217;android</a>.</p>
<p>Je suis sur Linux, donc j&#8217;ai simplement mis en place la configuration suivante pour mon téléphone LGGT540 sur android 2.1. Sur mon pc avec Ubuntu 10.10 j&#8217;ai défini les informations suivantes dans le fichier /etc/udev/rules.d/51-android.rules:<br />
<em>Les fichiers présents dans /etc/udev/rules.d/ sont destinés à définir <a href="http://www.reactivated.net/writing_udev_rules.html#why" target="_blank">des règles persistantes pour les périphériques</a>, dont l&#8217;une est de changer le CHMOD d&#8217;accès à un périphérique, en fonction d&#8217;éléments permettant de l&#8217;identifier.</em></p><pre class="crayon-plain-tag">SUBSYSTEM==&quot;usb&quot;, SYSFS{idVendor}==&quot;1004&quot;, MODE=&quot;0666&quot;
SUBSYSTEM==&quot;usb_device&quot;, SYSFS{idVendor}==&quot;1004&quot;, MODE=&quot;0666&quot;</pre><p>Où 1004 vient d&#8217;une liste fournie de Vendor Ids pour les périphériques android: <a href="http://developer.android.com/guide/developing/device.html#VendorIds/">http://developer.android.com/guide/developing/device.html#VendorIds/</a>. Prenez celui qui convient. <img src="https://blog.freelan.org/wp-includes/images/smilies/icon_smile.gif" alt=":)" class="wp-smiley" /></p>
<p>Sur Windows il vous faudra simplement installer les pilotes adb, et sur Mac OS X cela fonctionne sans rien faire, toutefois rappelez vous que android-lighthouse pour Mac OS X ne semble pas fonctionner.</p>
<p>Pour lister les périphériques Android existants vous pouvez lancer: <em>adb devices</em>.</p>
<h2>Votre première Application Qt pour Android</h2>
<p>Nous n&#8217;allons pas écrire notre propre code (oui je sais c&#8217;est triste), parce qu&#8217;il y a beaucoup de Hello World-like dans les demos du Qt Sdk. Nous allons donc choisir un très simple, afin d&#8217;expliquer les choses qui nous intéressent: la configuration de la compilation et comment créer un projet java afin de lancer l&#8217;application.</p>
<p>En effet contrairement aux dires du site officiel il n&#8217;est pas possible actuellement de compiler directement l&#8217;application en temps qu&#8217;exécutable natif. Il est nécessaire de la compiler en une bibliothèque dynamique, que l&#8217;on chargera à l&#8217;aide d&#8217;un petit launcher java basé sur les classes fournies par android-lighthouse. Ces dernières sont présentes dans le package com.nokia.qt.QtActivity.</p>
<p>Maintenant allez dans le répertoire <em>/android-lighthouse/demos/mainwindow/</em>, ici vous pouvez ouvrir le fichier mainwindow.pro, qui devrait contenir les configurations suivantes:</p><pre class="crayon-plain-tag">TEMPLATE = lib
CONFIG += dll

HEADERS += colorswatch.h mainwindow.h toolbar.h
SOURCES += colorswatch.cpp mainwindow.cpp toolbar.cpp main.cpp</pre><p>Il est réellement important de compiler l&#8217;application en tant que bibliothèque dynamique, ainsi pour vos prochaines applications n&#8217;oubliez pas d&#8217;utiliser les deux premières lignes données ci-dessus. Personnellement j&#8217;ai une préférence pour CMake, mais je n&#8217;ai pas encore pu préparer de configuration pour android pour le moment, et pourtant cela devrait seulement consister à éditer la méthode <strong>qt4_wrap_cpp</strong> pour lui donner la version android-lightouse spécialisée de qmake.</p>
<p>En effet pour compiler l&#8217;application, il faut utilisez <em>android-lighthouse/bin/qmake</em> afin de générer les fichiers de moc et le Makefile, et non pas la version de qmake que vous avez dans votre PATH.</p><pre class="crayon-plain-tag">/path/to/android-lighthouse/bin/qmake
make -j3</pre><p>Voilà, vous ne devez même pas adapter le code de votre application Qt. Le résultat des commandes que vous avez lancées devrait être un fichier so (shared object) avec différents liens symboliques afin de rendre possible la compatibilité entre versions apportée par libtool.</p>
<p>Envoyez simplement celle sans informations de compatibilité de versions sur votre périphérique android: <em>adb push libmainwindow.so /data/local/qt/lib</em>. Une fois que vous avez fait cela, l&#8217;application est sur le téléphone, mais rien n&#8217;existe pour la lancer.</p>
<h2>Créez le Projet Android</h2>
<p>Nous allons ainsi créer un launcher en java, basé sur le launcher fourni par le projet android-lighthouse, qui s&#8217;occupe tout seul des bindings JNI nécessaires. <img src="https://blog.freelan.org/wp-includes/images/smilies/icon_biggrin.gif" alt=":D" class="wp-smiley" /></p>
<p>Tout d&#8217;abord <a href="http://blog.freelan.org/2010/11/22/developper-pour-android-sans-utiliser-eclipse/" target="_blank">créez un projet</a> dans un sous-dossier (javaLoader par exemple)</p><pre class="crayon-plain-tag">android create project --target 2.1 \
			--name mainwindow \
			--path ./ \
			--activity mainwindow \
			--package com.yourcompany.mainwindow</pre><p>Créez une classe <strong>QtMain.java</strong> (vim seul ou avec eclim est un bon outil pour cela):</p><pre class="crayon-plain-tag">package org.yourcompany.mainwindow;

	import com.nokia.qt.QtActivity;

	public class QtMain extends QtActivity
	{
		public QtMain()
		{
			/* setLibraries(libraries);
			    This could be useful for you if you need to load
			    some other libraries with your application.
			*/
			setApplication(&quot;mainwindow&quot;);
		}
	}</pre><p>Et ensuite tapez simplement:</p><pre class="crayon-plain-tag">ant debug
cd bin
adb install mainwindow-debug.apk</pre><p>Votre application est installée, et peut facilement être lancée sur votre périphérique à l&#8217;aide de:</p><pre class="crayon-plain-tag">adb shell am start -a android.intent.action.MAIN -n com.yourcompany.mainwindow/.mainwindow</pre><p></p>
<h2>À propos du débogage</h2>
<p>Pour le moment je n&#8217;ai hélas pas réussi à déboguer l&#8217;application sur le périphérique, mais les sorties consoles sont redirigées, il est donc tout de même possible d&#8217;utiliser qDebug pour faire le débogage. Ce n&#8217;est pas optimal mais ce n&#8217;est qu&#8217;en attendant de trouver un moyen simple. Je pense néanmoins que l&#8217;outil qadk-r4/ndk-gdb peut rendre le débogage possible, je n&#8217;ai pas réussi cependant à faire quoi que ce soit pour l&#8217;instant à ce sujet. Je posterai dès que j&#8217;y parviendrai. <img src="https://blog.freelan.org/wp-includes/images/smilies/icon_wink.gif" alt=";)" class="wp-smiley" /></p>
<h2>Qt Creator</h2>
<p>Apparemment l&#8217;intégration d&#8217;Android pour Qt Creator est très avancée mais pas encore dans le dépôtd&#8217;après un mail de Tero Savolainen arrivé au moment de poster l&#8217;article, sur la liste de diffusion nommé &#8220;Re: Qt porting status and some great news&#8221; l&#8217;intégration de Qt Creator avec Androïd est faite et le débogage est la prochaine fonctionnalité à venir.</p>
<h1>Conclusion</h1>
<p>Comme vous avez pu le voir il devient très simple de développer nativement pour Android, le projet étant très actif, il y a fort à parier que pour fin décembre les limitations citées devraient avoir disparues et que le débogage soit possible.</p>
<p>Merci beaucoup pour votre lecture, je suis ouvert à toutes vos suggestions et remarques concernant cet l&#8217;article. <img src="https://blog.freelan.org/wp-includes/images/smilies/icon_wink.gif" alt=";)" class="wp-smiley" /></p>
]]></content:encoded>
			<wfw:commentRss>https://blog.freelan.org/2010/11/27/developper-avec-qt-pour-android/feed/</wfw:commentRss>
		<slash:comments>10</slash:comments>
		</item>
	</channel>
</rss>
