Mielõtt mérlegelnénk az objektumorientált nyelvek elõnyeit, meg kell ismertnünk magát a fogalmat! Kezdetben voltak a sima programnyelvek, mint a Basic, a Pascal és a C. Aki ismeri a Basicet(ki ne ismerné

), az tudja, hogy azt ki is ejthetjük a sorból, hiszen nem lehet együtt emlegetni pl. a Pascallal. A Pascal nyelvet oktatási célokra találták ki, ám könnyû használhatósága miatt széles körben elterjedt, szintaxisát ugyancsak kibõvítették, és a Pascal is objektumorientálttá vált(Object Pascal). Objektumorientált programnyelv a Pascal szintaxist használó Delphi is. Régen, aki C-ben programozott, az kihúzta magát, mert "én húde tudok programozni", pedig programozni C alatt hasonló volt mint Pascal alatt, csupán más szintaxissal. Aki pedig szöveges programot írt, az úgyis Pascal-t használt, mert az sokkal egyszerûbb volt. Magát a C-t csupán a profiknak volt érdemes használni.
Aztán jött egy új nyelv, a C++. Hangsúlyozom, hogy új nyelv, hiszen a C-vel csak szintaxisában egyezett, illetve felülrõl kompatibilis volt a C nyelvvel. Fõ újítása az objektumorientáltság volt, ami jelentõsen megkönnyítette a programozást az újrafelhasználható elemek révén. Tehát már ki is szivárgott az elsõ információ: a programot ezentúl modulokban írjuk, nem pedig csak úgy vaktában... Ezeknek a moduloknak a neve: osztály.
Nézzük mi a viszonya az osztályokban a függvényeknek és az adatoknak! Pascalban vagy C-ben létrehoztunk változókat, aztán mûveleteket hajtottunk rajtuk végre. Vagy globálisan hoztunk létre változót, vagy lokálisan, ettõl függõen átadogattuk õket a függvényeknek, vagy csak simán hivatkoztunk rájuk a függvényekbõl... Ez a C++-al megszûnt, pontosabban támogatja az ilyen programozást a C-vel való kapcsolata miatt, de a fõ vezérelv az objektumorientáltság lett. Azaz legyen egy objektumunk. Ez az objektum tartalmazzon az objektumot leíró adatokat, melyeket az objektum létrehozásakor inicializálunk, aztán el is felejtjük õket, legalábbis az objektumon kívûlrõl! Tehát ezek után az objektumon kívûlrõl csak függvények útján kommunikálunk az objektummal. Ezt hívják
adatrejtés elvének. Lássuk, miért is jó ez: egyrész így illetéktelen programrész nem nyúlhat bele a változóinkba, ami esetleg galibát okozna, pontosabban az objektumunk helytelen mûködését. A másik pedig a hibakeresés: nem kell sorról sorra végignézni a programunkat, hogy hol a hiba, hiszen az objektumunkat addig tesztelhetjük, amíg tökéletes nem lesz, majd azután beleépítjük a programunkba. Ez a program pedig nem tudja elrontani az objektumunkat(mármint ha az objektumot helyes írtuk meg).
Az objektumok pontos mûködésérõl, az öröklõdésrõl, a beágyazásról, a virtuális függvényekrõl majd már a gyakorati részben írok, addig pedig meg lehet barátkozni a gondolattal, hogy a nehezen megtanult C nyelvrõl most új vizekre evezünk!
Alapok
Lássuk akkor, hogy is kell programozni objektumorientáltan! Hangsúlyozom, hogy csak az alapdolgokat mutatom be, aki feltétlenül meg akar érteni minden részletet, az vehet valamilyen könyvet a C++ programozásról, úgyis annyi létezik már. Én mindig azt mondom, hogy az iagzi tudást könyvbõl lehet megszerezni, vagy méginkább egy egyetemen! Szóval hajrá, irány tanulni

!
Az elsõ és legfontosabb dolog:
nem kell header fájl!!! Mint az elõzõ cikkben
(elõzõ bekezdésben - HG) említettem, az objektumorientált programozás része a C++ nyelvnek, tehát az alapvetõ nyelvi elemek megtalálhatók. Ugye mindenki ismeri a
struct felhasználói típust? Nos, azt is ellátták az objektumorientáltsághoz szükséges eszközökkel, de mi az osztály típust fogjuk használni. Hogy miért? Mert sokkal jobban beleillik az adatrejtés elvébe, azaz minden tag alapban kívûlrõl nem elérhetõ. De talán akkor kezdjünk is bele, és késõbb talán jobban megértjük, miért is fontos az objektumorientált programozás.
Hogyan hozunk létre egy osztályt? Mindenekelõtt kell egy prototípus, hiszen mit akarunk addig létrehozni? Lássuk, hogyan hozunk létre egy struktúra prototípust!
Most nézzük az osztály prototípust!
Ugyan az, csak a kulcsszó tér el! Vigyázzunk a pontosvesszõvel, ugyanis ide is kell!!! Namost, akkor lássuk, mit is tudunk ezzel az osztállyal csinálni, mit is lehet beírni a zárójelek közé! Az elsõ legfontosabb dolog az, hogy megismerjük az adatrejtés elvét!
Régen ugye voltak a struktúrák, amikbe csak változókat lehetett deklarálni, de függvényeket nem! Ott természetesen kívûlrõl kellett látni ezeket a változókat, mert belülrõl mi látta volna õket? Ott nem volt semmilyen függvény. Itt most lehetnek, tehát nem szükséges, sõt sokszor fontos, hogy ne is lássák a változóinkat kívülrõl! Ekkor ezeket a változókat csak az osztályon BELÜLI függvényekkel tudjuk megváltoztatni. Akkor lássuk az elérést módosító kulcsszavakat:
private - privát elérés, azaz csak a mi osztályunkon belülrõl látszik
public - nyilvános elérés, azaz az osztályon kívül is látszik
protected - privát elérés kívülrõl, azonban az örökölt osztályok láthatják(errõl majd késõbb

)
Nézzünk erre egy példát: egy anyuka már 50 éves, tehát nem akarja hogy más is tudja az életkorát, azonban a fõ méretei 90-60-90, tehát azokkal pedig csak büszkélkedni tud. Lássuk ezt C++-ban:
class anyuka {
private: int kor;
public:
int csipo,derek,mell;
}; |
Látszik, hogy attribútumszerûen megadjuk az adatrejtés típusát, majd kettõspont után írjuk a változóinkat. Egy ilyen kijelölt rész a következõ adatrejtési kulcsszóig tart. Megjegyzem, hogy az osztály típusban a tagok, mint az elõbb említettem, alapban
private elérésû, míg struktúrában alapban
public elérésûek.
Szóval ha ezt mind értjük, akkor nézzük meg nagyon röviden mi lehet egy osztályban:
- adatelérést szabályzó kulccsszavak
- változók, mutatók, akármilyen eddig ismert változótípus, tömbök, stb. FONTOS, hogy a változóknak nem lehet kezdõértéket adni!
- függvények töménytelen mennyiségben, ha private kulcsszó alatt van, akkor természetesen az sem érhetõ el kívûlrõl
- lehetnek még különbözõ öröklõdést, adatrejtést,stb. szabályzó kulcsszavak(ezekrõl késõbb)
Nézzünk akkor egy ilyen osztályt, amiben vannak függvények és változók is:
class Szamlalo { private: int akt; public: void Inicializal(int honnan=0) { akt=honnan; } void Novel() { akt++; } int Leker() { return akt; } }; |
Akkor lássuk az újdoságokat! Azt észrevehetjük, hogy ez egy komplett, mûködõ, bár a tudásához képes méretes egy osztály, szóval egy egyszerû, bár borzasztóan rossz példa. De mondhatnám kitenyésztettnek, mert sok minden benne van, ami kell. Mit is csinál? Ha létrehozzuk az osztályt, és inicializáljuk, akkor kapunk egy szamlalót, mely az inicializálás paramétereként megadott számtól számol elõre minden
Novel() parancsra! Az is feltûnõ, hogy itt már a deklarációban benne vannak a definiciók, azaz mindegyik függvényt megadtam! Természetesen ezeket külön is meg lehet adni, a hatókör feloldása operátorral(::), de arról majd késõbb, ugyanis itt nagyon egyszerû függvényekrõl van szó.
Nézzük az adatrejtést: a változóknak nem közvetlenül adunk értéket, hanem az osztály függvényein keresztül! Ez azért fontos, hogy megbízható legyen a programunk futása! Gonduljuk el, hogy ez a számláló egy nagyobb program része! Mondjuk éppen már kész is van, csak azt szeretnénk, hogy ez a program ne legyen tele hibával! Tehát ennek alapfeltétele, hogy a számlálónk jó legyen. Ez természetesen jó, de mi van, ha a program a számlálónk
akt változóját átírja? A számláló ugrik egy nagyot, mi pedig kershetjük a hibát mindenhol, ez pedig nehéz. De a program NEM TUDJA ÁTÍRNI az
akt változót, mert az privát elérésû! Tehát biztosak lehetünk benne, hogy a számláló mûködik, máshol kell keresni a hibát!
Következõ: lássuk hogyan adunk meg függvényeket! Ugyanúgy, ahogy osztályon kívûl. Csupán arra kell figyelni, hogy ne legyen az osztály nevével azonos nevû változónk vagy függvényünk! Az
Inicializal(...) talán nem ismerjük az alapértelmezett érték trükköt(nem trükk, szintaktika). Ez azt jelenti csupán, hogyha nem adunk meg semmilyen paramétert a függvénynek, akkor a
honnan nulla értéket fog felvenni. Ez mûködik többre is, pl.:
int vissza(int a, float k, double t=4.5f,char e=3); |
de ez nem jó:
int vissza(int a=0, float k, double t=4.5f, char e=3);ugyanis az ilyen paramétereknek mindig a paraméterlista végén kell lenni, nem lehet utánnuk alapértelmezett érték nélküli paraméter! Akkor gondolom minden szép és jó, lássuk, hogyan hivatkozunk az osztály tagjaira!
Szamlalo szaml; int a;
szaml.Inicializal(); //vagy szaml.Inicializal(67); szaml.Novel(); szaml.akt=67; //Ez HIBÁS!!! a=szaml.Leker(); |
Tehát elõször létrehoztam a
Szamlalo egy példányát(igy csináljuk struktúránál is!), majd egy
a változót. Gondolom az osztály tagjainak elérése egyértelmû. Természetesen a
szaml.akt=67; sor hibás, mert az
akt az osztály privát tagja. Ha nyilvános tagja lenne, akkor tökéletes értékadás történne.
Mi van akkor, ha az osztályt dinamikusan akarom létrehozni? Semmi, tegyük az alábbiakat:
Szamlalo *szaml;
szaml=new Szamlalo; szaml->Inicializal(); |
Tehát elõször mutatót hozok létre, majd a
new paranccsal(ami ugyancsak a C++-hoz tartozik) létrehozom az osztályt. A
-> jelet már DirectX-ben megszokhattuk, nos ezért. Ugyanis a
szaml->Inicializal() ugyan az, mint a
(*szaml).Inicializal(); csak a C szintaktika egyszerûsíti.
Mivel a DirectX is osztályokra épül ,ezért a DirectDraw-ban lévõ mutatózgatást most nézzük meg, miért fontos! Lássuk a programot, szigorúan csak a dinamikus osztálylétrehozás szempontjából, és persze a függvényeket leegyszerûsitve:
LPDIRECTDRAW7 lpDD; //IDirectDraw7* lpDD; ->ezt csinálja a makró(azaz az LPDIRECTDRAW7 igazából mutatót kreál)
HRESULT DirectDrawCreateEx(...,IDirectDraw7** vmi,...) {
...
(*vmi)=new IDirectDraw7;
...
} |
Tehát mindig egy globális függvénnyel indítunk, mely létrehozza nekünk a megfelelõ osztályt. Remélem érthetõ, bár ez csak egy kis kitérés volt...
Egy dolog maradt hátra, méghozzá a hatókör feloldása operátor. Ez két kettõspont egymás után. Így az osztályon kívûlre is tudunk definíciót helyezni, de annak mindig látnia kell az eredeti deklarációt! Lássuk erre példát, például a számlálónk definícióit helyezzük az osztályon kívûlre! Ekkor az operátor bal oldalán mindig az osztály neve áll, a jobb oldalán a függvény neve!
class Szamlalo { private: int akt; public: void Inicializal(int honnan=0); void Novel(); int Leker(); };
void Szamlalo::Inicializal(int honnan) {akt=honnan;}
void Szamlalo::Novel() {akt++;}
int Szamlalo::Leker() {return akt; } |
Szóval akkor az alapok készen vannak, ennyihez nem mellékelek forráskódot.
Konstruktor, destruktor
Mik is ezek a rejtélyes nevek? Konstruktor annyit jelent, mint építõ, a destruktor pedig romboló. Körülbelül. De mire jók?
KonstruktorA konstruktor arra jó, hogy inicializáljuk az osztályunk egyik példányát(a példány maga a változó, vázlatosan pl. int a; ,ekkor a az integer egyik példánya). Ezt azért hozták létre, mert ugye privát tagokat kívûlrõl nem tudunk inicializálni. Ezért létezik egy konstruktor, mely ezeket a változókat olyan állapotba állítja, amilyenbe mi akarjuk. Ráadásul a konstruktor a mi külön parancsunk nélkül fut le(még akkor is, ha külön nem csinálunk konstruktort, akkor az alapértelmezett fut le).
A konstruktor akkor fut le, ha az osztály példánya létrejön... De mikor jön létre az osztály egy példánya? Két módon jöhet létre: statikusan vagy dinamikusan. Ezek egyszerûek, nezzük a statikusat:
Osztaly valtozonev; //Ezt úgy értsétek mint pl.: int a; |
Azaz mikor egyszerûen létrehozunk egy Osztaly típusú változót. Tehát ekkor fut le, mi mégse kértük. Ez azt jelenti, hogy mindig lefut, ha van. Az elõzõ részben lévõ példáinkban nem volt, szóval ott nem. Fontos hangsúlyozni, hogy NEM a konstruktor foglal memóriát az objektum példányának, hanem jelen esetben a fordító! Vagy pedig mi, dinamikus esetben:
Osztaly *mutato;
mutato=new Osztaly; |
Ekkor a
new paranccsal jön létre és a
new parancs fogja a konstruktort lefuttatni! Tehát MINDIG
new paranccsal foglaljunk memóriát, mert ez már a C++ része! Hiába próbálkozunk a
malloc vagy a
calloc paranccsal, azok nem futtatják le a konstruktort! Szóval felejtsük el ezeket az õsrégi tákolmányokat most(persze hasznosak, de nem most!). Akkor példálozzunk! Hogy is csinálunk konstruktort? A konstruktor neve mindig azonos az osztály nevével, azaz errõl tudjuk, hogy konstruktor! A konstruktornak NINCS visszatérési értéke! Az esetleges paraméterekrõl majd késõbb szólok.
class Anya { private: int gyerekekszama; public: Anya() { gyerekekszama=0; }
}; |
Fontos, hogy a konstruktornak nyilvános elérésûnek kell lenni! Ekkor az
példányosítás után a
gyerekekszama nem ismeretlen értékû, hanem nulla lesz! Így tehát könnyedén tudunk inicializálni egy osztálypéldányt. Fontos, hogy nem osztályt inicializálunk, hanem a példányt!
Konstruktorok paraméterezéseNézzük az alábbi létrehozást:
Anya *mutato;
mutato=new Anya; |
Ez azonos az alábbival:
Ez pedig azt jelenti, hogy a konstruktor hordozhat paramétereket is. Alapértelmezett konstruktor mindig van, és az paraméter nélküli!!! Ha mi egy akármilyen konstruktort létrehozunk, akkor az már nincs többé! Tekintsük az alábbi kódot:
class Anya { private: int gyerekekszama; public: Anya(int szam) { gyerekekszama=szam; } }; |
Tehát létrehozásnál beállíthatjuk a gyerekek számát. Ekkor viszont az alapértelmezett létrehozás elveszik, azaz nem mondhatjuk azt, hogy:
mert a fordító azt fogja mondani, nincs alapértelmezett konstruktor, azaz nincs
Anya() konstruktor! Tehát létrehozni most így tudjuk:
vagy
Anya *mutato;
mutato=new Anya(6); |
De mi van, ha szeretnénk alapértelmezett konstruktort? Akkor azt is megadunk, és a fordító majd a megfelelõ paraméterezésût hívja meg:
class Anya { private: int gyerekekszama; public: Anya() {gyerekekszama=0;} Anya(int szam) {gyerekekszama=szam;} }; |
Ekkor viszont akármelyik módon létrehozhatjuk, csak figyeljünk, hogy az a konstruktor hívódik-e meg, amelyiket akarjuk! A több konstruktor egyébként a magyar szakirodalom túlterhelt konstruktornak nevezi(az angol overload után). Szerintem ez nagyon nyelverõszakolás...
DestruktorAkkor most már tudjuk mi az a destruktor: mikor az osztály megszûnik, akkor elõtte lefut. Mikor szûnik meg egy osztály? Statikusan létrehozott osztály akkor szûnik meg, ha a fordító felszabadítja. A dinamikusan létrehozott osztály pedig a
parancsra hívja meg a destruktort. Itt is fontos, hogy nem a destruktor szabadítja fel a memóriát, hanem a fordító, vagy éppen a
delete parancs. Csak elõtte meghívja a destruktort! A
free() parancs NEM hívja meg a destruktort! Destruktor csak egy lehet, ez pedig az alábbiként néz ki:
class Anya { private: int gyerekekszama; public: ~Anya(); };
Anya::~Anya() {gyerekekszama=0; } |
Azaz egy ~ jel után az osztály neve. Most nem akartam okos példát találni, de gondolom értjük a lényegét, azaz ha pl. létrehoztunk egy nagy 1000 elemû dinamikus tömböt, akkor azt itt felszabadíthatjuk.
A destruktornak nincs visszatérési értéke és nem lehet paramétere.
Akkor nézzünk egy ilyen dinamikus tömbös példát(jóval komplexebb példa az Ogg lejátszásnál van!):
//Deklarációk class Tomb { private: int *tomb; int elemekszama; public: Tomb(int); ~Tomb();
void Beir(int,int); int Leker(int); int LekerElemSzam() { return elemekszama; } };
//Definíciók
Tomb::Tomb(int elemszam) { tomb=new int[elemszam]; elemekszama=elemszam; }
Tomb::~Tomb() { delete[] tomb; }
void Tomb::Beir(int melyik, int mit) { if(melyik>elemekszama) ; //hibakezelés tomb[melyik]=mit; }
int Tomb::Leker(int melyik) { return tomb[melyik]; } |
A
tomb=new int[elemszam] ugyancsak C++ parancs, azaz helyet foglal
elemszam darab egésznek, a
delete[] tomb pedig felszabadítja. Vigyázat! A
delete tomb csak az elsõ elemet szabadítja fel!
Ez volt egy tömb körülményes, de tanulságos megvalósítása!
Öröklõdés
Na, akkor lássuk a leghíresebb tulajdonságát az objektum-orientált programozásnak... Az öröklõdés fõleg a kezdõ C++ programozónak jelent problémát, mert nem teljesen érthetõ... Ugyanis sokszor úgy vezetik be, hogy van egy apuka, meg egy gyereke. Namost, az apukából örököl a gyerek, így ez lesz, meg az lesz. Én inkább másból indulnék ki, és ezt az apuka-gyerek kapcsolatot a végén fejteném ki teljesen, mikor már minden érthetõ lesz... Kezdjünk bele!
Csináljunk egy primitívek rajzolásához szükséges osztályt! Itt a primitív olyan geometriai alakzatokat jelent, mint a kör, háromszög, poligon, stb. Lássuk, hogy a primitívekben mi a közös! Mindegyik például pontokból áll. Legyen mondjuk ez a vizsgálódás tárgya! Szóval kellenek pontok! Csináljunk pontokat, bár ezek nem igazán kapcsolódnak most az öröklõdéshez:
struct pont { double x,y; }; |
Akkor vegyük azt, hogy csinálunk egy teljesen általános primitív osztályt, mely tartalmazni fogja a primitívünk pontjait, területét és kerületét! Lássuk:
class cPrimitiv { protected: double terulet,kerulet; pont *pontok; int pontokszama; public: cPrimitiv(int); ~cPrimitiv();
double Terulet() {return terulet; } double Kerulet() {return kerulet; } }; |
Tehát tároljuk a primitív területét és pontjait
protected eléréssel, ami azt jelenti, hogy az öröklõ osztályból
public elérésûek, kívülrõl pedig
private elérésüek. A konstruktor csupán a pontok számát kéri paraméternek. A pontokat dinamikus tömbben fogjuk tárolni, amelyet a konstruktor hoz létre, aminek a definíciója:
cPrimitiv::cPrimitiv(int psz) { pontokszama = psz; pontok = new pont[psz]; } |
Ez létre is hozta a tömböt. A destruktor pedig ezt felszabadítja:
cPrimitiv::~cPrimitiv() { delete[] pontok; //ez itt szögletes zárójel space nélkül: [ ] } |
Oké. Akkor kész is, van egy primitívünk, melynek a területérõl és kerületérõl nem tudunk, hiszen ahhoz tudni kell a primitív geometriájáról! Viszont erre a kódra, osztályra lehet már építeni különbözõ geometriájú alakzatokat. Akkor csináljunk egy négyzetet! Ehhez azt használjuk, hogy már van egy primitívünk. Ezért olyan osztályt csinálunk, ami nagyon egyszerû lesz, ugyanis ez az osztály örökölni fogja a primitív osztályunk függvényeit! És annyira, hogy teljesen a sajátja lesz, tehát nem a primitív osztályunké! Mert a primitív osztályt a program automatikusan létrehozza, és a függvényeit elérhetõvé teszi a négyzet osztályban, feltéve ha azok nem
private függvények! Akkor nézzük a négyzet osztály deklarációját:
class cNegyzet : public cPrimitiv { public: cNegyzet(double,int,int); }; |
Itt a kettõspont után álló kifejezés azt jelenti, hogy a primitív osztályunktól örököl függvényeket, és a
public kulcsszó miatt a
protected és a
public függvényeit. Elnevezés szerint így ez az osztály az öröklõ osztály, a primitiv osztály pedig az alaposztály. Használva ezeket, tudni kell, hogy
- az öröklött osztály létrehozása után meghívódik az alaposztályok konstruktora, mejd végül az öröklött osztály konstruktora.
- a destruktorokra ez pont fordítva igaz, ugyanis elõször az öröklött osztályé fut le, majd az alaposztályoké.
Mivel meghívódik a primitiv osztály konstruktora, és ráadásul ennek az osztálynak definiáltunk konstruktort, ezért nincsen megfelelõ konstruktor, ami meghívódjon. Ezért nekünk kell megmondani a fordítónak, melyik konstruktort hívja meg(ezt csak akkor lehet elhagyni, ha a paraméter nélküli alapértelmezett konstruktort akarjuk meghivatni):
cNegyzet::cNegyzet(double a,int x,int y) : cPrimitiv(4) { terulet=a*a; kerulet=4*a;
pontok[0].x=x; pontok[0].y=y; pontok[1].x=x+a; pontok[1].y=y; pontok[2].x=x+a; pontok[2].y=y+a; pontok[3].x=x; pontok[3].y=y+a; } |
Mint látjuk, ez a négyzetünk konstruktora, melynek fejléce után kettõsponttal elválasztva megadjuk az alaposztályunk meghívandó konstruktorát. Emlékezzünk vissza, hogy a primitív osztályunk konstruktora a pontok számát kéri! Ez most éppen négy (négyzet

). Így az alaposztály konstruktora meghívódik, majd azután a négyzet konstruktora, amiben mint látható, kiszámoljuk a teruletet és a kerületet, majd a pontok helyzetét is kiszámítjuk. A négyzet kontstruktora a négyzet oldalának hosszát és bal felsõ pontját kéri. Mindez után ha kiadjuk a
cNegyzet negyzet(10,5,5); |
parancsot(változó definiálást), akkor lesz egy 10 oldalu négyzetünk, melyre a
printf("%f, %f, %d, %d",negyzet.terulet, negyzet.kerulet, negyzet.pontok[2].x, negyzet.pontok[2].y); |
parancs az alábbi output-ot adja:
100.000000, 40.000000, 15, 15ami rendre a terület, kerület, és a jobb alsó pont x és y koordinátája. Remélem érthetõ, hogy minden egyes négyzet létrehozás után új primitív osztály jön létre. Ezért hibás az, hogy ha az apuka osztályból örököltetünk egy gyereket, mert minden létrehozott gyereknek új apja lesz! Ennek elkerülésére a beágyazást használjuk. Az alul található példában megírtam a kör osztályt is, mely ugyancsak a
cPrimitiv osztályra épül.
Most pár szó a beágyazásról: az öröklõdés a programkód egyszerûségét segíti elõ, viszont nincs igazi programozási eredménye, csupán magát a programozási folyamatot egyszerûsíti, nem az eredményt. Viszont a beágyazás semmi extra, hiszen például már használtuk is: méghozzá a pontoknál. Mert ha azt mondanám, hogy:
class cPrimitiv : public pont |
azt jelentené, hogy minden primitív egy ponttal rendelkezne. Ezt mi inkább beágyazással oldottuk meg, lásd felül. Szóval akkor használjuk, ha egy bázis osztály PÉLDÁNYÁHOZ több alosztály PÉLDÁNYT szeretnénk kötni. Ezért például apukánál
class cApuka {
array gyerekek;
}; |
ahol az
array egy
gyerek-ekbõl álló tömböt akar jelölni szemléletesen. Mert öröklõdéssel minden gyereknek új apja lenne! Remélem érthetõ, csupán át kell gondolni! Sok sikert!
oroklodes.rarKapcsolódó linkek:
DirectX programozás 11. - Objektumorientált programozás