Elemi Alkalmazások Fejlesztése II. Osztályok közötti kapcsolatok • örökl˝odés • asszociáció • aggregáció • kompozíció
1. Feladat Készítsünk programot, amellyel testek térfogatát határozhatjuk meg, illetve megadhatjuk azt is, hogy az egyes testfajtákból hány objektum létezik! A lehetséges fajták: • szabályos sokszögek: gömb, kocka, tetraéder, oktaéder; • hasáb jelleg˝u testek: henger, négyzet alapú hasáb, szabályos háromszög alapú hasáb; • gúla jelleg˝u testek: kúp, négyzetes gúla.
2. A megoldás menete Az el˝oz˝o órán megismert megoldást módosítsuk. Hasáb jelleg˝u testek esetén az alapterület kiszámítását egy beágyazott objektumra delegáljuk. Így elérhet˝o, hogy négyzet alapú hasáb, illetve gúla esetén ugyanazt a m˝uveletet használjuk fel, nem kell ugyanazt a megvalósítást elkészítenünk két különböz˝o osztályban. Ugyanez igaz háromszög, illetve kör alap esetén is. Az alapterület kiszámítását az Alap absztrakt osztály deklarálja, amit a konkrét Kor, Negyzet, Haromszog osztályokban valósítunk meg. A beágyazott objektum ennek megfelel˝oen az Alap osztályból származtatott konkrét osztály példánya lesz.
3. Osztálydiagram Test
Gömb
Szabályos
Hasáb
Kúp
Gúla
Négyzetes
Kocka
Háromszöges
Tetraéder NGúla Oktaéder
Henger
Test # méret : double - darab : int # Test(méret : double) + ˜Test() + Térfogat() : double + Darab() : int
Szabályos - darab : int # Szabályos(méret : double) + ˜Szabályos() + Térfogat() : double # Szorzó() : double + Darab() : int
Hasáb # magasság : double - darab : int # alap # Hasáb(méret : double, magasság : double) + ˜Hasáb() + Térfogat() : double + Darab() : int
Alap + Terület(m : double) : double
Alap + Terület(m : double) : double
Kör
Négyzet
Háromszög
+ Terület(m : double) : double
+ Terület(m : double) : double
+ Terület(m : double) : double
Szabályos - darab : int # Szabályos(méret : double) + ˜Szabályos() + Térfogat() : double # Szorzó() : double + Darab() : int
Gömb - darab : int - szorzó : double = 4π/3 + Gömb(méret : double) + ˜Gömb() # Szorzó() : double + Darab() : int
Kocka - darab : int + Kocka(méret : double) + ˜Kocka() # Szorzó() : double + Darab() : int
Tetraéder
Oktaéder
- darab : int √ - szorzó : double = 2/12
- darab : int √ - szorzó : double = 2/3
+ Tetraéder(méret : double) + ˜Tetraéder() # Szorzó() : double + Darab() : int
+ Oktaéder(méret : double) + ˜Oktaéder() # Szorzó() : double + Darab() : int
Hasáb # magasság : double - darab : int # Hasáb(méret : double, magasság : double) + ˜Hasáb() + Térfogat() : double + Darab() : int
Gúla - darab : int # Gúla(méret : double, magasság : double) + ˜Gúla() + Térfogat() : double + Darab() : int
Hasáb # magasság : double - darab : int # Hasáb(méret : double, magasság : double) + ˜Hasáb() + Térfogat() : double + Darab() : int
Henger
Négyzetes
Háromszöges
- darab : int
- darab : int
- darab : int
+ Henger(méret : double, magasság : double) + ˜Henger() + Darab() : int
+ Négyzetes(méret : double, magasság : double) + ˜Négyzetes() + Darab() : int
+ Háromszöges(méret : double, magasság : double) + ˜Háromszöges() + Darab() : int
Gúla - darab : int # Gúla(méret : double, magasság : double) + ˜Gúla() + Térfogat() : double + Darab() : int
Kúp
NGúla
- darab : int
- darab : int
+ Kúp(méret : double, magasság : double) + ˜Kúp() + Darab() : int
+ NGúla(méret : double, magasság : double) + ˜NGúla() + Darab() : int
4. Osztályok Nem változnak az el˝oz˝o megoldáshoz képest: • Test, • Szabalyos, • Gomb, • Kocka, • Tetraeder, • Oktaeder.
5. Az Alap osztály class Alap { public: virtual double Terulet(double m) const = 0; ~Alap() {} protected: Alap() {} };
6. A Kor osztály class Kor : public Alap { public: double Terulet(double m) const { return PI * m * m; } };
7. A Negyzet osztály class Negyzet : public Alap { public: double Terulet(double m) const { return m * m; } };
8. A Haromszog osztály class Haromszog : public Alap { public: double Terulet(double m) const { return SQ3 * m * m / 4.0; } }
9. A Hasab osztály class Hasab : public Test { public: ~Hasab(); double Terfogat() const; static int Darab() { return darab; } protected: Hasab(double meret, double magassag); protected: double magassag; Alap *alap; private: static int darab; };
int Hasab::darab = 0; Hasab::Hasab(double meret, double magassag) : Test(meret) { this->magassag = magassag; darab++; } Hasab::~Hasab() { darab--; } double Hasab::Terfogat() const { return alap->Terulet(meret) * magassag; }
10. A Gula osztály class Gula : public Hasab { public: ~Gula(); double Terfogat() const; static int Darab() { return darab; } protected: Gula(double meret, double magassag); private: static int darab; };
int Gula::darab = 0; Gula::Gula(double meret, double magassag) : Hasab(meret, magassag) { darab++; } Gula::~Gula() { darab--; } double Gula::Terfogat() const { return (alap->Terulet(meret) * magassag) / 3.0; }
11. A Henger osztály class Henger : public Hasab { public: Henger(double meret, double magassag); ~Henger(); static int Darab() { return darab; } private: static int darab; };
int Henger::darab = 0; Henger::Henger(double meret, double magassag) : Hasab(meret, magassag) { darab++; alap = new Kor(); } Henger::~Henger() { darab--; delete alap; }
12. A Negyzetes osztály class Negyzetes : public Hasab { public: Negyzetes(double meret, double magassag); ~Negyzetes(); static int Darab() { return darab; } private: static int darab; };
int Negyzetes::darab = 0; Negyzetes::Negyzetes(double meret, double magassag) : Hasab(meret, magassag) { darab++; alap = new Negyzet(); } Negyzetes::~Negyzetes() { darab--; delete alap; }
13. A Haromszoges osztály class Haromszoges : public Hasab { public: Haromszoges(double meret, double magassag); ~Haromszoges(); static int Darab() { return darab; } private: static int darab; };
int Haromszoges::darab = 0; Haromszoges::Haromszoges(double meret, double magassag) : Hasab(meret, magassag) { darab++; alap = new Haromszog(); } Haromszoges::~Haromszoges() { darab--; delete alap; }
14. A Kup osztály class Kup : public Gula { public: Kup(double meret, double magassag); ~Kup(); static int Darab() { return darab; } private: static int darab; };
int Kup::darab = 0; Kup::Kup(double meret, double magassag) : Gula(meret, magassag) { darab++; alap = new Kor(); } Kup::~Kup() { darab--; }
delete alap;
15. A NGula osztály class NGula : public Gula { public: NGula(double meret, double magassag); ~NGula(); static int Darab() { return darab; } private: static int darab; };
int NGula::darab = 0; NGula::NGula(double meret, double magassag) : Gula(meret, magassag) { darab++; alap = new Negyzet(); } NGula::~NGula() { darab--; delete alap; }
A f˝oprogram értelemszer˝uen nem változik az el˝oz˝o megoldáshoz képest.
16. Javítás Vegyük észre, hogy Alap típusú elemekb˝ol elég egyetlen példányt létrehoznunk, azt közösen használhatják a megfelel˝o testek. Tehát elég egyetlen Kör, egytelen Négyzet és egyetlen Háromszög objektum. A közös Kör objektumot használhatja az összes kör alapú test. (Eddig minden test külön objektumot hozott létre.)
Alap + Terület(m : double) : double
Kör
Négyzet
Háromszög
- példány : Kör
- példány : Négyzet
- példány : Háromszög
+ Terület(m : double) : double + Példány() : Kör
+ Terület(m : double) : double + Példány() : Négyzet
+ Terület(m : double) : double + Példány() : Háromszög
17. A Kor osztály class Kor : public Alap { public: double Terulet(double m) const { return PI * m * m; } static Kor *Peldany(); private: static Kor *peldany; Kor() {} };
Kor *Kor::peldany = 0; Kor *Kor::Peldany() { if ( peldany == 0 ) return peldany; }
peldany = new Kor();
18. A Negyzet osztály class Negyzet : public Alap { public: double Terulet(double m) const { return m * m; } static Negyzet *Peldany(); private: static Negyzet *peldany; Negyzet() {} };
Negyzet *Negyzet::peldany = 0; Negyzet *Negyzet::Peldany() { if ( peldany == 0 ) peldany = new Negyzet(); return peldany; }
19. A Haromszog osztály class Haromszog : public Alap { public: double Terulet(double m) const { return SQ3 * m * m / 4.0; } static Haromszog *Peldany(); private: static Haromszog *peldany; Haromszog() {} };
Haromszog *Haromszog::peldany = 0; Haromszog *Haromszog::Peldany() { if ( peldany == 0 ) peldany = new Haromszog(); return peldany; }
Ezután az összes Hasáb jelleg˝u osztály konstruktorában a new helyett az osztályszint˝u Peldany m˝uvelet szerepel. A destruktorban pedig elmarad a felszabadítás.
Például a Henger osztályban: Henger::Henger(double meret, double magassag) : Hasab(meret, magassag) { darab++; alap = Kor::Peldany(); } Henger::~Henger() { darab--; }
20. Asszociáció és aggregáció implementálása Ezeket a kapcsolatokat mutatók segítségével lehet megvalósítani, ahogy a Hasáb osztály és az Alap osztály kapcsolatánál láthattuk. Ha a multiplicitás többszörös, akkor egy megfelel˝o méret˝u mutató tömböt kell felvenni.
21. Kompozíció implementálása A kompozíció attribútum jelleg˝u kapcsolat, ezért a kompozíciós objektum beágyazott objektumként (adattag) jelenik meg az összetett objektumban. Ha egyéb, gyakorlati okokból mutató(ka)t használunk, akkor az összetett objektum létrehozásakor, a konstruktorban, létre kell hoznunk a beágyazott objektumokat is, és a mutatókat csak az objektum megsz˝unésekor, a destruktorban, változtathatjuk meg, szabadíthatjuk fel.
Rendszer név
∗
Bolygó név
Csillag class Rendszer { Rendszer(string nev, int meret, string nevek[]); ~Rendszer(); ... private: Csillag csillag; int bolgyoszam; Bolygo* bolygok[]; string nev; };
class Bolygo { Bolygo(string nev); ... }; Rendszer::Rendszer(string nev, int meret, string nevek[]) { this.nev = nev; bolygoszam = meret; // csillag automatikusan létrejön bolygok = new Bolygo *[bolygoszam]; for ( int i = 0; i < bolygoszam; i++ ) bolygok[i] = new Bolygo(nevek[i]); } Rendszer::~Rendszer() { delete [] bolygok; }