<?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>deadlime &#187; C++</title>
	<atom:link href="http://deadlime.hu/tag/cpp/feed/" rel="self" type="application/rss+xml" />
	<link>http://deadlime.hu</link>
	<description>unexpected terminator</description>
	<lastBuildDate>Mon, 14 May 2012 20:38:51 +0000</lastBuildDate>
	<language>en</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
	<generator>http://wordpress.org/?v=3.3.2</generator>
		<item>
		<title>Objektum-orientált C++ VII.</title>
		<link>http://deadlime.hu/2006/12/02/objektum-orientalt-cpp-7/</link>
		<comments>http://deadlime.hu/2006/12/02/objektum-orientalt-cpp-7/#comments</comments>
		<pubDate>Sat, 02 Dec 2006 06:06:20 +0000</pubDate>
		<dc:creator>Nagy Krisztián</dc:creator>
				<category><![CDATA[nincs kategória]]></category>
		<category><![CDATA[C++]]></category>
		<category><![CDATA[objektum-iteráció]]></category>
		<category><![CDATA[objektum-orientált]]></category>

		<guid isPermaLink="false">http://deadlime.hu/2006/12/02/objektum-orientalt-cpp-7/</guid>
		<description><![CDATA[Annak idején, amikor a sorozat hatodik részét megírtam, még azt hittem, hogy vége a sorozatnak. De hatalmas hibát követtem el. Megfeledkeztem a bejárókról. Ezt a hatalmas hiányosságot igyekszem most hirtelen pótolni ennek a bejegyzésnek a keretein belül. Kezdjük is talán a legelején, hogy mi is az a bejáró (iterator)? A Nagy Könyv keveset mondó ám [...]]]></description>
			<content:encoded><![CDATA[<p>Annak idején, amikor a <a href="http://deadlime.hu/2006/04/21/objektum-orientalt-cpp-6/">sorozat hatodik részét</a> megírtam, még azt hittem, hogy vége a sorozatnak. De hatalmas hibát követtem el. Megfeledkeztem a bejárókról. Ezt a hatalmas hiányosságot igyekszem most hirtelen pótolni ennek a bejegyzésnek a keretein belül. Kezdjük is talán a legelején, hogy mi is az a bejáró (iterator)? A <a href="http://kiado.kiskapu.hu/main.php?SHOW_BODY=books&#038;OP=detailed&#038;PROD_ID=41">Nagy Könyv</a> keveset mondó ám annál hangzatosabb definíciója szerint minden bejáró, ami úgy viselkedik, mint egy bejáró. Viselkedését - és operátorait - tekintve a bejáró viszont a mutatókhoz hasonlatos. Hasonlóan lehet növelni illetve csökkenteni (a <code>++</code> és a <code>--</code> operátorokkal) vagy az éppen aktuális elem értékét megkapni a <code>*</code> operátor segítségével. Ellenben amíg van nullpointer addig "semmire" mutató bejáró nincsen.</p>

<p>A bejárók lényegében egy egységes felületet kívánnak nyújtani a különböző adatszerkezetekhez, hogy egyes algoritmusoknak ne kelljen tudnia, hogy például egy zsák adatszerkezet az most tömbösen vagy láncolt listásan lett-e vajon megvalósítva. Ugyebár miért is kéne tudnia? Bizonyos algoritmusoknál ez mindegy is.</p>

<p>A bejárókat meghatározott műveleteik alapján csoportosítani lehet (azt pedig, hogy milyen operátorok vannak definiálva, azt az határozza meg, hogy az egyes operátorok mennyire műveletigényesek - általában csak az alacsony műveletigényű funkciókhoz szokás operátort rendelni, a nagyobbakhoz pedig függvényt). Ez a <a href="http://www.msoe.edu/eecs/ce/courseinfo/stl/">standard template library</a>-ban szépen meg is van téve, ám én erre a részre nem kanyarodnék rá, mivel egyrészt maga megérne jópár bejegyzést (az STL és az STL bejárókkal kapcsolatos része is), másrészt pedig nem szeretném ennyire elbonyolítani a helyzetet. Ezért a korábban már megírt láncolt lista adatszerkezetünkhöz fogok egy bejárót írni. Természetesen amennyire lehetséges tartom magam az STL-ben használt elnevezésekhez és ugyanazok az operátorok itt is ugyanazt a funkciót fogják betölteni (tehát visszakanyarodva az első "bejáró" meghatározásunkhoz, ez egy bejáró lesz, mert bejáróként fog viselkedni :) ).</p>

<p>Szerencsére az eredeti osztályunkat csak két függvénnyel kell kiegészíteni. Az egyik a <code>begin()</code>, ami egy, a lista elején álló bejáróval fog visszatérni. Az <code>end()</code> pedig a lista végén áll.</p>

<pre class="code prettyprint lang-c">typedef cList_const_iterator&lt;T&gt; const_iterator;
typedef cList_iterator&lt;T&gt; iterator;

iterator begin(void)
{
    return *(new iterator(*(list-&gt;next)));
}
iterator end(void)
{
    return *(new iterator(*list));
}</pre>

<p>A mutatók mintájára bejáróból is két fajtánk lesz, egy sima és egy konstans, ahogy az a fenti kódból is látszik. A <code>typedef</code> rész azért egy lényeges dolog (azon kívül, hogy a két függvényt egy csöppnyit szebbé és rövidebbé teszi), mert így <code>cList&lt;T&gt;::iterator it;</code> formában létre tudunk hozni egy <code>cList&lt;T&gt;</code>-beli bejárót (az STL is így viselkedik, ezért tartom magam ehhez). Na, jöhet az izgalmasabb része a dolognak, első körben a <code>cList_iterator</code> osztály:</p>

<pre class="code prettyprint lang-c">template&lt;class T&gt; class cList_const_iterator;

template&lt;class T&gt; class cList_iterator
{
    private:
        listNode&lt;T&gt;* current_item;

        friend class cList_const_iterator&lt;T&gt;;
    public:
        cList_iterator(listNode&lt;T&gt;&amp; value)
        {
            current_item = &amp;value;
        }
        cList_iterator(const cList_iterator&lt;T&gt;&amp; other)
        {
            current_item = other.current_item;
        }
        cList_iterator&lt;T&gt;&amp; operator++()
        {
            current_item = current_item-&gt;next;
            return *this;
        }
        cList_iterator&lt;T&gt;&amp; operator=(cList_iterator&lt;T&gt;&amp; other)
        {
            this-&gt;current_item = other.current_item;
            return *this;
        }
        T&amp; operator*()
        {
            return current_item-&gt;data;
        }
        bool operator==(const cList_iterator&lt;T&gt;&amp; other)
        {
            return (current_item == other.current_item);
        }
        bool operator!=(const cList_iterator&lt;T&gt;&amp; other)
        {
            return (current_item != other.current_item);
        }
};</pre>

<p>Bár a <code>cList_iterator</code>-ral kezdünk, mégis előbb a <code>cList_const_iterator</code>-t kell egy sorban definiálni, az osztályban szereplő friend sor miatt (ami azért kell, hogy majd a <code>const_iterator</code> el tudja érni az <code>iterator</code> private adattagját (ami kell majd a copy konstruktorához, hogy lehessen <code>cList_iterator</code>-ból <code>cList_const_iterator</code>-t csinálni)). A dolog teljesen egyszerű egyébként, a <code>current_item</code> tárolja, hogy épp hogy vagyunk, lépdesni ugyanúgy lépdesünk vele, mint ahogy a láconlt lista kódjában is tettük. Akár a <code>--</code> operátort is meg lehetne írni, mivel a listánk kétirányú volt. Érdemes még odafigyelni arra, hogy a <code>*</code> operátor referenciát ad vissza, tehát (ha minden igaz :D ) szerepelhet egyenlőség bal oldalán (a bejárón keresztül megváltoztatható az aktuális elem értéke). Második kör, a <code>cList_const_iterator</code> osztály. Csak azokat a funkciókat írom le, amivel bővült, illetve amik változtak (azt nem tekintem változásnak, hogy <code>cList_iterator</code> helyett csak <code>cList_const_iterator</code>-t kell írni):</p>

<pre class="code prettyprint lang-c">template&lt;class T&gt; class cList_const_iterator
{
    private:
        const listNode&lt;T&gt;* current_item;
    public:
        cList_const_iterator(const cList_iterator&lt;T&gt;&amp; other)
        {
            current_item = (const listNode&lt;T&gt;*)other.current_item;
        }
        T operator*()
        {
            return current_item-&gt;data;
        }
};</pre>

<p>Az utolsó ami még hiányzik, az egy kis példakód, hogy mit is tudunk kezdeni ezzel a bejáróval, amit épp megírtunk. A lent látható kód a listán való végigmenés rövid, fájdalommentes, átlátható, bejárókat használó kódja:</p>

<pre class="code prettyprint lang-c">cList&lt;int&gt; int_list;

int_list &lt;&lt; 0 &lt;&lt; 1 &lt;&lt; 2 &lt;&lt; 3 &lt;&lt; 4 &lt;&lt; 5 &lt;&lt; 6 &lt;&lt; 7 &lt;&lt; 8 &lt;&lt; 9;

for (cList&lt;int&gt;::const_iterator it = int_list.begin(); it != int_list.end(); ++it) {
    std::cout &lt;&lt; *it &lt;&lt; std::endl;
}
std::cout &lt;&lt; &quot;Lista vége&quot; &lt;&lt; std::endl;</pre>

<p>Ennyit a saját készítésű bejárókról (az STL-ről meg talán a későbbiekben még egy nagyobb lélegzetvételű dolog születhet, ha úgy alakul - addig is ajánlott olvasmány a dologgal kapcsolatban a fentebb említett Nagy Könyv 19. fejezete). További jó iterálást mindenkinek.</p>]]></content:encoded>
			<wfw:commentRss>http://deadlime.hu/2006/12/02/objektum-orientalt-cpp-7/feed/</wfw:commentRss>
		<slash:comments>3</slash:comments>
		</item>
		<item>
		<title>Cpp/Prolog/SML példák 1.</title>
		<link>http://deadlime.hu/2006/04/25/cpp-prolog-sml-peldak-1/</link>
		<comments>http://deadlime.hu/2006/04/25/cpp-prolog-sml-peldak-1/#comments</comments>
		<pubDate>Tue, 25 Apr 2006 19:11:19 +0000</pubDate>
		<dc:creator>Tommey</dc:creator>
				<category><![CDATA[nincs kategória]]></category>
		<category><![CDATA[C++]]></category>
		<category><![CDATA[Prolog]]></category>
		<category><![CDATA[SML]]></category>

		<guid isPermaLink="false">http://deadlime.hu/2006/04/25/cppprologsml-peldak-1/</guid>
		<description><![CDATA[Nemrég kriz kérte, hogy csináljak egy olyan cikket is, ahol C++, Prolog, SML összehasonlítások vannak :) Nos most hirtelen egy jut eszembe, nálunk volt zh példa. Van egy bemenő listánk és ebből kell kiszűrni az első pithagoraszi számhármast.% Prolog % A léptetés miatt kétszer adom át a listát, egyéb segéd- % függvényekkel lehet máshogy is [...]]]></description>
			<content:encoded><![CDATA[<p>Nemrég kriz kérte, hogy csináljak egy olyan cikket is, ahol C++, Prolog, SML összehasonlítások vannak :) Nos most hirtelen egy jut eszembe, nálunk volt zh példa. Van egy bemenő listánk és ebből kell kiszűrni az első pithagoraszi számhármast.</p><pre class="code prettyprint lang-prolog">% Prolog
% A léptetés miatt kétszer adom át a listát, egyéb segéd-
% függvényekkel lehet máshogy is de beépített függvények 
% nincsenek, csak tanítanak néhány alapot, de ezekre most
% nem térnék ki, és nem is alkalmazok.

pith(L,P):- getpith(L,L,P).

% Gyorsan leírom a listákat hogy tiszta legyen, alapvetően 
% kétféleképpen lehet listákat leírni, az első: [A,B], ez 
% egy két elemű lista, ami tulajdonképpen 3 elemű. Na ezt 
% adjátok össze :) szóval, az első, tehát az A az mindig az
% első elem, a B pedig egy másik kételemű lista, aminek első 
% eleme a B, a második eleme pedig a [], tehát az üres lista.
% A második típus a listáknál a [A|B] kinézetű, ez annyit 
% tesz, hogy A a lista első eleme, B pedig az utána lévő 
% összes többi. pl. ha ezt adjuk rá: [1,2,3,4,5] vagyis egy 
% 5 elemű listát akkor az A = 1, és a B = [2,3,4,5] vagyis 
% 4 elemű lista. Ezen kívül még egy elem látható, a '_', 
% ez minden karakter lehet, tehát ez egy olyan, amit 
% figyelmen kívül hagyunk. Ennyit a listák bevezetéséről :)
% A két listát máshogy dolgozom fel, az A,B,C a lista első 
% három eleme mindig. A második lista az első elemen kívül
% mindent tartalmaz, tehát a léptetést szolgálja a mi 
% esetünkben, de mint említettem erre már vannak kifinomultabb
% technikák is, de beépített függvény nincs. Ezen felül a P 
% a visszatérési érték. A ZH-ban egy struktúraként kellett 
% visszaadni a megtalált számhármast, ezért most egy kicsit 
% a struktúrákról is: A struktúrák abban különböznek a 
% függvényektől, hogy nincs testük, tehát pl. p(A,B,C). 
% Függvénynév, argumentumok, és egy '.' :)
% Még egy új elem, amit eddigi prolog tudásotok még nem 
% tartalmaz, hogy prologban az if-then-else így néz ki: 
% ( feltétel -&gt; igaz ág ; hamis ág )

getpith([A,B,C|_],[_|D],P):-   % függvény kezdete 
   (                           % feltétel kezdete
   A &gt; 0 ,                     % A,B,C &gt; 0
   B &gt; 0 , 
   C &gt; 0 , 
   A &lt; B ,                     % A &lt; B &lt; C
   B &lt; C , 
   X is A*A+B*B,               % A*A+B*B=C*C - vizsgálat
   Y is C*C,                   %  előtt a kiértékelődés
   X = Y                       %  miatt két változót használok
   -&gt;                          % igaz ág
   P = p(A,B,C)                % a 3 szám p struktúrában
   ;                           % hamis ág
   getpith(D,D,P)              % a következő 3 elem vizsgálata
   )                           % if-then-else vége
.                              % függvény vége

% Tömörebben: getpith([A,B,C|_],[_|D],P):- (A&gt;0,B&gt;0,C&gt;0,A&lt;B,B&lt;C,X is A*A+B*B,Y is C*C,X=Y-&gt;P=p(A,B,C);getpith(D,D,P)).

% Használat: 
% pith([1,3,5,3,7,24,25,8,7],P).
% Várt eredmény:
% P = p(7,24,25)</pre>
<p>SML-ben most hirtelen nem is tudom van-e comment, nem rémlik, hogy láttam volna, úgyhogy inkább ide írom, a hozzászólásokat :) Tehát SMLben máshogy működnek a listák, egy kicsit ezekről: a listák formailag ugyanolyanok, de a függvényekben másként lehet szétszedni őket, amint látható. Most n1 az első elem, n2 a második, n3 a harmadik, ns pedig az összes többi. Az operátor ami ezek között van op:: egy listába fűzi össze a tagokat, így a léptetés is jóval egyszerűbb, ahogy az else ágnál is látszik; szándékosan nem szedtem szét több sorba, mivel lényegében ugyanaz, mint a prolognál. A további különbségek, hogy itt normális if-then-else szerkezet van, csak ugye még a then-t is ki kell írni :) illetve az andalso a sima 'és' kapcsolatot hivatott jelképezni, and-jellel nem megy a dolog, próbáltam kettővel és hárommal is :D igazából hárommal jó lenne, csak akkor más formában kéne, de erről most nem beszélnék, így egyszerűbb. A prologgal ellentétben itt egy listát adunk vissza, mivel nincs olyan struktúra, mint prologban, és ide nem is kell külön X, és Y a másodfokú egyenlethez, mivel az '='-nél kiértékelődik a két oldal :) Még két újdonság lehet, a függvény végén a '| pith _ = []', ami azt jelenti, hogyha a legelső argumentumra nem illeszkedik a bemenet, akkor egy üres lista lesz az eredmény. Tehát ha n1::n2::n3::ns -re nem négyelemű lista jön, ami lehet 3 érték és egy üres elem, akkor átugrik a másik lehetőségre pith _ -ra, ahol a _ a prologhoz hasonlóan a bármit jelenti. Erről azt hiszem eleget is beszéltem. Aztán pedig a függvényhívást így is el lehet végezni, kicsit rövidebben, mint az SML bevezetőben írtam, tehát nem kell 'val x =' az elejére, ilyenkor azt kapjuk, hogy az 'it'-nek az eredménye amit kaptunk, magyarán, "valami pont annyi amennyi a függvény értéke" :D Az utolsó sor végén pedig láthatjuk hogy ez egy int lista.</p>
<pre class="code prettyprint lang-sml">
fun pith(n1::n2::n3::ns) = ( if n1 &gt; 0 andalso n2 &gt; 0 andalso n3 &gt; 0 andalso n1 &lt; n2 andalso n2 &lt; n3 andalso n1*n1+n2*n2=n3*n3 then [n1,n2,n3] else pith(n2::n3::ns)) | pith _ = [];
&gt; val pith = fn : int list -&gt; int list
pith([1,3,5,3,7,24,25,8,7]);
&gt; val it = [7, 24, 25] : int list
</pre>
<pre class="code prettyprint lang-c">/* C++ megvalósítás */
/* Ennek a működését remélem nem kell ecsetelnem :) próbáltam 
Prologhoz hasonlóan struktúrában visszaadni a pith() 
visszatérési értékét, azt hiszem eléggé jól látható, 
hogy mi is a prolog és sml pozitívuma cpp-vel ellentétben :) 
azt hiszem a listakezelésük egy csöppet veri a cpp-ét, 
legalábbis rövidségben, és hatékonyságban :) */

#include &lt;iostream&gt;

using namespace std;

struct p { int a,b,c; };

p pith(int a, int b, int c) {
   p tmp;
   tmp.a=0;
   tmp.b=0;
   tmp.c=0;
   if(a&gt;0&amp;&amp;b&gt;0&amp;&amp;c&gt;0&amp;&amp;a&lt;b&amp;&amp;b&lt;c&amp;&amp;(a*a+b*b==c*c)) {
      tmp.a=a;
      tmp.b=b;
      tmp.c=c;
   }
   return tmp;
}

int main() {
   int listaelemek[8];
   listaelemek[0]=1;
   listaelemek[1]=3;
   listaelemek[2]=5;
   listaelemek[3]=3;
   listaelemek[4]=7;
   listaelemek[5]=24;
   listaelemek[6]=25;
   listaelemek[7]=8;
   p tmp;
   for(int i=0;listaelemek[i+2]!=0;i++) {
      tmp=pith(listaelemek[i],listaelemek[i+1],listaelemek[i+2]);
      if(tmp.a!=0) { 
         cout &lt;&lt; &quot;p(&quot; &lt;&lt; tmp.a &lt;&lt; &quot;,&quot;;
         cout &lt;&lt; tmp.b &lt;&lt; &quot;,&quot; &lt;&lt; tmp.c &lt;&lt; &quot;)&quot;; 
         break; 
      }
   }
   return 0;
}</pre>
   ]]></content:encoded>
			<wfw:commentRss>http://deadlime.hu/2006/04/25/cpp-prolog-sml-peldak-1/feed/</wfw:commentRss>
		<slash:comments>1</slash:comments>
		</item>
		<item>
		<title>Objektum-orientált C++ VI.</title>
		<link>http://deadlime.hu/2006/04/21/objektum-orientalt-cpp-6/</link>
		<comments>http://deadlime.hu/2006/04/21/objektum-orientalt-cpp-6/#comments</comments>
		<pubDate>Fri, 21 Apr 2006 11:01:03 +0000</pubDate>
		<dc:creator>Nagy Krisztián</dc:creator>
				<category><![CDATA[nincs kategória]]></category>
		<category><![CDATA[C++]]></category>
		<category><![CDATA[objektum-orientált]]></category>
		<category><![CDATA[származtatás]]></category>

		<guid isPermaLink="false">http://deadlime.hu/2006/04/21/objektum-orientalt-cpp-6/</guid>
		<description><![CDATA[Elérkezett hát az idő, hogy megtárgyaljuk az osztályok származtatását és az ezekből adódó problémákat. Első nekifutásra az az érzés fogott el, hogy túl nagy fába vágom a fejszémet, amikor egy bejegyzésben akarok mesélni ezekről a dolgokról. Túl sok, túl összetett és még egy normális példát sem lehet hozzá írni, ami nem túl bonyolult de nem [...]]]></description>
			<content:encoded><![CDATA[<p>Elérkezett hát az idő, hogy megtárgyaljuk az osztályok származtatását és az ezekből adódó problémákat. Első nekifutásra az az érzés fogott el, hogy túl nagy fába vágom a fejszémet, amikor egy bejegyzésben akarok mesélni ezekről a dolgokról. Túl sok, túl összetett és még egy normális példát sem lehet hozzá írni, ami nem túl bonyolult de nem is rugaszkodik el annyira a valóságtól.</p>

<p>Annak idején én egy közlekedési példával lettem bevezetve a származtatás világába. Tegyük fel, hogy van egy személygépkocsi, egy tehergépkocsi, egy kamion, stb. osztályunk. Mindegyik osztályban van valami közös, például, hogy van kormánya, meg van X darab kereke. Ezek miatt a közös részek miatt érdemes őket egy bázisosztályból származtatni. Tehát legyen egy járművek osztályunk, amiben megvan minden közös tulajdonság, ami a járműveket jellemzi és minden egyediséget a belőle származtatott osztályokban valósítunk meg.</p>

<p>Ezzel sikerült elrugaszkodnunk eléggé a valóság talajáról - már ha ez esetben egyáltalán lehet erről beszélni. Térjünk hát át egy kézzel foghatóbb és egyszerűbben kódolhatóbb (mondhatni hétköznapi) problémára, melyet az A C++ programozási nyelv c. könyvben találtam. Tegyük fel, hogy valamilyen cég számára írunk egyfajta alkalmazott-nyilvántartó programot, ahol használunk valami ilyesféle típusokat:</p>

<pre class="code prettyprint lang-c">struct Alkalmazott
{
	std::string vezeteknev;
	std::string keresztnev;
	int fizetes;
};

struct Osztalyvezeto
{
	Alkalmazott alk;
	std::set&lt;Alkalmazott*&gt; csoport;
};</pre>

<p>Az <code>Osztalyvezeto</code> kódjából remekül látszik már így is, hogy az osztályvezető is egy alkalmazott, tehát nála is meg lehet/kell adni az alkalmazottaknál bevezetett mezőket. Viszont ennek a megoldásnak van egy olyan hatalmas hátránya, hogy az <code>Osztalyvezeto</code> típusokra nem használhatjuk azokat a függvényeket, amiket az <code>Alkalmazott</code> típusra írtunk. Több okból sem. Ebből az egyik, hogy például nem létezik <code>Osztalyvezeto.fizetes</code> tag, csak <code>Osztalyvezeto.alk.fizetes</code>. Ez talán még megoldható. De ha egy függvény egy <code>Alkalmazott</code>-ra mutató pointert vár, akkor nem adhatunk neki egy <code>Osztalyvezeto</code>-re mutató pointert. Ebben az esetben legalábbis nem. De ha így írjuk a dolgokat, akkor már igen:</p>

<pre class="code prettyprint lang-c">struct Osztalyvezeto : public Alkalmazott
{
	std::set&lt;Alkalmazott*&gt; csoport;
};</pre>

<p>Ez esetben az <code>Osztalyvezeto</code> osztályt származtattuk az <code>Alkalmazott</code> osztályból, így az <code>Alkalmazott</code> lett az <code>Osztalyvezeto</code> bázisosztálya, így rendelkezik minden tulajdonsággal, amivel az <code>Alkalmazott</code> rendelkezik, valamint <code>Alkalmazott*</code> típusú változónak értékül adhatunk <code>Osztalyvezeto*</code>-ot. Természetesen egy származtatott osztály is lehet bázisosztály így az <code>Osztalyvezeto</code>-ből származtathatjuk az <code>Igazgato</code>-t. Sőt, egy osztályt akár több bázisosztályból is származtathatunk. Az így létrejött kapcsolatrendszert szokás osztályhierarchiának nevezni és irányított gráffal lehet szépen szemléltetni, ahol a nyíl mindig a származtatott osztály felől mutat a bázisosztály felé.</p>

<p>A fenti példának is megvan az a hátránya, hogy ritkán szokás így használni, hogy csak adatszerkezet van függvények nélkül. A függvények behozatala némiképp megzavarja a képet, bár sok változás nem történik. Nézzük ezt a felállást:</p>

<pre class="code prettyprint lang-c">class Alkalmazott
{
	private:
		std::string vezeteknev;
		std::string keresztnev;
		int fizetes;
	public:
		Alkalmazott(const std::string&amp; vnev, const std::string&amp; knev, const int&amp; fiz) : vezeteknev(vnev), keresztnev(knev), fizetes(fiz) {}
		void print() const
		{
			std::cout &lt;&lt; &quot;Név: &quot; &lt;&lt; vezeteknev &lt;&lt; &quot; &quot; &lt;&lt; keresztnev &lt;&lt; std::endl;
			std::cout &lt;&lt; &quot;Fizetés: &quot; &lt;&lt; fizetes &lt;&lt; &quot; Ft&quot; &lt;&lt; std::endl;
		}
};

class Osztalyvezeto : public Alkalmazott
{
	std::set&lt;Alkalmazott*&gt; csoport;

	public:
		Osztalyvezeto(const std::string&amp; vnev, const std::string&amp; knev, const int&amp; fiz) : Alkalmazott(vnev, knev, fiz) {}
		void print() const
		{
			Alkalmazott::print();

			std::cout &lt;&lt; &quot;Csoport:&quot; &lt;&lt; std::endl;
			
			for (std::set&lt;Alkalmazott*&gt;::iterator current = csoport.begin(); current != csoport.end(); ++current) {
				(*current)-&gt;print();
			}
		}
};</pre>

<p>Ami először feltűnik, hogy felülírjuk a már létező <code>print()</code> függvényt a származtatott osztályban (meg belecsempésztem mindkét osztályba egy-egy konstruktort, hogy tudjak működő példát adni pár sorral lejjebb). Ugyanakkor a felülírott függvényt is meghívjuk, ugyanis másként nem tudnánk kiírni a vezeteknev, keresztnev, fizetes mezőket, mivel ezek az <code>Alkalmazott</code> osztály <code>private</code> mezői, tehát csak az <code>Alkalmazott</code> osztályon belül érhetőek el. Ha a bázisosztály <code>private</code> mezője úgy viselkedne a származtatott osztályban, mintha a származtatott osztály sajátja lenne, akkor a private értelmét vesztené, ugyanis bármilyen private mező feloldható lenne egy egyszerű származtatással.</p>

<p>Viszont akármennyire is hihetetlennek tűnhet, de már ez az egyszerű <code>print()</code> utasítás is hordoz magában hibákat. Gondoljuk csak meg, hogy mit csinálhat az alábbi kód:</p>

<pre class="code prettyprint lang-c">int main()
{
	Alkalmazott alk(&quot;Iksz&quot;, &quot;Ipszilon&quot;, 150000);
	Osztalyvezeto oszt(&quot;Adsf&quot;, &quot;Jklé&quot;, 350000);

	Osztalyvezeto* osztp;
	osztp = &amp;oszt;

	Alkalmazott* alkp;
	alkp = &amp;oszt;

	alkp-&gt;print();
}</pre>

<p>Mire számítunk? Természetesen arra, hogy kétszer egymásután ugyanazt olvashatjuk a képernyőn. Ennek ellenére nem ez fog történni, mivel az Alkalmazott* nem tud arról, hogy az <code>Osztalyvezeto</code> objektum felülírta az eredeti <code>print()</code>-et. Vagyis igazából nem is tud az <code>Osztalyvezeto</code> létezéséről, ezért az eredeti, <code>Alkalmazott</code>-ban megadott <code>print()</code>-et hívja meg. Ezt most csúnyán megszívtuk, gondolhatná a kedves olvasó, mivel mi értelme van, hogy <code>Alkalmazott*</code>-nak értékül adhatunk <code>Osztalyvezeto*</code>-ot is, ha nem tudjuk használni az <code>Alkalmazott*</code>-on keresztül az <code>Osztalyvezeto</code> által felüldefiniált függvényeket? De szerencsére van megoldás a virtuális függvények személyében.</p>

<pre class="code prettyprint lang-c">class Alkalmazott
{
	/* ... */
	public:
		/* ... */
		virtual void print() const
		{
			std::cout &lt;&lt; &quot;Név: &quot; &lt;&lt; vezeteknev &lt;&lt; &quot; &quot; &lt;&lt; keresztnev &lt;&lt; std::endl;
			std::cout &lt;&lt; &quot;Fizetés: &quot; &lt;&lt; fizetes &lt;&lt; &quot; Ft&quot; &lt;&lt; std::endl;
		}
};</pre>

<p>Azzal, hogy a print megadása elé tettünk egy virtual szócskát, jeleztük, hogy az adott függvényt a származtatott osztályokban felül lehet bírálni, így egy <code>Alkalmazott*</code> esetén a virtuális függvény megfelelő példánya fog meghívódni. Egy osztálynak lehetnek tisztán virtuális (pure virtual) függvényei is, vagyis a bázisosztályban nem adunk meg semmiféle megvalósítást és a függvényt (maradva a print példájánál) így deklaráljuk:</p>

<pre class="code prettyprint lang-c">class Alkalmazott
{
	/* ... */
	public:
		/* ... */
		virtual void print() const = 0;
		virtual ~Alkalmazott() {}
};</pre>

<p>Így az osztályunkat nem lehet példányosítani (fordítási idejű hibát generál), mivel egy függvénye nincs megvalósítva. Az ilyen osztályokat hívjuk absztrakt osztályoknak. Az absztrakt osztályokat felületként (interface) vagy más osztályok bázisosztályaként tudjuk használni. Egy pure virtual függvényt ha a származtatott osztályban nem adunk meg, akkor pure virtual marad ebből következik, hogy a származtatott osztály is absztrakt osztály lesz. Emellett az absztrakt osztályhoz virtuális destruktor is jár, hogy biztosítsuk a származtatott osztályunk utáni rendrakást.</p>

<p>Ezzel az objektum-orientált C++ világába bevezető sorozat befejező epizódjának végére értünk. Remélem mindenkire ragadt valami a bejegyzések olvasása közben. Sok sikert a gyakorlati alkalmazáshoz.</p>]]></content:encoded>
			<wfw:commentRss>http://deadlime.hu/2006/04/21/objektum-orientalt-cpp-6/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Adatbáziskezelés C/C++ -ban</title>
		<link>http://deadlime.hu/2006/04/16/adatbaziskezeles-c-cpp/</link>
		<comments>http://deadlime.hu/2006/04/16/adatbaziskezeles-c-cpp/#comments</comments>
		<pubDate>Sun, 16 Apr 2006 09:02:18 +0000</pubDate>
		<dc:creator>Polaa</dc:creator>
				<category><![CDATA[nincs kategória]]></category>
		<category><![CDATA[C++]]></category>
		<category><![CDATA[PostgreSQL]]></category>

		<guid isPermaLink="false">http://deadlime.hu/2006/04/16/adatbaziskezeles-cc-ban/</guid>
		<description><![CDATA[Hosszú kihagyás után újra, a megújult deadlime.project-en először végre kézbe veszem a billentyűzetem és egy (szerintem) érdekes témával folytatom itteni pályafutásom. Ez a téma nem lenne más, mint a PostgreSQL adatbázis-kezelő elérése C/C++ programokból. Az adatbázis eléréséhez a libpq áll a rendelkezésünkre. Próbáltam a libpqxx könyvtárat is, de rengeteg gond volt vele, ezért a "gyártó" [...]]]></description>
			<content:encoded><![CDATA[<p>Hosszú kihagyás után újra, a megújult deadlime.project-en először végre kézbe veszem a billentyűzetem és egy (szerintem) érdekes témával folytatom itteni pályafutásom.<br/>
Ez a téma nem lenne más, mint a PostgreSQL adatbázis-kezelő elérése C/C++ programokból.<br/> 
Az adatbázis eléréséhez a libpq áll a rendelkezésünkre. Próbáltam a libpqxx könyvtárat is, de rengeteg gond volt vele, ezért a "gyártó" által biztosított C-s lib-nél maradtam.<br/>
Ha forrásból telepítjük a PgSql-t, vagy windowson a megfelelő helyen pipálunk, akkor azonnal a rendelkezésünkre áll ez a könyvtár. Csak a fordítónak kell megadnunk az elérési utakat. Beállítástól függően #include &#60;libpq-fe.h&#62; vagy #include "libpq-fe.h" formában kell behúzni a forrásfájlunkba.<br/>
Nem célom, hogy minden függvényt bemutassak, arra megfelelőbb a PostgreSQL saját dokumentációja. Csupán azokat szeretném megemlíteni, melyek használat közben a legfontosabbak.</p>

<p>Tehát akkor egy kis kód:</p>
<pre class="code prettyprint lang-c">#include &lt;iostream&gt;
#include &lt;string&gt;
#include &lt;libpq-fe.h&gt;

int main()
{
	// kapcsolódáshoz szükséges adatok
	const std::string	conninfo = &quot;host=localhost port=5432 dbname=polaa user=polaa password=&quot;;
	// a kapcsolatmutató
	PGconn			*conn;
	// az eredménymutató
	PGresult		*res;

	/* kapcsolódás */
	conn = PQconnectdb(conninfo.c_str());
	if (PQstatus(conn) != CONNECTION_OK) 
	{
		std::cout &lt;&lt; &quot;Kapcsolódási hiba: &quot; &lt;&lt; PQerrorMessage(conn) &lt;&lt; std::endl;
		PQfinish(conn);
		return 1;
	}
	
	/* ... */
}</pre>
<p>Először is be kell vezetnünk néhány elengedhetetlen változót. Az adatbázishoz a PGconn *PQconnectdb(const *conninfo) függvénnyel kapcsolódhatunk hasonló módon, mint PHP-ban. A következő ellenőrzés szerintem magáért beszél. <br/>
A ConnStatusType PQstatus(const PGconn *conn) függvénnyel a kapcsolat aktuális állapotáról kaphatunk információt. <br/>
A void PQfinish(const PGconn *conn) függvény szerepe, hogy lezárja a kapcsolatot és felszabadítsa a PGconn által lefoglalt memóriát.</p>
<pre class="code prettyprint lang-c">/* ... */
int main()
{
	/* ... */

	/* parancs */
	res = PQexec(conn, &quot;INSERT INTO teszt VALUES (5, 10)&quot;);
	if (PQresultStatus(res) != PGRES_COMMAND_OK)
	{
		std::cout &lt;&lt; &quot;Parancsvégrehajtási hiba: &quot; &lt;&lt; PQerrorMessage(conn) &lt;&lt; std::endl;
		PQclear(res);
		PQfinish(conn);
		return 1;
	}
	PQclear(res);
	
	/* ... */
}</pre>
<p>A következő fontos függvény a PGresult *PQexec(PGconn *conn, const char *query), mely egy kérést küld a szervernek és egy Pgresult-ban tárolja az eredményt. <br/>
Ezt az eredményt a ExecStatusType PQresultStatus(const PGresult *res) függvénnyel ellenőrizhetjük.  <br/>
A PGresult által lefoglalt memóriát a void PQclear(const PGresult *res) függvénnyel szabadíthatjuk fel. Fontos minden alkalommal meghívni, hogy még véletlenül se maradjon memória szemét hátra a programunk után.</p>
<pre class="code prettyprint lang-c">/* ... */
int main()
{
	/* ... */

	/* lekérdezés */
	res = PQexec(conn, &quot;SELECT * FROM teszt&quot;);
	if (PQresultStatus(res) != PGRES_TUPLES_OK)
	{
		std::cout &lt;&lt; &quot;Lekérdezés hiba: &quot; &lt;&lt; PQerrorMessage(conn) &lt;&lt; std::endl;
		PQclear(res);
		PQfinish(conn);
		return 1;
	}
	/* lekérdezés feldolgozása */
	int rowNum, fieldNum;
	int i, j;

	rowNum		= PQntuples(res);
	fieldNum	= PQnfields(res);

	for (i = 0; i &lt; fieldNum; i++)
	{
		std::cout &lt;&lt; PQfname(res, i) &lt;&lt; &quot;\t&quot;;
	}
	std::cout &lt;&lt; std::endl;

	for (i = 0; i &lt; rowNum; i++)
	{
		for (j = 0; j &lt; fieldNum; j++)
		{
			std::cout &lt;&lt; PQgetvalue(res, i, j) &lt;&lt; &quot;\t&quot;;
		}
		std::cout &lt;&lt; std::endl;
	}
	PQclear(res);

	PQfinish(conn);
	return 0;
}</pre>
<p>A bemutató forrás végére hagytam a lekérdezést. Az eredménytáblában történő navigálást számos függvény könnyíti meg. <br/>
A sorok, illetve oszlopok számát az int PQntuples(const PGresult *res), illetve az int PQnfields(const PGresult *res) függvények adják vissza. <br/>
Az egyes oszlopok nevét a char *PQfname(const PGresult *res, int field_num) adja meg az oszlop indexe alapján (ami természetesen 0-ról indul). Az egyes mezők tartalmát a char *PQgetvalue(const PGresult *res, int tup_num, int field_num) függvény adja meg a PQfname-hez hasonló módon.</p>
<p>Ezekkel az alapfüggvényekkel már nyugodtan lehet kisebb-nagyobb adatbázis műveleteket végezni. Az objektum-orientált megoldást majd egy következő bejegyzésben részletezem.<br/>
A fenti kódot csak windowson próbáltam, mert csak. Fontos megjegyezni, hogy ott a lefordult exe mellé a következő dll-eket kell másolni még a PgSql-ünk bin nevü könyvtárából: comerr32.dll, krb5_32.dll, libiconv-2.dll, libintl-2.dll, libpq.dll.</p>]]></content:encoded>
			<wfw:commentRss>http://deadlime.hu/2006/04/16/adatbaziskezeles-c-cpp/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Objektum-orientált C++ V.</title>
		<link>http://deadlime.hu/2006/04/05/objektum-orientalt-cpp-5/</link>
		<comments>http://deadlime.hu/2006/04/05/objektum-orientalt-cpp-5/#comments</comments>
		<pubDate>Wed, 05 Apr 2006 22:20:02 +0000</pubDate>
		<dc:creator>Nagy Krisztián</dc:creator>
				<category><![CDATA[nincs kategória]]></category>
		<category><![CDATA[C++]]></category>
		<category><![CDATA[objektum-orientált]]></category>
		<category><![CDATA[sablonok]]></category>

		<guid isPermaLink="false">http://deadlime.hu/2006/04/05/objektum-orientalt-cpp-5/</guid>
		<description><![CDATA[Annak idején ott hagytuk abba, hogy elkészítettünk egy új adatszerkezetet, ami nem más volt mit a láncolt lista. Elkészítettünk hozzá egy használható felhasználói felületet, aztán elkezdhetünk gondolkozni azon, hogy mi van, ha mi nem egyszerű inteket akarunk abban a listában tárolni, hanem valami teljesen mást? Mert hát miért is akarnánk az inteknél leragadni, amikor annyi [...]]]></description>
			<content:encoded><![CDATA[<p>Annak idején ott hagytuk abba, hogy elkészítettünk egy új adatszerkezetet, ami nem más volt mit a láncolt lista. Elkészítettünk hozzá egy használható felhasználói felületet, aztán elkezdhetünk gondolkozni azon, hogy mi van, ha mi nem egyszerű <code>int</code>eket akarunk abban a listában tárolni, hanem valami teljesen mást? Mert hát miért is akarnánk az <code>int</code>eknél leragadni, amikor annyi minden van még.</p>

<p>Ilyen megközelítésben természetesen eléggé használhatatlannak bizonyul a kódunk, mert csak arra az egy típusra működik megfelelően. Még szerencse, hogy itt vannak a sablonok, amikkel ez a probléma relatíve egyszerűen áthidalható.</p>

<p>Bevezetésnek kezdjünk valami egyszerű függvénnyel, mondjuk amivel össze tudunk adni mindenféle objektumot, aminek meg van adva a <code>+</code> operátora (tény, hogy a példa cseppet értelmetlen, de mondjuk gondoljunk akkor egy <code>sort()</code> függvényre, aminek végülis mindegy, hogy milyen adatokat hasonlít össze, amíg annak az adatszerkezetnek megvan a <code>&lt;</code> vagy <code>&gt;</code> operátora).</p>

<pre class="code prettyprint lang-c">#include &lt;string&gt;
#include &lt;iostream&gt;

template&lt;class T&gt; T Add(const T&amp; o1, const T&amp; o2)
{
    return o1 + o2;
}

int main()
{
    int i1 = 1;
    int i2 = 2;
    int i3 = Add(i1, i2);
    std::cout &lt;&lt; i3 &lt;&lt; std::endl;

    std::string s1 = &quot;abc&quot;;
    std::string s2 = &quot;xyz&quot;;
    std::string s3 = Add(s1, s2);
    std::cout &lt;&lt; s3 &lt;&lt; std::endl;
}</pre>

<p>Ennyi az egész, tulajdonképpen csak a választott függvényünk elé tesszük, hogy <code>template&lt;class T&gt;</code> és mindenhol, ahol egyébként mondjuk int-et írtunk volna, ott T-t használunk. Hasonló a helyzet az osztályok esetében is, nézzük először a már megírt cList.h fájlunk sablonosított változatát.</p>

<pre class="code prettyprint lang-c">#ifndef __CLIST_H__
#define __CLIST_H__

template&lt;class T&gt; struct listNode
{
    listNode&lt;T&gt; *prev;
    listNode&lt;T&gt; *next;
    T data;

    listNode()
    {
        next = prev = this;
    }
    listNode(const T&amp; num)
    {
        next = prev = this;
        data = num;
    }
};

template&lt;class T&gt; class cList
{
    private:
        listNode&lt;T&gt;* list;

        void Create(void);
        void Destroy(void);

        void Remove(listNode&lt;T&gt;* target);
        listNode&lt;T&gt;* Get(listNode&lt;T&gt;* target);
    public:
        cList(void);
        cList(const cList&lt;T&gt; &amp;other);
        ~cList(void);

        class E_OUTOFMEMORY {};
        class E_INVALIDITEM {};

        void left_insert(listNode&lt;T&gt;* target, listNode&lt;T&gt;* data);
        void right_insert(listNode&lt;T&gt;* target, listNode&lt;T&gt;* data);
        listNode&lt;T&gt;* get_first(void);
        listNode&lt;T&gt;* get_last(void);
        listNode&lt;T&gt;* Search(const T&amp; number);

        cList&lt;T&gt;&amp; operator+(const cList&lt;T&gt;&amp; other);
        cList&lt;T&gt;&amp; operator=(const cList&lt;T&gt;&amp; other);
        cList&lt;T&gt;&amp; operator&gt;&gt;(T&amp; number);
        cList&lt;T&gt;&amp; operator&gt;&gt;(listNode&lt;T&gt;* pointer);
        cList&lt;T&gt;&amp; operator&lt;&lt;(const T&amp; number);
        cList&lt;T&gt;&amp; operator&lt;&lt;(listNode&lt;T&gt;* pointer);
};</pre>

<p>Pár <code>&lt;T&gt;</code>-től talán még megszabadulhatnánk, ha a <code>listNode</code> osztályt a <code>cList</code> osztályon belül adnánk meg, de most már mindegy (egy kis gyakorlás gyanánt mindenki megcsinálhatja magának). Most, hogy volt egy kis szünet, mindenki kifújta magát, visszatérhetünk az osztály metódusainak kibontogatására (maradunk a cList.h-ban):</p>

<pre class="code prettyprint lang-c">template&lt;class T&gt; void cList&lt;T&gt;::Create(void)
{
    list = new listNode&lt;T&gt;();
    if (!list) throw E_OUTOFMEMORY();
 
    list-&gt;next = list;
    list-&gt;prev = list;
    return;
}

template&lt;class T&gt; void cList&lt;T&gt;::Destroy(void)
{
    while (list-&gt;prev != list) {
        Remove(list-&gt;prev);
    }
    return;
}

template&lt;class T&gt; void cList&lt;T&gt;::Remove(listNode&lt;T&gt;* target)
{
    listNode&lt;T&gt;* tmp = Get(target);
    delete tmp;
    return;
}

template&lt;class T&gt; listNode&lt;T&gt;* cList&lt;T&gt;::Get(listNode&lt;T&gt;* target)
{
    target-&gt;prev-&gt;next = target-&gt;next;
    target-&gt;next-&gt;prev = target-&gt;prev;
    target-&gt;prev = target;
    target-&gt;next = target;
    return target;
}

template&lt;class T&gt; cList&lt;T&gt;::cList(void)
{
    Create();
}

template&lt;class T&gt; cList&lt;T&gt;::cList(const cList&lt;T&gt;&amp; other)
{
    Create();
 
    listNode&lt;T&gt;* tmp = other.list-&gt;next;
    while (tmp != other.list) {
        listNode&lt;T&gt;* node = new listNode&lt;T&gt;(tmp-&gt;data);
        if (!node) throw E_OUTOFMEMORY();
 
        this-&gt;left_insert(this-&gt;list, node);
        tmp = tmp-&gt;next;
    }
}

template&lt;class T&gt; cList&lt;T&gt;::~cList(void)
{
    Destroy();
    delete list;
}

template&lt;class T&gt; void cList&lt;T&gt;::left_insert(listNode&lt;T&gt;* target, listNode&lt;T&gt;* data)
{
    data-&gt;prev = target-&gt;prev;
    data-&gt;next = target;
    target-&gt;prev-&gt;next = data;
    target-&gt;prev = data;
    return;
}
template&lt;class T&gt; void cList&lt;T&gt;::right_insert(listNode&lt;T&gt;* target, listNode&lt;T&gt;* data)
{
    data-&gt;prev = target;
    data-&gt;next = target-&gt;next;
    target-&gt;next-&gt;prev = data;
    target-&gt;next = data;
    return;
}

template&lt;class T&gt; listNode&lt;T&gt;* cList&lt;T&gt;::get_first(void)
{
    if (list-&gt;next == list) throw E_INVALIDITEM();
    return Get(list-&gt;next);
}
template&lt;class T&gt; listNode&lt;T&gt;* cList&lt;T&gt;::get_last(void)
{
    if (list-&gt;prev == list) throw E_INVALIDITEM();
    return Get(list-&gt;prev);
}

template&lt;class T&gt; listNode&lt;T&gt;* cList&lt;T&gt;::Search(const T&amp; number)
{
    listNode&lt;T&gt;* tmp = list-&gt;next;
    while (number != tmp-&gt;data &amp;&amp; tmp != list) {
        tmp = tmp-&gt;next;
    }
    if (tmp == list) throw E_INVALIDITEM();
    return tmp;
}

template&lt;class T&gt; cList&lt;T&gt;&amp; cList&lt;T&gt;::operator+(const cList&lt;T&gt;&amp; other)
{
    listNode&lt;T&gt;* tmp = other.list-&gt;next;
    while (tmp != other.list) {
        listNode&lt;T&gt;* node = new listNode&lt;T&gt;(tmp-&gt;data);
        if (!node) throw E_OUTOFMEMORY();
 
        this-&gt;left_insert(this-&gt;list, node);
        tmp = tmp-&gt;next;
    }
}
template&lt;class T&gt; cList&lt;T&gt;&amp; cList&lt;T&gt;::operator=(const cList&lt;T&gt;&amp; other)
{
    if (this == &amp;other) return *this;
    this-&gt;Destroy();
 
    listNode&lt;T&gt;* tmp = other.list-&gt;next;
    while (tmp != other.list) {
        listNode&lt;T&gt;* node = new listNode&lt;T&gt;(tmp-&gt;data);
        if (!node) throw E_OUTOFMEMORY();
 
        this-&gt;left_insert(this-&gt;list, node);
        tmp = tmp-&gt;next;
    }
    return *this;
}

template&lt;class T&gt; cList&lt;T&gt;&amp; cList&lt;T&gt;::operator&gt;&gt;(T&amp; number)
{
    number = get_last()-&gt;data;
    return *this;
}
template&lt;class T&gt; cList&lt;T&gt;&amp; cList&lt;T&gt;::operator&gt;&gt;(listNode&lt;T&gt;* pointer)
{
    pointer = get_last();
    return *this;
}
 
template&lt;class T&gt; cList&lt;T&gt;&amp; cList&lt;T&gt;::operator&lt;&lt;(const T&amp; number)
{
    listNode&lt;T&gt;* tmp = new listNode&lt;T&gt;(number);
    if (!tmp) throw E_OUTOFMEMORY();
 
    left_insert(list, tmp);
    return *this;
}
template&lt;class T&gt; cList&lt;T&gt;&amp; cList&lt;T&gt;::operator&lt;&lt;(listNode&lt;T&gt;* pointer)
{
    left_insert(list, pointer);
    return *this;
}

#endif</pre>

<p>Nincs más hátra, mint egy megfelelő main.cpp-vel tesztelni ezt a rengeteg kódot, hogy egyáltalán működik-e ez az egész:</p>

<pre class="code prettyprint lang-c">#include &lt;string&gt;
#include &lt;iostream&gt;

#include &quot;cList.h&quot;

int main()
{
        cList&lt;int&gt; list1;
        list1 &lt;&lt; 1 &lt;&lt; 2 &lt;&lt; 3 &lt;&lt; 4 &lt;&lt; 5;
        int num;
        list1 &gt;&gt; num;
        std::cout &lt;&lt; num &lt;&lt; std::endl;

        cList&lt;char&gt; list2;
        list2 &lt;&lt; 'a' &lt;&lt; 'b' &lt;&lt; 'c' &lt;&lt; 'd' &lt;&lt; 'e';
        char chr;
        list2 &gt;&gt; chr;
        std::cout &lt;&lt; chr &lt;&lt; std::endl;

        cList&lt;std::string&gt; list3;
        list3 &lt;&lt; &quot;alma&quot; &lt;&lt; &quot;barack&quot; &lt;&lt; &quot;citrom&quot; &lt;&lt; &quot;dinnye&quot; &lt;&lt; &quot;eper&quot;;
        std::string str;
        list3 &gt;&gt; str;
        std::cout &lt;&lt; str &lt;&lt; std::endl;
}</pre>

<p>A fenti kód lefordítása majd futtatása után keletkezett kimenet legjobb esetben az, hogy 5, e, eper (mindegyik új sorban). Ezzel a sablonizációs bejegyzés végére is értünk, a legközelebbi alkalommal származtatni fogunk, ha a C++ istenei is így akarják.</p>]]></content:encoded>
			<wfw:commentRss>http://deadlime.hu/2006/04/05/objektum-orientalt-cpp-5/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Objektum-orientált C++ IV.</title>
		<link>http://deadlime.hu/2006/04/05/objektum-orientalt-cpp-4/</link>
		<comments>http://deadlime.hu/2006/04/05/objektum-orientalt-cpp-4/#comments</comments>
		<pubDate>Wed, 05 Apr 2006 20:17:38 +0000</pubDate>
		<dc:creator>Nagy Krisztián</dc:creator>
				<category><![CDATA[nincs kategória]]></category>
		<category><![CDATA[C++]]></category>
		<category><![CDATA[láncolt lista]]></category>
		<category><![CDATA[objektum-orientált]]></category>

		<guid isPermaLink="false">http://deadlime.hu/2006/04/05/objektum-orientalt-cpp-4/</guid>
		<description><![CDATA[Abban a szerencsétlen helyzetben hagytuk abba legutóbb, hogy a left_insert() függvény hiányzott és a szegény objektumnak nem volt felhasználói felülete. De talán abban egyet érthetünk, hogy így is elég hosszúra nyúlt az előző bejegyzés, meg nekem se volt túl sok kedvem hajnali nem tudom hány órakor még a maradék részt kifejteni.Ami késik, gyakran múlik, de [...]]]></description>
			<content:encoded><![CDATA[<p>Abban a szerencsétlen helyzetben hagytuk abba legutóbb, hogy a <code>left_insert()</code> függvény hiányzott és a szegény objektumnak nem volt felhasználói felülete. De talán abban egyet érthetünk, hogy így is elég hosszúra nyúlt az előző bejegyzés, meg nekem se volt túl sok kedvem hajnali nem tudom hány órakor még a maradék részt kifejteni.<br/>Ami késik, gyakran múlik, de most kivételesen nem. Szóval itt az idő, itt a hely, hogy a félbehagyott osztály elnyerje (még messze nem) végleges formáját.</p>

<h3>Felhasználói felület</h3>

<p>Mint ahogy már az első bejegyzésben is elmeséltem, a <code>private</code> és <code>public</code> blokkok tárgyalásánál, a felhasználói felület jó dolog, mivel megszabhatjuk vele, hogy a felhasználó milyen módon férhet hozzá az objektum adataihoz, milyen módon használhatja magát az osztályt. Kezdjük a sort a már annyiszor emlegetett <code>left_insert()</code>-tel:</p>

<pre class="code prettyprint lang-c">void cList::left_insert(listNode* target, listNode* data)
{
    data-&gt;prev = target-&gt;prev;
    data-&gt;next = target;
    target-&gt;prev-&gt;next = data;
    target-&gt;prev = data;
    return;
}</pre>

<p><img id="image27" src="/wp-content/uploads/2006/04/oop-cpp-3.gif" alt="oop-cpp-3.gif" class="post-image image-right"/>Jaj, de jó. Ismét egy szép hosszú sor mutató állítgatás. Lehet sejteni, hogy mi is fog következni. Igen, rajzolni fogok. Vagyis már rajzoltam, az eredmény itt jobbra látható a zagyvaságom mellett (stílusosan, mivel ez egy balos beillesztés).<br/>Kis képmagyarázat mielőtt belevágnánk: minden két sor egy-egy sort valósít meg a kódból (a függvény megadását, a return; utasítást és a lezáró zárójelet kihagyva). A jobb felső elem, amihez képest balra szúrjuk be a jobb alsó elemet. Tehát, az első két (kód)sorban csak annyit csinálunk, hogy a beszúrandó listaelem két mutatóját (először a hátrafelé, aztán az előrefelé mutatót) ráállítjuk a célelem előtti elemre, illetve magára a célelemre. Aztán jön az izgi rész, amikor is megbontjuk magát a listát, és befűzzük az elemünket. Először a célelem visszafelé mutatója által mutatott objektum előrefelé mutató mutatóját állítjuk rá a befűzendő elemre, majd a célelem visszafelé mutatóját.<br/>Figyelem! A képen ez a két lépés (szándékosan) fel van cserélve, hogy rajzolási szempontból könnyebb legyen ábrázolnom a dolgot (így nem kellett kereszteznem két mutatót, ami még átláthatatlanabbá tenné az ábrát).</p>

<p>Huhh, haladunk ezerre. Következhet a <code>right_insert()</code>, ami nem okoz majd túl nagy meglepetéseket, ezért különösebb kommentárt nem is fűznék hozzá (igen, képet sem, szóval mindenki megkönnyebbülhet), beszéljen inkább a kód, meg talán az előző magyarázat/kép hatására egyértelmű is lesz a dolog:</p>

<pre class="code prettyprint lang-c">void cList::right_insert(listNode* target, listNode* data)
{
    data-&gt;prev = target;
    data-&gt;next = target-&gt;next;
    target-&gt;next-&gt;prev = data;
    target-&gt;next = data;
    return;
}</pre>

<p>Semmi meglepő, semmi meghökkentő. Jöjjön két függvény, amivel adatokat szedhetünk ki a listából ("név" szerint az első és az utolsó elemet):</p>

<pre class="code prettyprint lang-c">listNode *cList::get_first(void)
{
    if (list-&gt;next == list) throw E_INVALIDITEM();
    return Get(list-&gt;next);
}
listNode* cList::get_last(void)
{
    if (list-&gt;prev == list) throw E_INVALIDITEM();
    return Get(list-&gt;prev);
}</pre>

<p>Ismét látható, hogy mennyire hasznos tud lenni a kétirányú, ciklikus fejelemes lista. Rosszabb esetekben kénytelenek lennénk végigmenni az egész listán, hogy az utolsó elemet ki tudjuk szedni. Vagy kivételként kellene kezelni az utolsó elemet, mert a mutatója (vagy az egyik mutatója) nullpointer. De szerencsére nem kell, így meg is vagyunk a dologgal. Ezekkel az eszközökkel már nagyjából tudunk mit kezdeni a listával, de a felület a megvalósítandó feladattól függően változhat. Minden esetre én még írtam bele egy <code>Search()</code> függvényt is, biztos ami biztos:</p>

<pre class="code prettyprint lang-c">listNode* cList::Search(const int&amp; number)
{
    listNode* tmp = list-&gt;next;
    while (number != tmp-&gt;data &amp;&amp; tmp != list) {
        tmp = tmp-&gt;next;
    }
    if (tmp == list) throw E_INVALIDITEM();
    return tmp;
}</pre>

<p>A keresett elemre mutató mutatóval tér vissza, vagy egy kivételt dob, ha nem találja a megadott elemre. Nem egy lényeges dolog, főleg ha szükség sincs rá, mindenesetre sok vizet nem zavar. Jöjjön valami - relatíve - izgalmasabb dolog: újra operátorokat fogunk írni.</p>

<h3>Lista operátorok</h3>

<p>Mint azt az általános operátoros leírásnál említettem, mindig törekedjünk arra, hogy az operátor valami rá jellemző dolgot hajtson végre. Extrém példaként felhozhatnám azt, hogy mondjuk a - operátort és a + operátort a komplex számoknál felcseréli valaki. Szegény programozó, aki meg akarja használni az objektumot, csak les, hogy mi a fene van. Persze mindenki azt csinál, amit akar, de nem árt az ilyen íratlannak mondható "szabályokra" is ügyelni.</p>

<p>Elsőként a + operátor segítségével fogunk két listát összefűzni. A kód igazából nem olyan hatékony, mint amilyen lenni tudna. Ha például a másik objektumra nem lenne szükségünk, akkor egyszerűen a mi objektumunk végét megbontanánk és hozzácsatolnánk a másik objektumot, vigyázva arra, hogy a fejelemet ne vegyük bele a játékba. Így se lesz sokkal bonyolultabb, csak végigmegyünk a másik objektumon, és szépen hozzáadogatjuk a listánk végére az elemeket (hasonlít egy picit a dolog a copy konstruktorhoz):</p>

<pre class="code prettyprint lang-c">cList&amp; cList::operator+(const cList&amp; other)
{
    listNode* tmp = other.list-&gt;next;
    while (tmp != other.list) {
        listNode* node = new listNode(tmp-&gt;data);
        if (!node) throw E_OUTOFMEMORY();

        this-&gt;left_insert(this-&gt;list, node);
        tmp = tmp-&gt;next;
    }
}</pre>

<p>Következőnek jöhet az egyenlőség operátor. Működését tekintve csak annyit, hogy először kiürítjük a listát, majd a másik lista elemeit átmásoljuk a mi listánkba (copy konstruktorhoz és a + operátorhoz hasonlóan). Az első feltétel meg azért szükséges, hogy ha saját magát adjuk értékül a listának, akkor abból se legyen para.</p>

<pre class="code prettyprint lang-c">cList&amp; cList::operator=(const cList&amp; other)
{
    if (this == &amp;other) return *this;
    this-&gt;Destroy();

    listNode* tmp = other.list-&gt;next;
    while (tmp != other.list) {
        listNode* node = new listNode(tmp-&gt;data);
        if (!node) throw E_OUTOFMEMORY();

        this-&gt;left_insert(this-&gt;list, node);
        tmp = tmp-&gt;next;
    }
    return *this;
}</pre>

<p>Már csak két operátor van, amit meg fogok valósítani, a &lt;&lt; operátor és párocskája a &gt;&gt;. Lényegi haszna nem lesz egyiknek sem, tulajdonképpen csak hasznos álnevekként funkcionálnak majd a végére beszúrás és az utolsó elem kiszedése számára.</p>

<pre class="code prettyprint lang-c">cList&amp; cList::operator&gt;&gt;(int&amp; number)
{
    number = get_last()-&gt;data;
    return *this;
}
cList&amp; cList::operator&gt;&gt;(listNode* pointer)
{
    pointer = get_last();
    return *this;
}

cList&amp; cList::operator&lt;&lt;(const int&amp; number)
{
    listNode* tmp = new listNode(number);
    if (!tmp) throw E_OUTOFMEMORY();

    left_insert(list, tmp);
    return *this;
}
cList&amp; cList::operator&lt;&lt;(listNode* pointer)
{
    left_insert(list, pointer);
    return *this;
}</pre>

<p>A két plusz függvény tényleg csak a kódot teszi szemléletesebbé, átláthatóbbá. Bár ez a két dolog sosem lehet "csak" tényező. Legalább is nekem mindig fontos volt, hogy két-három hónap után is tudjam, hogy mit csinál az általam írt kód, és ezt eddig a Perl kivételével minden nyelvben sikerült is megtennem. :)<br/>Pár példa a használatra:</p>

<pre class="code prettyprint lang-c">cList lista;
lista &lt;&lt; 6 &lt;&lt; 7 &lt;&lt; 1 &lt;&lt; 12 &lt;&lt; 23;
int szam;
lista &gt;&gt; szam;</pre>

<p>Amint az látszik is, eléggé szemléletes. Először a 6-ot, 7-et, 1-et, 12-t, 23-at beletesszük a listába, majd kiszedjük az utolsó elemet (vagyis a szam értéke a végén 23 lesz).</p>

<p>Ezzel végére is értünk a mai napra rendelt dolgoknak. A sablonok ismét a csúszás áldozatává válnak, cserében viszont senki mással nem kell megosztaniuk majd a következő - szám szerint az ötödik - bejegyzést. Addig is további jó próbálkozást.</p>]]></content:encoded>
			<wfw:commentRss>http://deadlime.hu/2006/04/05/objektum-orientalt-cpp-4/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Objektum-orientált C++ III.</title>
		<link>http://deadlime.hu/2006/04/05/objektum-orientalt-cpp-3/</link>
		<comments>http://deadlime.hu/2006/04/05/objektum-orientalt-cpp-3/#comments</comments>
		<pubDate>Wed, 05 Apr 2006 20:11:02 +0000</pubDate>
		<dc:creator>Nagy Krisztián</dc:creator>
				<category><![CDATA[nincs kategória]]></category>
		<category><![CDATA[C++]]></category>
		<category><![CDATA[láncolt lista]]></category>
		<category><![CDATA[objektum-orientált]]></category>

		<guid isPermaLink="false">http://deadlime.hu/2006/04/05/objektum-orientalt-cpp-3/</guid>
		<description><![CDATA[Ahogy ígértem, itt a harmadik rész is. Mint már az előző ajánlóban említettem, egy adatok tárolására alkalmas szerkezetű objektumot fogunk elkészíteni. Hogy a jövőben elkerüljem az ilyen nyakatekert mondatokat, nevezzük csak a dolgot "láncolt listának". Így gondolom már több embernek ismerős lehet a dolog. Ismét hanyagolnám a további bevezető rizsázást, klattyanjunk a tovább gombra. Az [...]]]></description>
			<content:encoded><![CDATA[<p>Ahogy ígértem, itt a harmadik rész is. Mint már az előző ajánlóban említettem, egy adatok tárolására alkalmas szerkezetű objektumot fogunk elkészíteni. Hogy a jövőben elkerüljem az ilyen nyakatekert mondatokat, nevezzük csak a dolgot "láncolt listának". Így gondolom már több embernek ismerős lehet a dolog. Ismét hanyagolnám a további bevezető rizsázást, klattyanjunk a tovább gombra.</p>

<p><img id="image24" src="/wp-content/uploads/2006/04/oop-cpp-1.gif" alt="oop-cpp-1.gif" class="post-image image-left"/>Az első képen gyönyörűen látszik a tömb (felül) és a láncolt lista (alul). Mi is a gondunk a szimpla tömbbel? Csak fix méretben foglalhatjuk le. Annyira fix méretben, hogy már a fordításkor tudnunk kell, hogy mekkorát szeretnénk. De ez csak egy gond. Egy másik gond, hogy ha nem egy szimpla int-et vagy hasonlóan egyszerű objektumot, hanem valami szép nagy dolgot pakolunk bele, és azt szeretnénk rendezni, az ugye nem kis erőforrásigényű, ahogy cserélgeti az objektumokat a memóriaterületen, hogy sorban legyenek. Perszer erre lehet azt mondani, hogy a kriz az hülye, mert miért nem objektumokra mutató mutatókból csinál tömböt, és akkor csak a mutatókat kell mozgatnia. No igen, ez egy fokkal jobb ötlet, és azt a problémánkat is megolja, hogy fordítási időben kell tudnunk a tömb méretét. Elég a tömb lefoglalásakor akár dinamikusan egy változóban tudni a méretet. A probléma még mindig probléma, hogy ha azt a fix méretet túllépjük, akkor az gáz.</p>

<p>Itt jön a képbe a láncolt lista. A szerkezet lényege, hogy egy listaelem egy adatrészből és egy mutatórészből áll. Pontosítok: egy listaelem egy adatrészből és legalább egy mutatórészből áll. Miért jó ez? Egyrészről azért, mert a listaelemeket dinamikusan, a futási idő alatt foglalgatjuk le, felső határ csak a memória mérete, nem pedig egy előre meghatározott szám. Másrészről pedig itt is megvan az az előny, hogy csak a pointereket kell új címre állítani ahhoz, hogy rendezni tudjuk a listánkat. Izgi, mi? :)</p>

<p>Hogy ne legyen ilyen egyszerű a helyzet, mi egy fejelemes, kétirányú, ciklikus láncolt listát fogunk csinálni. ez azt jelenti, hogy a listaelemben két mutató van, amiből az egyik az előző, a másik a következő elemre fog mutatni (ezért kétirányú), a lista első eleme nem tartalmaz adatot, az csak azért van hogy az első elem beszúrása és az utolsó elem törlése jóval könnyebb legyen (tehát fejelemes) és az utolsó elem "következő elem" mutatója nem nullpointer, hanem a fejelemre mutat (ugyanígy a fejelem "előző elem" mutatója az utolsó elemre mutat). Kezdjük talán a dolog egyszerűbb végénél, a listaelem szerkezetének a megvalósításánál:</p>

<pre class="code prettyprint lang-c">struct listNode
{
    listNode* prev;
    listNode* next;
    int data;

    listNode()
    {
        next = prev = this;
    }
    listNode(const int&amp; num)
    {
        next = prev = this;
        data = num;
    }
};</pre>

<p>Csoddálatos. Értelem szerűen van egy prev mutató az előző elemre, egy next mutató a következő elemre és egy data, amiben az adatokat tároljuk. Itt az ideje, hogy magának a listának is nekiálljunk. A dolog végtelenül egyszerű, szükségünk lesz egy <code>listNode*</code> változóra, ami "tartani" fogja a lista fejelemét, egy befűző és egy kifűző függvényre, amivel új elemeket szúrhatunk be, illetve létezőket vehetünk ki.</p>

<pre class="code prettyprint lang-c">class cList
{
    private:
        // A lista fejelemére mutató pointer
        listNode* list;

        // Üres lista létrehozása
        void Create(void);

        // Lista kiürítése
        void Destroy(void);

        // target című elem törlése
        void Remove(listNode* target);

        // target című elem kifűzése
        listNode* Get(listNode* target);
    public:
        // Konstruktor
        cList(void);

        // Copy Konstruktor
        cList(const cList&amp; other);

        // Destruktor
        ~cList(void);

        // Kivétel osztályok
        class E_OUTOFMEMORY {};
        class E_INVALIDITEM {};

        void left_insert(listNode* target, listNode* data) {}
};</pre>

<p>Ennyi egyenlőre elég is lesz, bár az objektum kezelőfelülete még a tervezés szintjén sincs kész (a <code>left_join()</code>-t leszámítva, ami csak azér került bele (üresen), hogy leforduljon a kód, majd a negyedik részben lesz rendesen kifejtve), de azzal ráérünk később is foglalkozni. Kezdjük akkor sorban a megvalósítást, először a <code>Create()</code> függvénnyel, ami létrehozza az üres listát (amiben csak a fejelem van).</p>

<pre class="code prettyprint lang-c">void cList::Create(void)
{
    list = new listNode();
    if (!list) throw E_OUTOFMEMORY();

    list-&gt;next = list;
    list-&gt;prev = list;
    return;
}</pre>

<p>A <code>cList::</code> előtag annak köszönhető, hogy az osztály definícióján kívül van megvalósítva a függvény. Gondolom nem annyira ismeretlen eljárás ez. Az objektum szerkezete megy a fejelembe (.h vagy .hpp), a többi meg az ugyanolyan nevű .cpp fájlba. Áttérhetünk a <code>Destroy()</code> függvényre, ami a fejelemen kívül minden elemet töröl a listából.</p>

<pre class="code prettyprint lang-c">void cList::Destroy(void)
{
    while (list-&gt;prev != list) {
        Remove(list-&gt;prev);
    }
    return;
}</pre>

<p>Rettentő cselesen a <code>Remove()</code> függvényt használtam a dologhoz, így tulajdonképpen egyesével kifűzve az összes elemet a listából, mígnem a fejelem prev mutatója meg nem egyezik a lista fejelemének a címével. Ahogy illik, a <code>Remove()</code> megvalósításával folytatom a sort. Lassan, de biztosan közeledünk a vége felé... :)</p>

<pre class="code prettyprint lang-c">void cList::Remove(listNode* target)
{
    listNode* tmp = Get(target);
    delete tmp;
    return;
}</pre>

<p>Ismét továbbadjuk a dolog megvalósítását egy másik függvénynek, a <code>Get()</code>-nek, ami így is, úgy is kifűzi az elemet, akkor miért ismételnénk meg ugyanazt a kódot még egyszer a <code>Remove()</code>-ban is? Tehát, a <code>Get()</code>-tel kifűzetjük, majd a kapott elemet töröljük. Nna, nézzük azt a <code>Get()</code>-et, ha már egyszer ennyi minden épül rá:</p>

<pre class="code prettyprint lang-c">listNode* cList::Get(listNode* target)
{
    target-&gt;prev-&gt;next = target-&gt;next;
    target-&gt;next-&gt;prev = target-&gt;prev;
    target-&gt;prev = target;
    target-&gt;next = target;
    return target;
}</pre>

<p><img id="image25" src="/wp-content/uploads/2006/04/oop-cpp-2.gif" alt="oop-cpp-2.gif" class="post-image image-left"/>Nos, ez egy nem egyszerű dolog. Igazából egyszerű, csak leírni lenne túl bonyolult, inkább veszem a bátorságot és rajzolok egy ábrát hozzá. Egy "jó" ábra felér egy bekezdésnyi szöveggel. Mindenesetre az ábrát is megmagyarázom inkább. Fő a biztonság. Szóval, a kép első sorában az alaphelyzetet látjuk. A második sor a függvény első sorának hatását hivatott szemléltetni, azaz a kifűzendő listaelem előtti elemnek a következő elemre mutató mutatóját átállítjuk a kifűzendő elem utáni elemre. A kép harmadik sorának lényege ugyanez, csak fordítva, mivel a kifűzendő elem utáni elem előző elemre mutató mutatóját állítjuk a kifűzendő elem előtti elemre. Így a lista maga már nem függ a kifűzendő elemtől, mindenesetre a biztonság kedvéért a két mutatóját saját magára állítjuk (a függvény utolsó két mutató állítása). Végül visszatérünk a kifűzött elem mutatójával. Ezzel le is tudtuk az objektum private részét, jöhet a public:</p>

<pre class="code prettyprint lang-c">cList::cList(void)
{
    Create();
}</pre>

<p>Egyszerűbb nem is lehetne, csak a <code>Create()</code>-et hívjuk, meg hogy legyen egy üres listánk. Nézzük a copy konstruktort:</p>

<pre class="code prettyprint lang-c">cList::cList(const cList&amp; other)
{
    Create();

    listNode* tmp = other.list-&gt;next;
    while (tmp != other.list) {
        listNode* node = new listNode(tmp-&gt;data);
        if (!node) throw E_OUTOFMEMORY();

        this-&gt;left_insert(this-&gt;list, node);
        tmp = tmp-&gt;next;
    }
}</pre>

<p>Lényegében az értékül adott listán végigmegyünk és egyesével beszúrjuk az elemeit a saját listánkba. Mint említettem annak idején, a copy konstruktor fontos dolog. Gondoljunk csak bele, hogy mi történne akkor, ha nem írnánk sajátot. Az objektum változóinak értéke szépen átmásolódna. Tehát ha B objektumnak adjuk kezdőértékül A objektumot, akkor B objektum list változója ugyanoda fog mutatni, mint az A objektum list változója, tehát ha az A objektumot megszüntetjük, akkor a B objektum tulajdonképpen a "semmibe" fog mutatni. De ha B objektum listáján változtatunk (kifűzünk, befűzünk), akkor A objektum listája is változik.<br/>A <code>left_insert()</code> az első paraméterként kapott pointer által mutatott listaelemhez képest balra fűz be egy elemet. Mivel esetünkben a lista fejelemét kapja meg a függvény, és mivel a lista fejelemének bal oldalra mutató mutatója (azaz a prev) a lista utolsó elemére mutat, ez azt jelenti, hogy a lista végére fűzzük be az elemet. Jöjjön végül, de nem utolsó sorban a destruktor:</p>

<pre class="code prettyprint lang-c">cList::~cList(void)
{
    Destroy();
    delete list;
}</pre>

<p>Nem meglepő módon a destruktor (ami ugyebár a konstruktor úgymond ellentéte, és akkor fut le, amikor az objektum megszűnik) a <code>Destroy()</code> függvénnyel kiüríti a listát, majd a list változó segítségével megszünteti a fejelemet is.<br/>Asszem ennyi elég is lesz mára. Az objektum felhasználói felületét (a public függvények, mint például a <code>left_insert()</code>) és néhány operátort a következő részben fogunk megírni, és ha nem nyúlik túl hosszúra a dolog (mint ahogy most), akkor végre a sablonokat is kitárgyaljuk.</p>]]></content:encoded>
			<wfw:commentRss>http://deadlime.hu/2006/04/05/objektum-orientalt-cpp-3/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Objektum-orientált C++ II.</title>
		<link>http://deadlime.hu/2006/04/05/objektum-orientalt-cpp-2/</link>
		<comments>http://deadlime.hu/2006/04/05/objektum-orientalt-cpp-2/#comments</comments>
		<pubDate>Wed, 05 Apr 2006 20:05:32 +0000</pubDate>
		<dc:creator>Nagy Krisztián</dc:creator>
				<category><![CDATA[nincs kategória]]></category>
		<category><![CDATA[C++]]></category>
		<category><![CDATA[objektum-orientált]]></category>

		<guid isPermaLink="false">http://deadlime.hu/2006/04/05/objektum-orientalt-cpp-2/</guid>
		<description><![CDATA[El is érkeztünk a második részhez, remélem mindenki türelmetlenül várta már, hogy mi következhet még. Mint az az előző részből látható volt, semmi olyat nem valósítottunk meg, amit C-ben ne tudtunk volna megcsinálni, csak sokkal átláthatóbb lett az egész, szerves egységet alkot, nem arról van csak szó, hogy egy struct köré építünk pár kezelő függvényt. [...]]]></description>
			<content:encoded><![CDATA[<p>El is érkeztünk a második részhez, remélem mindenki türelmetlenül várta már, hogy mi következhet még. Mint az az előző részből látható volt, semmi olyat nem valósítottunk meg, amit C-ben ne tudtunk volna megcsinálni, csak sokkal átláthatóbb lett az egész, szerves egységet alkot, nem arról van csak szó, hogy egy <code>struct</code> köré építünk pár kezelő függvényt. Most lehet azt gondolni, hogy az OOP megszállotja vagyok. Előfordulhat, de miért is tagadnék meg valami olyasmit, ami megkönnyíti az életemet, kevesebb és sokkal átláthatóbb kódot eredményez?</p>

<p>A mai terv első körben a <code>Complex</code> objektum szorzásának (<code>operator*</code>) és az összehasonlító operátornak (<code>operator==</code>) megvalósítása és a komplex számunk megjelenítése valamiféleképpen a képernyőn. Az első két dologgal nem lesz túl sok gondunk az előző rész alapján. Csak két új függvénnyel kell bővítenünk az objektumot:</p>

<pre class="code prettyprint lang-c">Complex operator*(const Complex&amp; num)
{
    return Complex(re*num.re - im*num.im, re*num.im + im*num.re);
}

bool operator==(const Complex&amp; num) const
{
    return (re == num.re &amp;&amp; im == num.im);
}</pre>

<p>Tuladjonképpen semmi új, leszámítva a második függvény első sorának a végén azt a kis <code>const</code> szavacskát, ami azt hivatott jelezni, hogy a függvény az objektumot nem módosítja.<br/>Most, hogy ezt is tisztáztuk, evezzünk izgalmasabb vizekre. Fontos megemlíteni, hogy nem csak az osztályon belül definiálhatunk operátorokat, hanem az osztályon kívül is. Ez már csak azért is egy hasznos dolog, mert elég gyakran adódhat olyan eset, hogy nem tudunk belenyúlni a kódba, amihez viszont egy operátort hozzá akarunk csapni (értelmes és mindent megmagyarázó példát lásd egy picit lejjebb).</p>

<h3>Copy konstruktor</h3>

<p>A copy konstruktor szépsége esetünkben abban testesül meg, hogy használata teljesen felesleges, viszont bevezetését már ezen a szinten fontosnak tartom, mivel a későbbiekben létfontosságúvá válik, szóval jobb, ha már most hozzászokunk. Ez a konstruktor se más mint a többi, a lényegbeli különbség csak annyi, hogy paraméterként egy, az objektum típusával megegyező objektumot kap, amivel kezdenie kell valamit.</p>

<pre class="code prettyprint lang-c">Complex(const Complex&amp; other) : re(other.re), im(other.im) {}</pre>

<p>Mivel esetünkben a megírt konstruktor viselkedése nem különbözik az alapértelmezettől (mert hát minden objektumnak ugyanúgy van copy konstruktora, mint konstruktora is, akár megadjuk a kódban akár nem), ezért célszerűbb elhagyni, mivel - A C++ programozási nyelv c. könyv állítása szerint - rövidebb gépikódot eredményez. Azért megjegyezném, hogy nem biztos, hogy tökéletesen átgondolt lépés volt tőlem, hogy <code>int</code>-nek választottam az osztály re és im változóit, lehet célszerűbb lett volna <code>float</code> vagy esetleg <code>double</code>, de ezt inkább az elvégzendő feladat határozza meg.</p>

<h3>Kimenetgenerálás</h3>

<p>Esetenként szükségünk lehet olyan dolgokra, hogy a véres verejtékkel kiszámolt komplex számunkat a júzer képernyőjén teljes pompájában jelenítsük meg. Az első gondolat természetsen valami olyasmi lehet, hogy csinálunk például egy <code>to_string()</code> vagy <code>print()</code> tagfüggvényt. Nem egy rossz gondolat, de ha már adva van egy operátor erre a célra (<code>operator&lt;&lt;</code>), akkor miért is ne használnánk azt, ahelyett hogy önkényesen definiálunk valami függvényt a probléma megoldására?</p>

<pre class="code prettyprint lang-c">friend std::ostream&amp; operator&lt;&lt;(std::ostream&amp; out, Complex&amp; num)
{
    out &lt;&lt; num.re &lt;&lt; &quot; + &quot; &lt;&lt; num.im &lt;&lt; &quot;i&quot;;
    return out;
}</pre>

<p>Bár fentebb azt említettem, hogy az osztályon kívül is definiálhatunk operátorokat, ez esetben mégsem tanácsos ezt tenni (a friend kulcsszó elhagyásával minden további nélkül helyes lenne szintaktikailag), mivel a <code>Complex</code> osztály re és im változói a private blokkban vannak, vagyis nem tudnánk elérni őket abban az esetben. Ezzel tulajdonképpen már meg is magyaráztam a friend kulcsszó lényegét: nélküle nem tudnánk két paraméteres <code>operator&lt;&lt;</code> függvényt megadni az osztályon belül. Ha viszont az osztályon kívül adnánk meg, akkor pedig nem tudnánk elérni a private blokkban lévő változókat.<br/>Egyébként az ostream objektum felelős a kimenetért. A sikeres fordítás előfeltétele egy <code>#include &lt;iostream&gt;</code> valahol a .cpp fájl elején. A megkapott ostream objektum visszaadása a beleírás után hasonló célt szolgál, mint az előző bejegyzésben az egyenlőség operátornál (tehát, hogy lehessen ilyesmiket is írni: <code>std::cout &lt;&lt; "Hello, World!" &lt;&lt; Complex(2,1) << std::endl;</code>). Ezzel a végére is értünk a második résznek. A következő rész tartalmából: megpróbálunk valami új adatstruktúrát összehozni, kivesézni a jó- és rossztulajdonságait, összehasonlítani a szimpla tömbbel. És ha minden igaz még egy sablont is fogunk ráhúzni!</p>]]></content:encoded>
			<wfw:commentRss>http://deadlime.hu/2006/04/05/objektum-orientalt-cpp-2/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Objektum-orientált C++ I.</title>
		<link>http://deadlime.hu/2006/04/05/objektum-orientalt-cpp-1/</link>
		<comments>http://deadlime.hu/2006/04/05/objektum-orientalt-cpp-1/#comments</comments>
		<pubDate>Wed, 05 Apr 2006 20:05:24 +0000</pubDate>
		<dc:creator>Nagy Krisztián</dc:creator>
				<category><![CDATA[nincs kategória]]></category>
		<category><![CDATA[C++]]></category>
		<category><![CDATA[objektum-orientált]]></category>

		<guid isPermaLink="false">http://deadlime.hu/2006/04/05/objektum-orientalt-cpp-1/</guid>
		<description><![CDATA[Egy kis fejtörés után arra az elhatározásra jutottam, hogy az elkerülhetetlennek vélt C++ tudás-felfrissítést egy bejegyzés-sorozat keretében ejtem meg, így legalább nem csak nekem lesz hasznom a dologból.Feltételezem, hogy aki ez iránt a téma iránt érdeklődik, már rendelkezik némi C++-os illetve C-s tapasztalattal, tehát az alapvető szintaxis ismertetésétől eltekintenék. Hogy rögtön a közepébe vágjunk, első [...]]]></description>
			<content:encoded><![CDATA[<p>Egy kis fejtörés után arra az elhatározásra jutottam, hogy az elkerülhetetlennek vélt C++ tudás-felfrissítést egy bejegyzés-sorozat keretében ejtem meg, így legalább nem csak nekem lesz hasznom a dologból.<br/>Feltételezem, hogy aki ez iránt a téma iránt érdeklődik, már rendelkezik némi C++-os illetve C-s tapasztalattal, tehát az alapvető szintaxis ismertetésétől eltekintenék. Hogy rögtön a közepébe vágjunk, első körben a <code>struct</code> nevezetű nyelvi szerkezet felé terelném a szót: a dolog már a C nyelvből is ismerős lehet, a különbség ott kezdődik, hogy immár nem csak különböző típusú változókat gyűjthetünk vele egy kupacba, hanem a hozzájuk tartozó függvényeket is. Igazából én az egyetlen értelmét a C-vel kapcsolatos visszafelé-kompatibilitásban látom ennek a dolognak, mivel egy az egyben ugyanarra a dologra használható mint a <code>class</code> azzal a csöppnyi különbséggel, hogy a <code>struct</code> tagfügvényei és változói alapértelmezésben <code>public</code>, míg a <code>class</code> esetében <code>private</code> részében vannak.</p>

<h3>Osztályok</h3>

<p>Talán tisztázzuk is rögtön ezeket a <code>public</code>, <code>private</code> dolgokat. A <code>public</code> részben elhelyezett függvényeket (illetve változókat) az osztály példányosítása után lehet használni, míg a <code>private</code> részben lévőket csak az osztály maga tudja felhasználni. Ezek a kis cimkék nagyon hasznosak tudnak lenni, így egy objektumhoz létre tudunk hozni egy nyilvános (<code>public</code>) felhasználói felületet, aminek ismeretével használni lehet majd az osztályt. Arra gondoltam, hogy a komplex számokat megvalósító osztály elég jó bevezető lehet, aztán majd a későbbiekben jobban elrugaszkodunk a valóságtól.</p>

<pre class="code prettyprint lang-c">class Complex
{
    int re, im;

    public:
        Complex(const int&amp; R, const int&amp; I)
        {
            re = R;
            im = I;
        }
};</pre>

<p>Ezzel így, ebben a formában semmit sem értünk el, mert hát egy <code>struct</code> is képes lett volna erre annak idején C-ben, a konstruktort leszámítva (az osztály nevével megegyező nevű rémséget (vagy gyakrabban rémségeket) nevezzük konstruktornak, amivel például a kezdeti értékadást végezhetjük el, mint esetünkben is). Aki nem szeret ilyen sokat írni, annak ajánlom a <code>Complex(int R, int I) : re(R), im(I) {}</code> - kicsit haxorosabb - formájú konstruktort, amivel ugyanezt a hatást érhetjük el. Itt az ideje, hogy valami izgalmasat is kezdjünk, a kezünkbe adott fene nagy hatalommal. Írjunk operátorokat!</p>

<h3>Operátorok</h3>

<pre class="code prettyprint lang-c">class Complex
{
    int re, im;

    public:
        Complex(const int&amp; R, const int&amp; I) : re(R), im(I) {}
        Complex(const int&amp; R) : re(R), im(0) {}

        // Összeadás
        Complex operator+(const Complex&amp; num)
        {
            return Complex(re+num.re, im+num.im);
        }
        // Értékadás
        Complex&amp; operator=(const Complex&amp; num)
        {
            re = num.re;
            im = num.im;

            return *this;
        }

        Complex&amp; operator=(const int&amp; num)
        {
            re = num;
            im = 0;

            return *this;
        }
};</pre>

<p>Mint az szépen látszik, a konstruktort és az egyenlőség operátort túlterheltem, hogy a következő megadások is működjenek:</p>

<pre class="code prettyprint lang-c">Complex c1 = 3;
Complex c2(6, 3);
c1 = 5;
c1 = c2;</pre>

<p>Az első sorban a második konstruktor futott le, mivel ez nem egy egyszerű értékadás (a <code>Complex c1(3);</code> hosszabb formája). A második sorban (egyértelműen) az első konstruktor futott le, a harmadik illetve negyedik sorokban értelemszerűen a megfelelő értékadó operátor függvények. Most, hogy már ilyen rengeteg kódunk van, itt az ideje egy kicsit egyszerűsíteni a dolgokon. Az egyszerűsítés a második konstruktornak köszönhető, mivel ezzel egy int-Complex típuskonverziót is definiáltunk. Tehát az értékadás operátor túlterhelése ilyen módon feleslegessé vált.<br/>Érdemes lehet még pár szót fecsérelni arra, hogy az értékadó operátor miért tér vissza egy <code>Complex</code> referenciával, és mi a fene az a <code>*this</code>. Az első kérdésre egy kicsit a dolgok mélyére kell nézni. Mi is történik egy <code>c1 = c2 = 5;</code> sor hatására? Hosszabban valahogy így írhatnánk fel a dolgot: <code>c1.operator=(c2.operator=(Complex(5))</code>. Így már világosan látszik, hogy ha nem térne vissza azzal az értékkel az értékadás, mint amit az objektum felvett, akkor bizony a második értékadás értelmetlen lenne. Ez nem feltétlenül baj, de engem úgy neveltek, hogy ha egy új típust/objektumot ír az ember, akkor az ott használt operátorok viselkedésükben próbáljanak minél jobban hasonlítani az operátor eredeti viselkedéséhez.<br/>A második válasz már lényegesen egyszerűbb, a <code>this</code> változó egy, az objketum éppen használt példányára mutató pointer, amit minden - nem <code>static</code> - tagfüggvényben használhatunk, tehát a <code>*this</code> maga az objektum amivel éppen dolgozunk.</p>

<p>Bevezetésnek, kedvcsinálónak talán ennyi elég is lesz. A következő részben kiegészítjük a <code>Complex</code> osztályunkat pár új operátorral és egy új konstruktorral is (copy konstruktor), majd gyengéden súroljuk a <code>std</code> névtér streamjeit is, csak hogy tényleg ne tűnjön olyan egyszerűnek az élet.</p>]]></content:encoded>
			<wfw:commentRss>http://deadlime.hu/2006/04/05/objektum-orientalt-cpp-1/feed/</wfw:commentRss>
		<slash:comments>1</slash:comments>
		</item>
		<item>
		<title>C++ és a socketek</title>
		<link>http://deadlime.hu/2006/04/01/cpp-es-a-socketek/</link>
		<comments>http://deadlime.hu/2006/04/01/cpp-es-a-socketek/#comments</comments>
		<pubDate>Sat, 01 Apr 2006 15:26:19 +0000</pubDate>
		<dc:creator>Nagy Krisztián</dc:creator>
				<category><![CDATA[nincs kategória]]></category>
		<category><![CDATA[C++]]></category>
		<category><![CDATA[socket]]></category>

		<guid isPermaLink="false">http://deadlime.hu/2006/04/01/c-es-a-socketek/</guid>
		<description><![CDATA[Mivel nincs kimondottan C++-os eszköz a socketelésre ezért a meglévő C-s eszközökkel elég sokat lehet szívni, ha épp a sors úgy hozza. És hát miért ne hozná úgy. Történetünk valahogy úgy kezdődik, hogy szeretnénk csatlakozni valami webszerverhez, hogy lekérjünk onnan valami adatot, így adott három változónk, nevezzük őket valahogy így: std::string host = &#34;www.something.com&#34;; std::string [...]]]></description>
			<content:encoded><![CDATA[<p>Mivel nincs kimondottan C++-os eszköz a socketelésre ezért a meglévő C-s eszközökkel elég sokat lehet szívni, ha épp a sors úgy hozza. És hát miért ne hozná úgy. Történetünk valahogy úgy kezdődik, hogy szeretnénk csatlakozni valami webszerverhez, hogy lekérjünk onnan valami adatot, így adott három változónk, nevezzük őket valahogy így:</p>

<pre class="code prettyprint lang-c">std::string host = &quot;www.something.com&quot;;
std::string port = &quot;80&quot;;
std::string data = &quot;GET / HTTP/1.1\\nHost: www.something.com\\nConnection:close\\n\\n&quot;;</pre>

<p>Már csak az az aprócska dolog maradt, hogy akkor most hát, innen hogyan tovább. Először is rakjunk össze egy c-szerű megoldást, a jobb érthetőség kedvéért, aztán majd jöhetnek az objektumok, hogy a dolog ki is nézzen valahogy.</p>

<p>Első lépésben szükség lesz még pár változóra, mondjuk egy bufferre, egyre amiben a socketet tároljuk, egyben, amiben a host visszafejtése után nyert struct adatokat és egyben amiben a kapcsolódáshoz szükséges adatokat tároljuk.</p>

<pre class="code prettyprint lang-c">/*
 * Ebben találjuk a sockaddr_in struct-ot és a htons()
 * függvényt, amire majd a későbbiekben szükségünk lesz.
 */
#include &lt;netinet/in.h&gt;
/*
 * Ebben van a hostent struct és a gethostbyname() függvény.
 */
#include &lt;netdb.h&gt;

int main()
{
    /* ... */
    char        buffer[32]; // Az olvasásnál használt buffer
    int         s;          // Ez kell a socketnek
    sockaddr_in sin;        // Ez tárolja a kapcsolódó adatokat
    hostent*    hp;         // Ez pedig a host adatokat
    /* ... */
}</pre>

<p>Az első ...-nál vannak az elején megadott host, port, data változók, amikhez nem árt egy #include &lt;string&gt; sor a többi #include között. A második ... után fogjuk a kódot folytatni a socket létrehozásával.</p>

<pre class="code prettyprint lang-c">/*
 * Erre a header fájlra van szükség a socket() függvényhez
 */
#include &lt;sys/socket.h&gt;
/* ... */
int main ()
{
    /* ... */
    if ((s = socket(AF_INET, SOCK_STREAM, 0)) &lt; 0) {
        return 1;
    }
    /* ... */
}</pre>

<p>A socket() függvény első paramétere határozza meg a címcsaládot, azaz hogy a cím hogyan legyen értelmezve. Ez IP esetén az AF_INET konstans, a többi típust a socket.h -ban meg lehet találni. A második paraméter a kapcsolat típusának meghatározásáért felelős, ami TCP esetén SOCK_STREAM, UDP esetén SOCK_DGRAM. Az utolsó a protokoll meghatározása, ami IP esetén 0, egyéb esetek az /etc/protocols-ban találhatóak meg. Most, hogy ezzel megvagyunk, ideje, hogy a hostunkból kapjunk egy használható structot a gethostbyname() függvény segítségével.</p>

<pre class="code prettyprint lang-c">/* ... */
int main()
{
    /* ... */
    if ((hp = gethostbyname(host.c_str())) == 0) {
        return 2;
    }
    sin.sin_family = AF_INET;
    bcopy(hp-&gt;h_addr, (char*)&amp;sin.sin_addr, hp-&gt;h_length);
    sin.sin_port = htons(atoi(port.c_str()));
    /* ... */
}</pre>

<p>A host megkapással egyben le is rendeztem a másik struct adatainak feltöltését, mivel minden szükséges adat a rendelkezésünkre állt. Azaz a cím család itt is AF_INET lett, a címet a hp struct-ból másolgattuk át, a portot pedig már a legelején stringként megadtuk, abból csináltunk char*-ot majd int-et és végül a htons() függvény segítségével host byte orderből network byte ordert csináltunk (ami nekem még nem teljesen tiszta, hogy miért is kell ezt így, sz'al ha valakinek valami infója van róla, szivesen venném). Így most már nincs más hátra mint csatlakozni és elküldeni a kérést.</p>

<pre class="code prettyprint lang-c">/* ... */
int main()
{
    /* ... */
    if (connect(s, (sockaddr*)&amp;sin, sizeof(sin)) &lt; 0) {
        return 3;
    }

    int num;
    num = write(s, data.c_str(), data.length());
    if (num &lt; 0) {
        return 4;
    }
    /* ... */
}</pre>

<p>A connect() első paramétere a megnyitott socket-ünk, a második a kapcsolat adatai a harmadik pedig a kapcsolat adatainak a mérete. A write() első paramétere a socket a második az adat (char* formában), a harmadik pedig a küldendő adat hossza. Most, hogy megvolt a csatlakozás, megvolt a kérés, már csak megfelelő fogadtatásban kell részesíteni az érkező adathalmazt.</p>

<pre class="code prettyprint lang-c">/* ... */
int main()
{
    /* ... */
    while ((num = read(s, buffer, sizeof(buffer))) &gt; 0) {
        buffer[num] = '\\0';
        std::cout &lt;&lt; buffer;
    }
    close(s);
    return 0;
}</pre>

<p>Megkaptuk az adatokat, lezárjuk a kapcsolatot, kilépünk a programból. Persze a kóddal a legnagyobb probléma (azon kívül, hogy ezekkel a /* ... */ kommentekkel talán még kibogózhatatlanabbá tettem), hogy nagyon is egyszer haszálatos, eléggé átláthatatlan meg egyébként is csúnya. Nézzünk akkor egy osztályos megoldást:</p>

<pre class="code prettyprint lang-c">#ifndef __SOCKET_H__
#define __SOCKET_H__

#include &lt;sys/socket.h&gt;
#include &lt;netinet/in.h&gt;
#include &lt;netdb.h&gt;

#include &lt;string&gt;

#define E_SOCKET_ERROR  1
#define E_HOST_ERROR    2
#define E_CONNECT_ERROR 3
#define E_WRITE_ERROR   4

class Socket
{
    private:
        char buffer[32];
        int sock;
        hostent* hp;
        sockaddr_in sin;
    public:
        Socket();
        Socket(const std::string&amp; host, const std::string&amp; port)
        {
            this-&gt;Open(host, port);
        }
        ~Socket()
        {
            this-&gt;Close();
        }
        void Open(const std::string&amp; host, const std::string&amp; port)
        {
            // Socket létrehozása
            if ((this-&gt;socket = socket(AF_INET, SOCK_STREAM, 0)) &lt; 0) {
                throw new Socket::SocketException(E_SOCKET_ERROR);
            }

            // Host visszafejtése
            if ((this-&gt;hp = gethostbyname(host.c_str())) == 0) {
                throw new Socket::SocketException(E_HOST_ERROR);
            }

            // sockaddr_in struct feltöltése
            this-&gt;sin.sin_family = AF_INET;
            bcopy(this-&gt;hp-&gt;h_addr, (char*)&amp;this-&gt;sin.sin_addr, this-&gt;hp-&gt;h_length);
            this-&gt;sin.sin_port = htons(atoi(port.c_str()));

            // Csatlakozás
            if (connect(this-&gt;sock, (sockaddr*)&amp;this-&gt;sin, sizeof(this-&gt;sin)) &lt; 0) {
                throw new Socket::SocketException(E_CONNECT_ERROR);
            }
        }
        void Send(const std::string&amp; data)
        {
            int wb = write(this-&gt;sock, data.c_str(), data.length());
            if (wb &lt; 0) {
                throw new Socket::SocketException(E_WRITE_ERROR);
            }
        }
        std::string GetLine()
        {
            int rb;
            std::string ret;
            do {
                rb = read(this-&gt;sock, this-&gt;buffer, 1);
                if (rb &gt; 0) {
                    if (this-&gt;buffer[0] != '\\n') {
                        ret += this-&gt;buffer[0];
                    }
                    else {
                        break;
                    }
                }
            } while (rb &gt; 0);

            return ret;
        }
        void Close()
        {
            close(this-&gt;sock);
            return;
        }
        class SoketException
        {
            public:
                int errorCode;
                SocketException(const int&amp; code)
                {
                    this-&gt;errorCode = code;
                }
        };
};

#endif</pre>

<p>Csak a kép teljességéért, egy rövidke példaprogram, ami ezt a Socket.h fájlt használja és ugyanazt eredményezi, mint az osztály nélküli kód.</p>

<pre class="code prettyprint lang-c">#include &quot;Socket.h&quot;

#include &lt;string&gt;
#include &lt;iostream&gt;

int main()
{
    std::string host = &quot;www.something.com&quot;;
    std::string port = &quot;80&quot;;
    std::string data = &quot;GET / HTTP/1.1\\nHost: www.something.com\\nConnection:close\\n\\n&quot;;

    Socket* sock;

    try {
        sock-&gt;Open(host, port);
        sock-&gt;Send(data);

        std::string row;
        while ((row = sock-&gt;GetLine()).length() &gt; 0) {
            std::cout &lt;&lt; row &lt;&lt; std::endl;
        }

        sock-&gt;Close();
    }
    catch (Socket::SocketException e) {
        delete sock;
        return e.errorCode;
    }
    delete sock;
    return 0;
}</pre>

<p>Egy cseppet szebb lett. Mondjuk nézőpont kérdése. Egy egyszer használatos gyors socketelésre felesleges lenne osztályt írni, de ha már az embernek kéznél van egy ilyen, akkor gyorsabban megírhat egy egyszerhasználatos socketelést, mint egyébként. Bár az igazsághoz hozzátartozik, hogy így a kód mérete picikét nagyobb lett (ha jól emlékszem alapból 16k volt, így meg 20k lett g++-szal fordítva mindenféle extra paraméterezés nélkül).</p>]]></content:encoded>
			<wfw:commentRss>http://deadlime.hu/2006/04/01/cpp-es-a-socketek/feed/</wfw:commentRss>
		<slash:comments>2</slash:comments>
		</item>
	</channel>
</rss>

