A kiindulási alap egy egyszerű heterogén kollekció: Alakzat, Szakasz, Kör, Poligon stb.
A problémánk ezzel a kóddal az, hogy nagyon belefolyik az osztályokba a memóriakezelés problémája.
Rengeteg a new
és a delete
, nekünk kell megírni a másoló konstruktorokat, destruktorokat,
és ez sok hibalehetőséget hordoz.
Az első változat letölthető innen: heterogen_alakzat_eredeti.zip.
Az elvégzett módosítások az alábbiak:
-
Az összes dinamikus tömböt
std::vector
-ra cseréltük. -
A poligon át tud venni konstruktorparaméterben egy pontokból álló vektort. Így annak csúcsai már a konstruktorban megadhatóak. Ugyanolyan egyszerűen példányosítható, mint az összes többi alakzat.
-
Az alakzatokhoz bevezettünk egy
masol()
virtuális függvényt, amely minden alakzatról a típusának megfelelő, dinamikusan foglalt másolatot készít. Ezzel lehetővé tettük a heterogén kollekció, a rajztábla másolását. -
Az alakzatokat reprezentáló
Alakzat *
pointert egy osztályba csomagoltuk, amely elrejti előlünk a heterogén alakzat dinamikus memóriakezelése miatti problémákat. Ez lett az új Alakzat osztály. Lásd lentebb.
A legfontosabb eredményünk a következő osztály:
class Alakzat {
private:
AlakzatOs * a;
public:
explicit Alakzat(AlakzatOs * a) : a(a) {}
Alakzat(Alakzat const & masolando) {
a = masolando.a->masol();
}
Alakzat& operator=(Alakzat const & masolando) {
if (this != &masolando) {
delete a;
a = masolando.a->masol();
}
return *this;
}
~Alakzat() {
delete a;
}
AlakzatOs * operator->() {
return a;
}
AlakzatOs const * operator->() const {
return a;
}
};
Ez érték szerint másolhatóvá tesz bármilyen alakzatot. A konstruktorában átvesz egy dinamikusan foglalt példányt, aztán 1) ha megszűnik, akkor megszüntetni azt; 2) ha lemásolódik, akkor lemásolja azt; 3) a nyíl operátoron keresztül pedig pointerszerű interfésszel elérhetővé teszi a tagfüggvényeit.
Miért jó ez? Mert a rajztábla (a heterogén kollekció) most csak ennyi:
class Rajztabla {
private:
std::vector<Alakzat> tabla;
public:
void felrak(AlakzatOs *ap) { // kötelezően dinamikusan foglalt
tabla.push_back( Alakzat(ap) ); // becsomagoljuk
}
void rajzol() {
for (Alakzat & a : tabla)
a->rajzol();
}
void mozgat(Point d) {
for (Alakzat & a : tabla)
a->mozgat(d);
}
};
Ennek nem kell se másoló konstruktort, se destruktort írnunk. A dinamikus tömböt a vektor kezeli,
a benne lévő dinamikusan foglalt objektumokat pedig a fenti Alakzat osztály. Sehol egy
new
, sehol egy delete
. Végre a feladatra tudunk koncentrálni!
A végleges változat letölthető innen: heterogen_alakzat_vegleges.zip.