4. Öröklődés Programozás II
Mielőtt belevágunk Egy Tárgy típusú objektumokat tároló tömb i. elemében tároljunk el egy új tárgyat Rossz módszer: tomb[i].setnev( uj.getnev() ); tomb[i].setertek( uj.getertek() ); Mi van, ha később új tulajdonsággal bővítjük a tárgyat? Akkor a fenti kódot is karban kell tartani macerás, és el is felejthetjük 2
Mielőtt belevágunk Egy Tárgy típusú objektumokat tároló tömb i. elemében tároljunk el egy új tárgyat Helyes módszer: tomb[i] = uj; Az értékadás ( = ) művelet alkalmazható objektumok között is Minden adattagot át fog másolni 3
Feladat Egy játékfejlesztő cég olyan programot fejleszt, amely nyilvántartja az alkalmazottai adatait. Tároljuk minden személy: Nevét (legfeljebb 50 karakter) Születési dátumát Fizetését Írj osztályt, amely a fenti adatokat tárolja. Használd az egységbezárás elvét, és az osztálydeklaráció külön header fájlban, a definíció külön forrásfájlban legyen! 4
Megoldás: dolgozo.h class Dolgozo { int fizetes; int ev, honap, nap; string nev; public: Dolgozo(const string & nev); Dolgozo(const Dolgozo & orig); int getfizetes() const; void getszuletes(int & ev, int & honap, int & nap) const; const string & getnev() const; void setfizetes(int f); void setszuletes(int ev, int honap, int nap); void setnev(const string & nev); ; 5
Megoldás: dolgozo.cpp #include "dolgozo.h Dolgozo::Dolgozo(const string & nev) { this->nev = nev; fizetes = 0; ev = honap = nap = 0; Dolgozo::Dolgozo(const Dolgozo & orig) { this->nev = orig.nev; fizetes = orig.fizetes; ev = orig.fizetes; honap = orig.fizetes; nap = orig.fizetes; 6
Megoldás: dolgozo.cpp int Dolgozo::getFizetes() const { return fizetes; void Dolgozo::getSzuletes(int & ev, int & honap, int & nap) const { ev = this->ev; honap = this->honap; nap = this->nap; const string & Dolgozo::getNev() const { return nev; void Dolgozo::setFizetes(int f) { fizetes = f; 7
Megoldás: dolgozo.cpp void Dolgozo::setSzuletes(int ev, int honap, int nap) { this->ev = ev; this->honap = honap; this->nap = nap; void Dolgozo::setNev(const string & nev) { this->nev = nev; 8
Megoldás: main.cpp #include <iostream> #include "dolgozo.h" using namespace std; #define UJ_DOLGOZO( neve ) CDolgozo neve ( #neve ) int main() { Dolgozo carmack( Carmack ); Dolgozo romero("romero"); cout << carmack.getnev() << endl; cout << romero.getnev() << endl; 9
Feladat A cégnél több fajta dolgozó van: programozó designer játék tesztelő 10
Feladat Írjunk olyan osztályt, amely egy programozó tulajdonságait tárolja: Szakmai ismeretek Munkakör A programozónak is van neve, fizetése és születési dátuma. Természetesen header + forrásfile-ban! 11
Megoldás 1. class Programozo { int fizetes; int ev, honap, nap; string nev, tudas, munka; public: Programozo(const string & nev); Programozo(const Programozo & orig); int getfizetes() const; void getszuletes(int & ev, int & honap, int & nap) const; const string & getnev() const; void setfizetes(int f); void setszuletes(int ev, int honap, int nap); void setnev(const string & nev); const string & gettudas() const; void settudas(const string & tudas); const string & getmunkakor() const; void setmunkakor(const string & munkakor); ; 12
Megoldás 1. class Programozo { int fizetes; int ev, honap, nap; string nev, tudas, munka; public: Programozo(const string & nev); Programozo(const Programozo & orig); int getfizetes() const; void getszuletes(int & ev, int & honap, int & nap) const; const string & getnev() const; void setfizetes(int f); void setszuletes(int ev, int honap, int nap); void setnev(const string & nev); const string & gettudas() const; void settudas(const string & tudas); const string & getmunkakor() const; void setmunkakor(const string & munkakor); ; 10
Megoldás 2. #include "dolgozo.h" class Programozo { Dolgozo d; string tudas, munka; public: Programozo(const string & nev); Programozo(const Programozo & orig); int getfizetes() const; void getszuletes(int & ev, int & honap, int & nap) const; const string & getnev() const; void setfizetes(int f) { d.setfizetes(f) ; void setszuletes(int ev, int honap, int nap); void setnev(const string & nev); const string & gettudas() const; void settudas(const string & tudas); const string & getmunkakor() const; ; void setmunkakor(const string & munkakor); 11
Megoldás 2. #include "dolgozo.h" class Programozo { Dolgozo d; string tudas, munka; public: Programozo(const string & nev); Programozo(const Programozo & orig); int getfizetes() const; void getszuletes(int & ev, int & honap, int & nap) const; const string & getnev() const; void setfizetes(int f) { d.setfizetes(f) ; void setszuletes(int ev, int honap, int nap); void setnev(const string & nev); const string & gettudas() const; void settudas(const string & tudas); const string & getmunkakor() const; void setmunkakor(const string & munkakor); ; 11
Megoldás 3. programozo.h #include "dolgozo.h" class Programozo: public Dolgozo { string tudas, munka; public: Programozo(const string & nev); Programozo(const Programozo & orig); ; const string & gettudas() const; void settudas(const string & tudas); const string & getmunkakor() const; void setmunkakor(const string & munkakor); 12
Megoldás 3. programozo.h #include "dolgozo.h" class Programozo: public Dolgozo { string tudas, munka; public: Programozo(const string & nev); Programozo(const Programozo & orig); ; const string & gettudas() const; void settudas(const string & tudas); const string & getmunkakor() const; void setmunkakor(const string & munkakor); 12
Megoldás: programozo.cpp #include <cstring> #include "programozo.h" Programozo::Programozo(const string & nev) { // nev????? tudas[0] = munka[0] = ; Programozo::Programozo(const Programozo & orig) { settudas(orig.tudas); setmunkakor(orig.munka); 13
Megoldás: programozo.cpp const string & Programozo::getTudas() const { return tudas; void Programozo::SetTudas(const string & tudas) { this->tudas = tudas; const string & Programozo::getMunkakor() const { return munka; void Programozo::setMunkakor(const string & munkakor) { this->munka = munka; 14
Objektum létrehozása #include <iostream> #include "dolgozo.h" #include "programozo.h" using namespace std; int main() { Programozo carmack("carmack"); Dolgozo romero("romero"); cout << carmack.getnev() << endl; cout << romero.getnev() << endl; 15
Objektum létrehozása #include <iostream> #include "dolgozo.h" #include "programozo.h" using namespace std; Mi lesz a probléma? int main() { Programozo carmack("carmack"); Dolgozo romero("romero"); cout << carmack.getnev() << endl; cout << romero.getnev() << endl; 15
Probléma: ősosztály konstruktora Az ősosztály konstruktora hívódik meg, majd a származtatott osztályé 16
Probléma: ősosztály konstruktora Az ősosztály konstruktora hívódik meg, majd a származtatott osztályé Az ősosztály konstruktora paramétert vár 16
Probléma: ősosztály konstruktora Az ősosztály konstruktora hívódik meg, majd a származtatott osztályé Az ősosztály konstruktora paramétert vár Valahogy át kell adni az ősosztály konstruktorának a paramétert 16
Megoldás Programozo::Programozo(const string & nev) : Dolgozo(nev) { tudas[0] = munka[0] = ; Programozo::Programozo(const Programozo & orig): Dolgozo(orig) { tudas = orig.tudas); munka = orig.munka; 17
Ősosztály származtatott osztály carmack típusa: Programozo romero típusa: Dolgozo void fizetes_kiir(const Dolgozo & dolgozo) { cout<<"fizetese: "<<dolgozo.getfizetes()<<endl; fizetes_kiir(carmack); // fizetes_kiir(romero); // 18
Ősosztály származtatott osztály carmack típusa: Programozo romero típusa: Dolgozo void fizetes_kiir(const Dolgozo & dolgozo) { cout<<"fizetese: "<<dolgozo.getfizetes()<<endl; fizetes_kiir(carmack); // fizetes_kiir(romero); // 18
Ősosztály származtatott osztály carmack típusa: Programozo romero típusa: Dolgozo void fizetes_kiir(const Dolgozo & dolgozo) { cout<<"fizetese: "<<dolgozo.getfizetes()<<endl; fizetes_kiir(carmack); fizetes_kiir(romero); // // Minden programozó dolgozó is 18
Ősosztály származtatott osztály carmack típusa: Programozo romero típusa: Dolgozo void fizetes_kiir(const Programozo & prg) { cout<<"fizetese: "<<prg.getfizetes()<<endl; fizetes_kiir(carmack); // fizetes_kiir(romero); // 19
Ősosztály származtatott osztály carmack típusa: Programozo romero típusa: Dolgozo void fizetes_kiir(const Programozo & prg) { cout<<"fizetese: "<<prg.getfizetes()<<endl; fizetes_kiir(carmack); // fizetes_kiir(romero); // 19
Ősosztály származtatott osztály carmack típusa: Programozo romero típusa: Dolgozo void fizetes_kiir(const Programozo & prg) { cout<<"fizetese: "<<prg.getfizetes()<<endl; fizetes_kiir(carmack); fizetes_kiir(romero); // // de nem minden dolgozó programozó! 19
Függvény felülírás Írjunk egy setfizetes függvényt a Programozo osztályba, amely a paraméterben kapott fizetéshez hozzáad 50000-et, és a kapott értéket tárolja el. Ehhez használjuk fel az ősosztály setfizetes függvényét! 20
Függvény felülírás Mi történik? void Programozo::setFizetes(int i) { setfizetes(i + 50000); 21
Függvény felülírás Mi történik? void Programozo::setFizetes(int i) { setfizetes(i + 50000); A függvény önmagát hívja meg. Ám mi az ősosztály setfizetes függvényét szeretnénk meghívni: void Programozo::setFizetes(int i) { Dolgozo::setFizetes(i + 50000); 21
protected hozzáférés Az ősosztályban protected jogosultságot is adhatunk: class Dolgozo { protected: int fizetes; int ev, honap, nap; protected: Kívülről nem látható, de a származtatott és saját osztályban igen. 22
Emlékeztető private: Kívülről és a származtatott osztályból nem látható. public: Kívülről és a származtatott osztályból is látható. 23
private öröklődés class A { A * pa; private: int a; B b; protected: int b; pa = &b; // public: int c; ; class B: private A { void f() { a = 0; // b = 0; // c = 0; // A * p = this; // ; class C: public B { void g() { a = 0; // b = 0; // c = 0; // A * p = this; // ; 24
private öröklődés class A { A * pa; private: int a; B b; protected: int b; pa = &b; // public: int c; ; class B: private A { void f() { a = 0; // b = 0; // c = 0; // A * p = this; // ; class C: public B { void g() { a = 0; // b = 0; // c = 0; // A * p = this; // ; 24
private öröklődés class A { A * pa; private: int a; B b; protected: int b; pa = &b; // public: int c; ; class B: private A { void f() { a = 0; // b = 0; // c = 0; // A * p = this; // ; class C: public B { void g() { a = 0; // b = 0; // c = 0; // A * p = this; // ; 24
private öröklődés class A { A * pa; private: int a; B b; protected: int b; pa = &b; // public: int c; ; class B: private A { void f() { a = 0; // b = 0; // c = 0; // A * p = this; // ; class C: public B { void g() { a = 0; // b = 0; // c = 0; // A * p = this; // ; 24
private öröklődés class A { A * pa; private: int a; B b; protected: int b; pa = &b; // public: int c; ; class B: private A { void f() { a = 0; // b = 0; // c = 0; // A * p = this; // ; class C: public B { void g() { a = 0; // b = 0; // c = 0; // A * p = this; // ; 24
private öröklődés class A { A * pa; private: int a; B b; protected: int b; pa = &b; // public: int c; ; class B: private A { void f() { a = 0; // b = 0; // c = 0; // A * p = this; // ; class C: public B { void g() { a = 0; // b = 0; // c = 0; // A * p = this; // ; 24
private öröklődés class A { A * pa; private: int a; B b; protected: int b; pa = &b; // public: int c; ; class B: private A { void f() { a = 0; // b = 0; // c = 0; // A * p = this; // ; class C: public B { void g() { a = 0; // b = 0; // c = 0; // A * p = this; // ; 24
private öröklődés class A { A * pa; private: int a; B b; protected: int b; pa = &b; // public: int c; ; class B: private A { void f() { a = 0; // b = 0; // c = 0; // A * p = this; // ; class C: public B { void g() { a = 0; // b = 0; // c = 0; // A * p = this; // ; 24
private öröklődés class A { A * pa; private: int a; B b; protected: int b; pa = &b; // public: int c; ; class B: private A { void f() { a = 0; // b = 0; // c = 0; // A * p = this; // ; class C: public B { void g() { a = 0; // b = 0; // c = 0; // A * p = this; // ; 24
private öröklődés class A { A * pa; private: int a; B b; protected: int b; pa = &b; // public: int c; ; class B: private A { void f() { a = 0; // b = 0; // c = 0; // A * p = this; // ; class C: public B { void g() { a = 0; // b = 0; // c = 0; // A * p = this; // ; 24
protected öröklődés class A { A * pa; private: int a; B b; protected: int b; pa = &b; // public: int c; ; class B: protected A { void f() { a = 0; // b = 0; // c = 0; // A * p = this; // ; class C: public B { void g() { a = 0; // b = 0; // c = 0; // A * p = this; // ; 25
protected öröklődés class A { A * pa; private: int a; B b; protected: int b; pa = &b; // public: int c; ; class B: protected A { void f() { a = 0; // b = 0; // c = 0; // A * p = this; // ; class C: public B { void g() { a = 0; // b = 0; // c = 0; // A * p = this; // ; 25
protected öröklődés class A { A * pa; private: int a; B b; protected: int b; pa = &b; // public: int c; ; class B: protected A { void f() { a = 0; // b = 0; // c = 0; // A * p = this; // ; class C: public B { void g() { a = 0; // b = 0; // c = 0; // A * p = this; // ; 25
protected öröklődés class A { A * pa; private: int a; B b; protected: int b; pa = &b; // public: int c; ; class B: protected A { void f() { a = 0; // b = 0; // c = 0; // A * p = this; // ; class C: public B { void g() { a = 0; // b = 0; // c = 0; // A * p = this; // ; 25
protected öröklődés class A { A * pa; private: int a; B b; protected: int b; pa = &b; // public: int c; ; class B: protected A { void f() { a = 0; // b = 0; // c = 0; // A * p = this; // ; class C: public B { void g() { a = 0; // b = 0; // c = 0; // A * p = this; // ; 25
protected öröklődés class A { A * pa; private: int a; B b; protected: int b; pa = &b; // public: int c; ; class B: protected A { void f() { a = 0; // b = 0; // c = 0; // A * p = this; // ; class C: public B { void g() { a = 0; // b = 0; // c = 0; // A * p = this; // ; 25
protected öröklődés class A { A * pa; private: int a; B b; protected: int b; pa = &b; // public: int c; ; class B: protected A { void f() { a = 0; // b = 0; // c = 0; // A * p = this; // ; class C: public B { void g() { a = 0; // b = 0; // c = 0; // A * p = this; // ; 25
protected öröklődés class A { A * pa; private: int a; B b; protected: int b; pa = &b; // public: int c; ; class B: protected A { void f() { a = 0; // b = 0; // c = 0; // A * p = this; // ; class C: public B { void g() { a = 0; // b = 0; // c = 0; // A * p = this; // ; 25
protected öröklődés class A { A * pa; private: int a; B b; protected: int b; pa = &b; // public: int c; ; class B: protected A { void f() { a = 0; // b = 0; // c = 0; // A * p = this; // ; class C: public B { void g() { a = 0; // b = 0; // c = 0; // A * p = this; // ; 25
protected öröklődés class A { A * pa; private: int a; B b; protected: int b; pa = &b; // public: int c; ; class B: protected A { void f() { a = 0; // b = 0; // c = 0; // A * p = this; // ; class C: public B { void g() { a = 0; // b = 0; // c = 0; // A * p = this; // ; 25
public öröklődés class A { A * pa; private: int a; B b; protected: int b; pa = &b; // public: int c; ; class B: public A { void f() { a = 0; // b = 0; // c = 0; // A * p = this; // ; class C: public B { void g() { a = 0; // b = 0; // c = 0; // A * p = this; // ; 26
public öröklődés class A { A * pa; private: int a; B b; protected: int b; pa = &b; // public: int c; ; class B: public A { void f() { a = 0; // b = 0; // c = 0; // A * p = this; // ; class C: public B { void g() { a = 0; // b = 0; // c = 0; // A * p = this; // ; 26
public öröklődés class A { A * pa; private: int a; B b; protected: int b; pa = &b; // public: int c; ; class B: public A { void f() { a = 0; // b = 0; // c = 0; // A * p = this; // ; class C: public B { void g() { a = 0; // b = 0; // c = 0; // A * p = this; // ; 26
public öröklődés class A { A * pa; private: int a; B b; protected: int b; pa = &b; // public: int c; ; class B: public A { void f() { a = 0; // b = 0; // c = 0; // A * p = this; // ; class C: public B { void g() { a = 0; // b = 0; // c = 0; // A * p = this; // ; 26
public öröklődés class A { A * pa; private: int a; B b; protected: int b; pa = &b; // public: int c; ; class B: public A { void f() { a = 0; // b = 0; // c = 0; // A * p = this; // ; class C: public B { void g() { a = 0; // b = 0; // c = 0; // A * p = this; // ; 26
public öröklődés class A { A * pa; private: int a; B b; protected: int b; pa = &b; // public: int c; ; class B: public A { void f() { a = 0; // b = 0; // c = 0; // A * p = this; // ; class C: public B { void g() { a = 0; // b = 0; // c = 0; // A * p = this; // ; 26
public öröklődés class A { A * pa; private: int a; B b; protected: int b; pa = &b; // public: int c; ; class B: public A { void f() { a = 0; // b = 0; // c = 0; // A * p = this; // ; class C: public B { void g() { a = 0; // b = 0; // c = 0; // A * p = this; // ; 26
public öröklődés class A { A * pa; private: int a; B b; protected: int b; pa = &b; // public: int c; ; class B: public A { void f() { a = 0; // b = 0; // c = 0; // A * p = this; // ; class C: public B { void g() { a = 0; // b = 0; // c = 0; // A * p = this; // ; 26
public öröklődés class A { A * pa; private: int a; B b; protected: int b; pa = &b; // public: int c; ; class B: public A { void f() { a = 0; // b = 0; // c = 0; // A * p = this; // ; class C: public B { void g() { a = 0; // b = 0; // c = 0; // A * p = this; // ; 26
public öröklődés class A { A * pa; private: int a; B b; protected: int b; pa = &b; // public: int c; ; class B: public A { void f() { a = 0; // b = 0; // c = 0; // A * p = this; // ; class C: public B { void g() { a = 0; // b = 0; // c = 0; // A * p = this; // ; 26
private öröklődés A private öröklődés elfedi azt, hogy egy A osztály a B-ből lett származtatva Ez csupán egy implementációs fogás, amit helyettesíthetünk azzal, hogy az A osztályba beágyazunk egy B objektumot Éppen ezért private öröklődésre csak nagyon ritkán van szükség 67
Beágyazás Öröklődés Írjunk osztályt, amely egy személy adatait tárolja Az adatok: állandó lakcím, ideiglenes cím, telefonszám, név, beszélt nyelvek Használhatunk itt öröklődést? 68
Beágyazás Öröklődés Írjunk osztályt, amely egy személy adatait tárolja Az adatok: állandó lakcím, ideiglenes cím, telefonszám, név, beszélt nyelvek Használhatunk itt öröklődést? Egy személy nem cím Egy személy nem név Egy személy nem beszélt nyelvek listája 69
Beágyazás Öröklődés Egy személy nem cím Egy személy nem név Egy személy nem beszélt nyelvek listája DE: Egy személynek van neve, van címe, és van egy listája az általa beszélt nyelvekről 70
Beágyazás Öröklődés Írjunk egy osztályt, amely vállalati autókat ábrázol Az autóról tároljuk az autó márkáját, és a hozzá tartozó sofőr nevét Öröklődhet-e ez az autó osztály a személy osztályból? Hiszen akkor az autóban meglenne minden, ami a személyben is 71
Beágyazás Öröklődés Írjunk egy osztályt, amely vállalati autókat ábrázol Az autóról tároljuk az autó márkáját, és a hozzá tartozó sofőr nevét Öröklődhet-e ez az autó osztály a személy osztályból? Hiszen akkor az autóban meglenne minden, ami a személyben is NEM! Az autó nem azonos az azt vezető személlyel 72
Beágyazás Öröklődés Írjunk egy osztályt, amely egy dolgozó adatait tárolja A dolgozó adatai: cím, ideiglenes cím, név, telefonszám, beszélt nyelvek, fizetés, beosztás megnevezése Öröklődhet a dolgozó osztály a személy osztályból? 73
Beágyazás Öröklődés Írjunk egy osztályt, amely egy dolgozó adatait tárolja A dolgozó adatai: cím, ideiglenes cím, név, telefonszám, beszélt nyelvek, fizetés, beosztás megnevezése Öröklődhet a dolgozó osztály a személy osztályból? Igen, hiszen a dolgozó egyben személy is 74
Beágyazás Öröklődés Beágyazást használunk, ha azt akarjuk kifejezni, hogy A rendelkezik B, C, D, stbvel Öröklődést használunk akkor, ha azt akarjuk kifejezni, hogy A az egyben B is, azaz A-ra időnként elég B-ként tekinteni a kódban 75
Feladat Egy web áruházban az alábbi árufajtákat lehet rendelni: könyv film játék Minden árunak van neve, és ára. A könyvnek van oldalszáma és szerzője. A filmnek van rendezője, és szereplőgárdája. A játéknak van tömege, és egy korhatár besorolása (hány éves kortól ajánlott). 76
Feladat Továbbá, minden áruhoz tartozik egy dátum, ami megadja, hogy mikortól rendelhető az áruházban. A dátumokhoz szükség van összehasonlító műveletre, amely megadja, hogy két dátum közül melyik a korábbi. 77
Feladat Tervezd meg az osztályokat, amelyekkel leírhatóak az árucikkek. Mely osztályoknak szükséges közös ősosztály? Mely osztályokat használunk beágyazottan, és mely osztályokba ágyazzuk be őket? 78
Házi feladat A készülő játékban különböző karakterek szerepelnek. A Lovagnak van neve, életereje, sebzése (vigyázat, ez új!), tapasztalati pontja, és szintje A Zombinak* van neve, életereje, sebzése, illetve, hogy mennyi tapasztalati pontot kap az a karakter (Lovag), aki legyőzi * Bármi mással helyettesíthető 79
Házi feladat Módosítsd a Lovag osztályt, valamint írd meg a Zombi osztályt, illetve a szükséges osztályokat úgy, hogy ha minden karaktert ki kell egészíteni egy új tulajdonsággal, akkor valóban minden karakter osztály megkapja azt 80
Házi feladat A karakter osztályok rendelkezzenek egy sebez függvénnyel, amely paraméterül kap egy másik karaktert A függvény a paraméterül kapott karakter életerejét csökkentse a támadó sebzésének értékével, azaz: a.sebez(b); Ekkor b életereje a karakter sebzésének értékével csökken 81
Házi feladat Fontold meg alaposan, hogy a sebez függvényt melyik osztályban helyezed el Fontold meg alaposan, hogy milyen típusú paramétere legyen Fontos, hogy a sebez függvény paraméterének bármilyen karaktert megadhassunk (később lehet, hogy még több karakter osztályunk lesz, a sebez függvényt ne kelljen ezekhez módosítani) 82
Házi feladat A játékban egyelőre csak egy ellenfél legyen Bővítsd ki a Menü osztályt egy olyan függvénnyel, amely az adott azonosítóval rendelkező menüpontot eltávolítja a menüből Adj egy támad menüpontot a menühöz (vigyázat, nem az osztályhoz, hanem a program az induláskor ezzel az új menüvel is lássa el a menüt) 83
Házi feladat A támad menüpontot választva a lovag vigyen be a sebzési értékének megfelelő sebzést az ellenfélnek Az ellenfél pedig válaszul 20%-os valószínűséggel vigyen be a saját sebzésének megfelelő sebzést a lovagnak (tipp: használd a rand függvényt) Mindehhez használd fel a sebez függvényt 84
Házi feladat Ha az ellenfél meghalt (életereje 0, vagy kevesebb), akkor a menüből távolítsuk el a támad menüpontot Ha a lovag hal meg, akkor a program lépjen ki Továbbra is minden osztályhoz külön header és forrásfájlt írj! 85