Definiálj alakzat ősosztályt, és abból származtatott, annak interfészét megvalósító a) téglalapot és b) kört!
Az alakzatoknak általában a színét és a pozícióját szeretnénk eltárolni. A szín egy színkód, egész szám,
0xRRGGBB
(red, green, blue) formában. Például
0xFF0000
(nagyon piros),
0xFFFF00
(piros+zöld = sárga),
0x7c2128
(BME-bordó),
0x052a4b
(VIK-kék).
Az alakzat konstruktora vegye át a közös attribútumokat! A többi osztályé pedig vegye át paraméterként az összes attribútumot. Legyen mindegyik osztálynak adatokat kiíró függvénye – a kiírás formátuma lényegtelen, csak látszódjanak az attribútumok. Ezen felül pedig lehessen lekérdezni a kerületüket!
Teglalap t(0xFF0000, 100, 20, 50, 60);
Kor k(0x00FFFF, 50, 50, 100);
t.kiir(); /* Téglalap x=100 y=20 sz=50 m=60 */
k.kiir(); /* Kör x=50 y=50 r=30 */
std::cout << t.kerulet(); /* 220 */
std::cout << k.kerulet(); /* 628.3184 */
Készíts rajztábla osztályt, amely legfeljebb 100 alakzat adatait tudja tárolni! (Jó most a statikus tömb is, nem ez a feladat lényege.) Lehessen új alakzatot hozzáadni, „beregisztrálni” a rajztáblába, és lehessen egy adott indexű alakzatot törölni belőle!
Teglalap t(0xFF0000, 100, 20, 50, 60);
Kor k(0x00FFFF, 50, 50, 100);
Rajztabla r;
r.hozzaad(t);
r.hozzaad(k);
r.mindet_rajzol(); /* megjelennek a téglalap és a kör adatai */
std::cout << r.osszkerulet(); /* az összes kerület összege */
r.torol(0); /* elfelejti a téglalapot */
r.mindet_rajzol(); /* csak a kör jelenik meg */
Rajzolj UML diagramot, amely ábrázolja a megírt osztályok kapcsolatát!
A fenti megoldás szembetűnő problémája, hogy a törlés pillanatában tulajdonképp a téglalap objektum nem törlődött ki, továbbra is létezik lokális változóként. Csak a rajztábla látóköréből került ki. Jobb lenne, ha a rajztábla nem csak ismerné az alakzat objektumokat, hanem ő maga tartalmazná azokat.
Ez megoldható az alakzatok dinamikus foglalásával. Alakítsd át ezért úgy a kódot, hogy az egyes objektumokat dinamikusan hozod létre!
int main() {
Rajztabla r;
r.hozzaad(new Teglalap(0xFF0000, 100, 20, 50, 60));
r.hozzaad(new Kor(0x00FFFF, 50, 50, 100));
r.mindet_rajzol();
r.torol(0); /* elfelejti a téglalapot, delete is */
r.mindet_rajzol();
} /* delete a megmaradt alakzatokra */
Módosítsd az UML diagramod, hogy ezt a működést tükrözze!
A rajzolóprogramunkban a rajztábla osztály nem csak az éppen kezelt rajzot modellezheti, hanem a vágólapot is. Ha a menüből kiválasztjuk a Másol funkciót, akkor a rajzelemek a vágólapra kerülnek. Ha ezek után a rajzot módosítjuk, akkor az alakzatok megváltozó attribútumai nincsenek hatással a vágólapon lévő objektumokra. Pl. ha a vágólapra egy piros téglalapot teszünk, és utána a rajzon az eredetit átszínezzük sárgára, akkor a Beillesztés művelet hatására piros téglalapot kapunk.
Írd meg ennek a műveletnek a támogatására a rajztábla osztály másoló konstruktorát! Ilyennek amúgy is kellene léteznie, ha megoldható... Emlékezz vissza: ha egy osztálynak van destruktora, kellene neki másoló konstruktora és értékadó operátora is legyen.
A másoló konsturktor megírásakor bele fogsz futni egy problémába. A lemásolandó rajztábla egy
heterogén kollekciót tartalmaz, alakzatokat. Ezeknek az alakzatoknak a pontos típusát nem ismered,
csak Alakzat*
pointereket látsz. Ennek ellenére típushelyesen kell tudni másolni az
alakzatokat: bár nem tudod, mi a típusuk, még háromszög másolata háromszög, téglalap másolata téglalap
kell legyen.
Hogy lehet ezt megoldani? A kulcskérdés: ki tudja azt, hogy melyik alakzat milyen típusú?
Az std::vector
(#include <vector>)
a C++ beépített dinamikus tömb
osztálya. Használata a következő:
#include <vector>
std::vector<int> v1; /* üres vektor, int tömb */
v1.resize(200); /* átméretezés 200-ra, csupa 0 lesz */
v1[12] = 123; /* indexelhető */
v1.push_back(9); /* a végére 9 kerül */
std::cout << v1.size(); /* 201 lett a mérete */
v1.erase(v1.begin() + 12); /* 12. elem törlése */
std::cout << v1.size(); /* 200 */
Írd át a rajztábla osztályod, hogy 100 elemű statikus tömb helyett vektort használjon! Ezzel a 100-as limit automatikusan megszűnik.
std::vector
-t, amely a csúcspontokat
tartalmazza páronként! Ezek a csúcspontok távolságai a referenciaponthoz képest. Ha páratlan a mérete,
vagy túl kevés eleme van, kivételt kell dobni.
std::vector<double> csucsok = { 10, 20, 30, 40, 50, 60 };
Sokszog s1(0x00C000, 5, 6, csucsok);
Használd az alábbi Vektor
osztályt!
struct Vektor {
double x, y;
Vektor() {}
Vektor(double x, double y) : x(x), y(y) {}
Vektor operator-(Vektor v) const {
return Vektor(x-v.x, y-v.y);
}
double hossz() const {
return sqrt(x*x + y*y);
}
};
Ha kész, válaszold meg a kérdést: miért/hogyan működik a következő programrész?
Sokszog s2(0x00C000, 5, 6, { 10, 20, 30, 40, 50, 60 });