<?xml version="1.0" encoding="utf-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom">
  <channel>
    <atom:link href="https://jacek.zlydach.pl/blog/tags/rzutowania-feed.xml" rel="self" type="application/rss+xml"/>
    <title>Posts tagged: rzutowania - Jacek Złydach - blog</title>
    <link>https://jacek.zlydach.pl/blog/tags/rzutowania.html</link>
    <lastBuildDate>Tue, 25 Jan 2022 12:54:25 +0100</lastBuildDate>
    <description>Blog of Jacek Złydach - a programmer and science enthusiast.</description>
    <generator>Regenerate2</generator>
    <managingEditor>temporal.pl@gmail.com (Jacek Złydach)</managingEditor>
    <webMaster>temporal.pl@gmail.com (Jacek Złydach)</webMaster>
    <ttl>1440</ttl>
    <copyright>© 2017, 2018, 2019, 2020, 2021, 2022, Jacek Złydach</copyright>
    <item>
      <title>Używaj rzutowania w stylu C++</title>
      <link>https://jacek.zlydach.pl/blog/2010-05-07-uzywaj-rzutowania-w-stylu-c.html</link>
      <guid isPermaLink="true">https://jacek.zlydach.pl/blog/2010-05-07-uzywaj-rzutowania-w-stylu-c.html</guid>
      <pubDate>Fri, 07 May 2010 12:44:21 +0200</pubDate>
      <category domain="https://jacek.zlydach.pl/blog/tags/old-blog.html">Old blog</category>
      <category domain="https://jacek.zlydach.pl/blog/tags/porady.html">porady</category>
      <category domain="https://jacek.zlydach.pl/blog/tags/c.html">C</category>
      <category domain="https://jacek.zlydach.pl/blog/tags/rzutowania.html">rzutowania</category>
      <description><![CDATA[Chociaż temat ten był wałkowany m.in. przez Scotta Meyers'a w <a href="http://www.wnt.pl/product.php?action=0&amp;prod_id=55&amp;hot=1">More Effective C++</a>, to wciąż widzi się masę kodu pisanego z rzutowaniami w stylu C. Dla przypomnienia, w C++ mamy cztery rodzaje rzutowań:
<ul>
	<li><code lang="C++" inline="true"><span class="no-paren-fx"><span class="symbol">static_cast</span></span></code></li>
	<li><code lang="C++" inline="true"><span class="no-paren-fx"><span class="symbol">const_cast</span></span></code></li>
	<li><code lang="C++" inline="true"><span class="no-paren-fx"><span class="symbol">dynamic_cast</span></span></code></li>
	<li><code lang="C++" inline="true"><span class="no-paren-fx"><span class="symbol">reinterpret_cast</span></span></code></li>
</ul>

Rzutowania w stylu C wyglądają natomiast tak: <code lang="C++" inline="true"><span class="no-paren-fx"><span class="paren1">(<span class="no-paren-fx">typ</span>)</span>argument</span></code>, lub tak: <code lang="C++" inline="true"><span class="no-paren-fx">typ<span class="paren1">(<span class="no-paren-fx">argument</span>)</span></span></code>.

Jeden z ciekawych problemów, który może się pojawić u programisty stosującego rzutowania w stylu C ilustruje poniższy fragment kodu:
<pre><code lang="C++"><span class="no-paren-fx">Object Foo<span class="paren1">(<span class="no-paren-fx"> <span class="symbol">int</span><span class="paren2">(<span class="no-paren-fx">parameter</span>)</span> </span>)</span>;</span></code></pre>

Ten kod wbrew pozorom nie robi tego, na co wygląda. Nie jest to stworzenie obiektu Foo typu Object, z rzutowaniem parametru na typ <code lang="C++" inline="true"><span class="no-paren-fx"><span class="symbol">int</span></span></code>. <strong>C++ przyjmuje zasadę, że wszystko co wygląda jak deklaracja funkcji ma być w pierwszej kolejności potraktowane jak deklaracja funkcji</strong>. I w tym przypadku kod ten deklaruje nam funkcję o nazwie Foo, zwracającej obiekt typu Object i przyjmującej jeden parametr typu <code lang="C++" inline="true"><span class="no-paren-fx"><span class="symbol">int</span></span></code>.

Może na co dzień nie spotkamy się z takimi ekstremalnymi zjawiskami, ale rzutowania w stylu C++ mają kilka dobrych cech, o których warto wiedzieć:
<ul>
	<li>Są dużo bardziej przyjazne dla grep'a i innych narzędzi wyszukujących w tekście. O wiele łatwiej jest znaleźć wszystkie wystąpienia <code lang="C++" inline="true"><span class="no-paren-fx"><span class="symbol">static_cast</span></span></code> niż rzutowań opartych o nawiasy okrągłe, które czasem mogą przypominać np. wywołanie funkcji albo tworzenie nowego obiektu. Poza tym, w jaki sposób znaleźć wszystkie rzutowania <em>niezależnie od typu, na który się ono odbywa</em>? ;)</li>
	<li>Są dużo bardziej przyjazne dla <a href="http://catb.org/jargon/html/V/vgrep.html">vgrep'a</a> (dla ludzkiego oka ;) ) - łatwiej je wypatrzeć w gąszczu nawiasów; z resztą w większości IDE są kolorowane jako słowa kluczowe. Weźmy przykład poniższego kodu:
<pre><code lang="C++"><span class="no-paren-fx"><span class="symbol">int</span> offset = <span class="paren1">(<span class="no-paren-fx"><span class="symbol">int</span></span>)</span><span class="paren1">(<span class="no-paren-fx">T*</span>)</span>1 - <span class="paren1">(<span class="no-paren-fx"><span class="symbol">int</span></span>)</span><span class="paren1">(<span class="no-paren-fx">Singleton &lt;T&gt;*</span>)</span><span class="paren1">(<span class="no-paren-fx">T*</span>)</span>1
	ms_singleton = <span class="paren1">(<span class="no-paren-fx">T*</span>)</span><span class="paren1">(<span class="no-paren-fx"><span class="paren2">(<span class="no-paren-fx"><span class="symbol">int</span></span>)</span><span class="symbol">this</span> + offset</span>)</span>;</span></code></pre>
i porównajmy go z tym:
<pre><code lang="C++"><span class="no-paren-fx"><span class="symbol">int</span> offset = <span class="symbol">reinterpret_cast</span>&lt;<span class="symbol">int</span>&gt;<span class="paren1">(<span class="no-paren-fx"><span class="symbol">reinterpret_cast</span>&lt;T*&gt;<span class="paren2">(<span class="no-paren-fx">1</span>)</span></span>)</span> -
	<span class="symbol">reinterpret_cast</span>&lt;<span class="symbol">int</span>&gt;<span class="paren1">(<span class="no-paren-fx"><span class="symbol">static_cast</span>&lt;Singleton &lt;T&gt;*&gt;<span class="paren2">(<span class="no-paren-fx"><span class="symbol">reinterpret_cast</span>&lt;T*&gt;<span class="paren3">(<span class="no-paren-fx">1</span>)</span></span>)</span></span>)</span>;
	ms_singleton = <span class="symbol">reinterpret_cast</span>&lt;T*&gt;<span class="paren1">(<span class="no-paren-fx"><span class="paren2">(<span class="no-paren-fx"><span class="symbol">reinterpret_cast</span>&lt;<span class="symbol">int</span>&gt;<span class="paren3">(<span class="no-paren-fx"><span class="symbol">this</span></span>)</span> + offset</span>)</span></span>)</span>;</span></code></pre>
Wariant C++ nie jest ani trochę piękniejszy, ale przynajmniej można od razu policzyć ile jest rzutowań i jakiego rodzaju. Poza tym, składnia wywołania funkcji pozwala od razu ogarnąć, które wyrażenia są rzutowane.
</li>
	<li>Jak widać powyżej, są długie, rozwlekłe i brzydkie. I bardzo dobrze. Rzutowania to coś, czego nie powinno się stosować bez wyraźnej potrzeby, więc jeśli programiście <em>przeszkadza</em> pisanie takiego kodu, to tym lepiej dla projektu.</li>
	<li>Lepiej rozdzielają odpowiedzialność - każdy z rodzajów rzutowania w C++ jest odpowiedzialny za inne zadanie. Dzięki temu kod lepiej wyraża intencje autora (np. widząc w kodzie <code lang="C++" inline="true"><span class="no-paren-fx"><span class="symbol">const_cast</span></span></code> masz pewność, że programista chciał jedynie zdjąć lub założyć modyfikator <code lang="C++" inline="true"><span class="no-paren-fx"><span class="symbol">const</span></span></code> albo <code lang="C++" inline="true"><span class="no-paren-fx"><span class="symbol">volatile</span></span></code>).</li>
	<li>Mają spójną składnię. Rzutowania w stylu C mogą występować w dwóch wariantach - z typem w nawiasie oraz w składni &quot;konstruktora&quot;, z rzutowanym argumentem w nawiasie. Sam fakt, że w tym samym programie możemy natknąć się na oba warianty powoduje, że myśl o wyszukiwaniu ich w kodzie jest przerażająca.</li>
</ul>

Zainteresowanych tematem rzutowania odsyłam do <a href="http://regedit.gamedev.pl/productions/artykuly/rzutowanie_typow_w_cpp.php5">świetnego artykułu Reg'a</a> poświęconego temu tematowi. Chciałbym zaznaczyć jednak, że nie zgadzam się z jego wnioskiem numer 2, tj.
<blockquote>Nie ma praktycznych przesłanek, by rezygnować ze stosowania eleganckiego, zwięzłego rzutowania w stylu C na rzecz rozwlekłych operatorów static_cast i reinterpret_cast.</blockquote>
Wydaje mi się, że w tym poście zawarłem wiele praktycznych przesłanek za rezygnacją z rzutowania w stylu C.
]]></description>
    </item>
  </channel>
</rss>