<?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.project &#187; származtatás</title>
	<atom:link href="http://deadlime.hu/tag/szarmaztatas/feed/" rel="self" type="application/rss+xml" />
	<link>http://deadlime.hu</link>
	<description>squeezed out</description>
	<lastBuildDate>Tue, 24 Jan 2012 21:54:45 +0000</lastBuildDate>
	<language>en</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
	<generator>http://wordpress.org/?v=3.3.1</generator>
		<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>kriz</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><span id="more-30"></span>

<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>
	</channel>
</rss>

