300 likes | 367 Views
Osztálytervezés. Ficsor Lajos Miskolci Egyetem Általános Informatikai Tanszék. Osztály tervezés. Egy nyelv szabályrendszere számos konstrukciót megenged A software fejlesztés során egy adott problémát kell megoldani
E N D
Osztálytervezés Ficsor Lajos Miskolci Egyetem Általános Informatikai Tanszék A C++ programozási nyelv 11. (Osztálytervezés)
Osztály tervezés • Egy nyelv szabályrendszere számos konstrukciót megenged • A software fejlesztés során egy adott problémát kell megoldani • Szükséges tanulmányozni, hogy adott cél elérése érdekében milyen nyelvi szerkezet használata a legcélszerűbb A C++ programozási nyelv 11. (Osztálytervezés)
Információ rejtés • A jól tervezett osztály belső részleteinek ismerete szükségtelen a használatához • Interface: a public tagfüggvények összessége • ezt kell ismernie az osztály használójának • a leszármazott osztály se tételezzen fel implementációs részleteket a bázisosztályáról A C++ programozási nyelv 11. (Osztálytervezés)
A jó osztály interface 1. • Teljes • minden funkciót tartalmaz, ami az osztálytól elvárható • nem az adott alkalmazás szempontjai határozzák meg • újrafelhasználható egység • Minimális • nem tartalmaz a felhasználó számára érdektelen (esetleg veszélyes) elemeket • belső felhasználású funkciók private vagy protected minősítésűek • a belső áttervezés nincs rá hatással A C++ programozási nyelv 11. (Osztálytervezés)
A jó osztály interface 2. • Kezelhető méretű • általában legfeljebb néhány tíz metódus • A sok funkció között nagyobb valószínűséggel lesznek hasonlóak (félreértés veszélye!) • A terjedelmes interface általában tervezési hibára utal: • Az interface része belső funkció is • Az osztály határait nem jól állapítottuk meg, és túl sok feladatot akarunk rábízni. A helyes architektúra kialakítása érdekében az eredetileg tervezett osztályt több osztályra kell bontani, és ezek között leszármaztatással vagy más mechanizmussal megteremteni a kapcsolatot. A C++ programozási nyelv 11. (Osztálytervezés)
Az osztály interface részei • Kezelő függvények • inicializáló, értékadó, konverziós stb. függvények • sokszor nem is a felhasználó program, hanem a fordítóprogram implicite hívja meg. • Elérési függvények • Az adattagok értékének elérésére vagy azok értékének módosítására. • Munkavégző függvények • Az osztály lényegi funkcióit aktivizáló függvények. A C++ programozási nyelv 11. (Osztálytervezés)
Kezelő függvények • A kezelő függvények kialakítása az osztály használhatóságát alapvetően befolyásolja • Egyes kezelő függvények hiánya vagy helytelen implementációja a jól implementált munkavégző függvények ellenére is programhibákhoz vagy hibás működéshez vezethet A C++ programozási nyelv 11. (Osztálytervezés)
Kezelő függvények tervezésének szempontjai 1. • Hogyan kell az objektumoknak létrejönniük és megszűnniük? • konstruktorok száma, paraméterlistájuk • a desktruktor működése • a new és delete operátorok esetleges átdefiniálásának szükségességét. • Miben különbözik egy objektum inicializálása és értékadása? • A konstruktorok és az értékadó operátor működése. A C++ programozási nyelv 11. (Osztálytervezés)
Kezelő függvények tervezésének szempontjai 2. • Milyen kezdőállapoto(ka)t vehet fel egy objektum a keletkezése után? • valamennyi tagfüggvény implementációját befolyásolja, hogy milyen állapotot tételezhet fel, illetve köteles ellenőrizni. • Hogyan történik az objektumok érték szerinti átadása? • A copy konstruktor tervezéséhez. A C++ programozási nyelv 11. (Osztálytervezés)
Kezelő függvények tervezésének szempontjai 3. • Milyen legális értékeket vehet fel az osztály egy objektuma? • A tagfüggvények hibaellenőrzését befolyásolja. • Van bázisosztálya az új osztálynak? • Mely funkciók örökölhetők változatlanul? • Vannak-e a bázisosztályban olyan virtuális függvények, amelyeket át kell definiálni? • Vannak-e a bázisosztályban olyan függvények, amelyeket felül kell definiálni? A C++ programozási nyelv 11. (Osztálytervezés)
Kezelő függvények tervezésének szempontjai 4. • Lesz-e várhatóan az osztálynak leszármazott osztálya? • Mely tagfüggvények, esetleg adattagok legyenek protected minősítésűek? • Melyek azok a funkciók, amelyeket a leszármazott osztályoknak át kell definiálni, azaz itt virtuálisnak célszerű minősíteni? A C++ programozási nyelv 11. (Osztálytervezés)
Kezelő függvények tervezésének szempontjai 5. • Milyen típusú konverziók megengedettek, illetve hasznosak? • Az általunk deklarált konverziós operátorokat a fordító a szükséges helyzetekben implicite (kifejezett kérésünk nélkül) is használni fogja. • Az implicit konverziót elkerülhetjük azáltal, hogy bizonyos konverziókat egyszerű tagfüggvények formájában fogalmazunk meg. • Érdemes gondolni arra, hogy az egyoperandusú konstruktor egyben konverziós operátor is! A C++ programozási nyelv 11. (Osztálytervezés)
Kezelő függvények tervezésének szempontjai 6. • Milyen operátorok definiálása lehet hasznos az osztály használatában? • Az operátor overloading tervezéséhez. • A felhasználó számára nem ajánlott, de az osztály implementációja számára hasznos operátorok definiálhatók private (esetleg protected) minősítéssel. A C++ programozási nyelv 11. (Osztálytervezés)
Kezelő függvények tervezésének szempontjai 7. • Miknek lehet szüksége a nem public tagok elérésére? • Mely adattagokat és tagfüggvényeket célszerű protected minősítéssel ellátni? • Mely osztályok illetve külső függvények kaphatják meg a friendminősítést? • Információ rejtésnek ellentmondó konstrukciók => gondosan elemzendő a szükségességük. • Különösen érdemes átgondolni, hogy a public adattag használata valóban elkerülhetetlen-e? A C++ programozási nyelv 11. (Osztálytervezés)
Konstruktor tervezésének szempontjai • A felhasználás kényelme • A konstruktornak konverziós szerepe is van! • Alapértelmezés szerinti konstruktor átdefiniálása szükséges-e? • copy konstruktor! A C++ programozási nyelv 11. (Osztálytervezés)
Destruktor tervezésének szempontjai • Minden "mellékhatás" eltüntetése. • Bármilyen (legális) állapotban levő objektumra működnie kell! • Ha az osztály bázisosztály is lehet: a destruktornak nem kell-e virtuálisnak lennie? A C++ programozási nyelv 11. (Osztálytervezés)
Operátorok tervezésének szempontjai 1. • Alapszabály: minden olyan operátort definiálni kell, ami az adott osztály használata során természetesnek tűnik. • Tervezési hiba, ha egy átértelmezett operátor jelentése a programozó számára nem egyértelmű. Különösen problémás egy, az operátor eredeti jelentésének ellentmondó jelentés definiálása. • Különleges szerepe van az = (értékadó) operátornak. A C++ programozási nyelv 11. (Osztálytervezés)
Operátorok tervezésének szempontjai 2. • Ha egy relációs operátort értelmezünk, az összeset definiáljuk. • Sokszor hasznos lehet (és bármilyen típusú objektumra alkalmazható) az == és a != operátorok implementálása. • Nagyon sokszor hívott funkcióra kényelmes megoldás lehet a () - függvényhívás-operátor - átdefiniálása. A C++ programozási nyelv 11. (Osztálytervezés)
Operátorok tervezésének szempontjai 3. • copy konstruktor, értékadás operátor és destruktor: két olyan műveletet, amelyeket azonosan kell implementálni: • az adattagok által használt memóriaterület felszabadítása ("destroy") • az adattagok másolása egyik objektumból a másikba ("copy"). • Ezeket a műveleteket célszerű private tagfüggvény alakjában implementálni. A C++ programozási nyelv 11. (Osztálytervezés)
Operátorok tervezésének szempontjai 4. • A segédfügvények felhasználásával: • copy konstruktor: "copy" • értékadás: "destroy" + "copy" • destruktor: "destroy" A C++ programozási nyelv 11. (Osztálytervezés)
Konstans tagfüggvények használata 1. • Minden olyan tagfüggvényt, amely nem változtatja meg az objektum állapotát, deklaráljunk konstans tagfüggvényként. • Konstans objektumra csak konstans tagfüggvény hívható meg. • Ha egy tagfüggvényből létezik const minősítésű és minősítetlen változat is, const objektumra const tagfüggvény hívódik meg. A C++ programozási nyelv 11. (Osztálytervezés)
Konstans tagfüggvények használata 2. • Az, hogy egy tagfüggvény definíciója nem tartalmaz olyan utasítást, amely valamely adattag értékét közvetlenül megváltoztatja, még nem jelenti azt, hogy valamilyen közvetettebb módon nem változhat az objektum állapota. • Egy tagfüggvény számára a const minősítés megadásához gyakran a működésének a funkcionális elemzése szükséges. • Példa: CPPEX29 A C++ programozási nyelv 11. (Osztálytervezés)
Objektum átadása hivatkozás szerint 1. • Az érték szerint átadott paraméterek és visszatérési érték felesleges konstruktor, copy konstruktor és destruktor hívások. • Példa: CPPEX30.C class String {…} class Szemely { String nev; String cim; …} A C++ programozási nyelv 11. (Osztálytervezés)
Objektum átadása hivatkozás szerint 2. Szemely szemelyvissza1(Szemely sz) { return sz; } Meghívása: Szemely en("Ficsor", "Miskolc"); Szemely vissza("",""); vissza = szemelyvissza1(en); A C++ programozási nyelv 11. (Osztálytervezés)
Objektum átadása hivatkozás szerint 3. 13 implicit függvényhívás! A C++ programozási nyelv 11. (Osztálytervezés)
Referencia objektum helyett 1. • Ne adjunk vissza referenciát, ha értéket kell visszaadni. • Ez gyakran érvénytelen hivatkozás visszaadását jelenti. A C++ programozási nyelv 11. (Osztálytervezés)
Ne adjuk vissza lokális objektum címét 1. Helyes implementáció: class Komplex { double valos; double kepzetes; public: Komplex(double v, double k); Komplex operator+(const Komplex& masik) {return Komplex(valos + masik.valos, kepzetes+masik.kepzetes); } A C++ programozási nyelv 11. (Osztálytervezés)
Ne adjuk vissza lokális objektum címét 2. • Helytelen implementáció: Komplex& operator+(const Komplex& masik) { Komplex eredmeny(valos + masik.valos, kepzetes+masik.kepzetes); return eredmeny; } Hiba: megszűnt objektum referenciája! A C++ programozási nyelv 11. (Osztálytervezés)
Ne adjuk vissza lokális objektum címét 3. • Másik helytelen implementáció: Komplex& operator+(const Komplex& masik) { Komplex* eredmeny = new Komplex (valos + masik.valos, kepzetes+masik.kepzetes); return *eredmeny } Hiba: ki szabadítja fel a lefoglalt helyet? A C++ programozási nyelv 11. (Osztálytervezés)
Korlátozott láthatóságú adattag 1. • Egy tagfüggvény ne adja vissza olyan adattag referenciáját vagy pointerét, amelynek a láthatósága kisebb, mint a függvényé. Példa: class String { private: char* elemek; public: operator char*() {return elemek;} //Hiba! }; A C++ programozási nyelv 11. (Osztálytervezés)