Návrh třídy
může probíhat například takto
Promyslete si, co by měla třída fakticky dělat a co po ní ve finále budete chtít.
Například projekt: navrhněte třídu pro manipulaci s lineárním seznamem (seznam obsahuje položky hodnota a index). Umožněte vkládání a odstraňování jednotlivých prvků, nebo celých seznamů, třídění podle velikosti (hodnoty nebo indexu), přiřazování seznamů, srovnání položek … Ve druhé fázi umožněte, aby prvky v seznamu mohly být libovolné – například obsahovat hodnoty různých typů. Pro inspiraci. Můžete použít například jako balíček karet a implementovat míchání, rozdávání, jednoduchou hru (válku, oko, prší ...). Postup pro 2D pole je zde.
Nebo projekt pro realizace grafického elementu, který umožní vykreslení objektů na obrazovce, vytváření těchto objektů, rušení objektů, přiřazování objektů... Začněte jedním grafický elementem: bodem nebo úsečkou, v konečné fázi zkuste kombinovat (společně smíchat) různé typy grafických objektů – pro jejich držení můžete použít například 1D pole nebo seznam. Můžete použít jako příklad nějaký pohyb bodů po obrazovce (variace na screen saver …) například podle stisknuté klávesy, náhodných čísel ...
Nebo si vytvořte váš vlastní projekt.
Promyslete si kategorie – vznik, zánik, nastavení a zjištění hodnot, manipulace (činnost), operátory, konverze, vstup a výstup, dynamické proměnné, dědění
U dědění je důležité rozhodnout zda prvek je rozšířením původního, nebo ho obsahuje. Například u grafického elementu je lépe volit, že úsečka obsahuje bod, než že z něj dědí. Jako základ dědění je vhodné uvádět společnou funkčnost a navrhnout tak zvané rozhraní. Metody rozhraní volíme jako virtuální, což nám následně umožní pracovat se zděděnými objekty přes jejich společnou část rozhraní (definovanou přes bázovou třídu). I když zde pracujeme s bázovou třídou, díky mechanizmu virtuálních metod máme k dispozici metody třídy zděděné, které samozřejmě ví o jaký prvek se jedná a dokáží zavolat mu příslušnou metodu.Prvky různých typů zděděných od báze se například mohou vložit do pole ukazatelů na bázový typ a potom se prochází jednotně přes metody rozhraní bez znalosti konkrétního typu (ten si zjišťuje program za chodu z tabulky virtuálních metod – metoda je volána přes adresu, kterou si objekt nese v sobě). Můžeme tak například stejným postupem vykreslit kružnici, čtverec … i když je jasné, že kreslící metoda i datová reprezentace je odlišná.
Například pro grafický element by mohlo rozhraní obsahovat tyto metody: Vykresli – pro vykreslení všech prvků, Rotuj – pro zrotování pozic všech objektů vůči zadanému středu otáčení, Posuň – pro posunutí všech prvků, VratVzdalenost – pro zjištění minimální vzdálenosti objektu od zadané pozice …
Například pro lineární seznam by se vytvořil společný prvek který by byl prvkem seznamu a měl základní metody. Pokud by z tohoto základního prvku dědila i třída pro práci se seznamem, choval by se seznam i jako prvek.
Promyslete si datovou reprezentaci a její návaznost na bod 2)
V případě dědění provádějte následující body od bázové třídy.
Vytvořte hlavičkové a zdrojové moduly tříd. Vytvořte modul
pro testování tříd (funkce main (či jiná), ve které vyzkoušíme
funkčnost napsaných metod). Hlavičkový soubor standardně ošetřete a
načtěte ho do zdrojových souborů. Zvažte použití vlastního jmenného
prostoru a nadefinujte třídu
class
CTrida { } .
Vytvořte datové členy třídy (měly by se vyskytovat v private sekci). Promyslete jak budete oznamovat (chybový) stav objektu.
Při psaní metod postupujte postupně po krocích tak, že
napíšete prázdné tělíčko, vyzkoušíte zda je v pořádku voláno a zda
má správně návratovou hodnotu.
Pro předávání parametrů
používejte přednostně referenci. Pro předávání používejte konstantní
parametry pro parametry funkce, které se v ní nemění.
Metody
neměnící instanci třídy označte jako konstantní.
Následně
doplňte zdrojový kód metody. Na základě složitosti metody rozhodněte
zda bude inline, nebo zda bude ve zdrojové části. U opravdu
jednoduchých inline metod napište tělo metody přímo do definice
třídy. U inline metod, které jsou delší než jeden řádek dopište
inline u deklarace a vlastní tělo metody napište za popis třídy do
hlavičkového souboru. Metody s funkčním voláním napište do
zdrojového souboru. Pokud je metoda mimo třídu, musí název metody
obsahovat upřesnění, ke které třídě patří. To se zajistí pomocí
operátoru příslušnosti (Třída::Metoda( ) ).
Pomocí trasování
sledujte proces volání a kudy program „chodí“.
Vytvořte statické datové členy a metody
U konstruktorů a
destruktorů je možné jako kontrolní mechanizmus implementovat
počítání vzniklých (konstruktor inkrementuje) a zaniklých
(destruktor dekrementuje) objektů pomocí statických objektů. Dále je
možné počítat celkový počet vzniklých objektů. Pokud je po skončení
programu počet aktivních proměnných různý od nuly je někde chyba.
Pro tisk statických proměnných se používají statické metody, které
lze použít i pro případ, kdy není vytvořená žádná instance.
Vytvořte statické proměnné pro uložení počtu aktivních a
vytvořených prvků (v definici třídy je deklarace proměnných,
definice je v cpp souboru). Ke zjištění počtu aktivních a celkových
prvků vytvořte statické metody. Vlastní funkce pro tisk bude volat
tyto metody.
{ int i=
CTrida::PocetVytvorene(); // pomocná proměnná - žádný objekt
třídy
TiskVytvorenych(); TiskAktivnich();
{
CTrida p1;
//implicitni
TiskVytvorenych(); TiskAktivnich();
}//tady se
volaji destruktory
i = 5; // zde už by neměl „žít“
žádný objekt třídy
TiskVytvorenych(); TiskAktivnich();
}
Vytvořte konstruktory a
destruktory
Jelikož konstruktory (pro nastavení/inicializaci) a
destruktory (pro „uklizení“) používají části kódu, které
jsou využitelné i v jiných metodách (například přiřazení, změny
rozměrů, nastavení do základního tvaru...) je výhodné pro tyto
vytvořit samostatné metody z konstruktorů volané. V případě
„nebezpečných“ metod (ke kterým by neměl mít uživatel
přístup, jako je alokace a odalokace paměti ...) je nutné tyto uvést
v private sekci.
Pro testování například tato část kódu
{
int i= CTridat::PocetAktivni(); // pomocná proměnná - žádný objekt
třídy
TiskVytvorenych(); TiskAktivnich();
{
CTrida p1;
//implicitni
CTrida p2 = 3, p6 = 3.1; // konverzní z int,
double
CTrida p3 = p2, p4(p3); // kopy
CTrida p5 ("3,
2,0");
// konverzní z char*
CTrida p7 (3,2,0), p8(3,2); // (použit jeden
společný) konstruktor se třemi (a také dvěma) parametry (pro třetí
parametr použita implicitní hodnota)
CTrida p8[4]; // pole prvků
třídy
CTrida *pp = (CTrida*) new CTrida(2,4,1); // dynamické
vytvoření pomocí konstruktory se třemi parametry
--- tady něco
chybí ---
TiskVytvorenych(); TiskAktivnich();
}//tady se
volaji destruktory
i = 5; // zde už by neměl „žít“
žádný objekt třídy
TiskVytvorenych(); TiskAktivnich();
}
Vytvořte metody pro zadávání a čtení dat (Gettery a Settery)
Pro testování například tato část kódu
p1.SetX(4);
// při nastavení se může například změnit rozměr, k čemuž použijeme
privátní metody (alokace, odalokace, které jsme použili pro
konstruktory)
p2.SetY(5);
p3.SetXY(3,4); // rozměry x,y; u
seznamu počet a hodnota ...
ix = p4.GetX();
iy =
p5.GetY();
Ověřte, že nefunguje přístup ke členským datům
třídy: aa = p1.proměnná;
musí dát chybu
Vytvořte metody pro výpočty (manipulaci)
Například pro vázaný seznam: vložení prvku, seřazení
podle daného kriteria, načtení prvku, zařazení prvku, vložení
seznamu, tisk, rušení prvku, zjištění počtu prvků, volného indexu,
maximálního indexu … ,
Například pro grafiku –
zadání souřadnic, zjištění minimální a maximální hodnoty souřadnice,
rotace, translace, určení zda je na obrazovce (ve vybraném regionu),
vyhledání nejbližšího elementu k určenému bodu, vykreslení …)
Pro testování například tato část kodu
p1.Vypocti();
p2.Srovnej(p1); // metody s jedním parametrem (+ volající objekt
(this))
p5.Pridej(p1,p2,65); p2.Uprav(); // metoda se třemi
parametry a bez parametrů (+ volající objekt (this))
p3.Invertuj();
// naimplementujte tak, že metoda invertuje p3, p3 je po operaci
změněná
p4.Srovnej(Invertuj(p3)) ;// funkce invertuje p3 a je
implementována tak, že se p3 nezmění, následně se výsledek inverze
p3 srovná s p4 (podle vhodného kriteria)
Například pro lineární seznam: připojení seznamu
pomocí + (a+b), vytvoření seznamu s „otočením“
znamének hodnot v seznamu pomocí - (-a s
tím, že respektuje stejná pravidla jako základní typy (int, float) a
tedy a je i po
operaci stejné jako před ní), ukázat rozdíl oproti + (+a),
přiřazení = (a=b), test na shodu seznamu == (a==b),
zjištění zda obsahuje hodnotu (a== 34) …
Nebo u
grafiky: přiřazení = (a=b), pro „zrcadlení“ prvku
- (-a), ukažte rozdíl s + (+a), výpočet „průměru“
dvou bodů a = (b+c)/2; násobení konstantou pro
zvětšení/zmenšení a = b *2; a *= 2; přičtení konstanty pro
posuv, zjištění zda dva body jsou totožné a==b …
Pro testování například tato část kodu
p1
= p2 = -p3 + p4 * p5; // přiřazení (zřetězené/vícenásobné), unární
mínus, plus a krát (objekt * objekt)
if (p1 <= p2) p1 -= +p5 *
8; // logický operátor <= pro srovnání, unární plus, operátory
„-=“ a krát (objekt*int)
else p1 -= 3*p4; // operátor
„-=“, nečlenský operátor (realizován funkcí)
int*objekt
float f = p1 != p3; // logický operátor je různé „!=“
(vrací typ bool)
int i = (int)p5; // konverzní operátor (objekt
se převede na int)
Vytvořte funkce/metody pro vstup a výstup
Tyto metody by měly být doplňkové. To znamená, že alespoň jeden z typů vstupu by měl být schopen načíst data pořízená výstupem.
Pro testování například tato část kodu
{cout
<< "
ted si vypisu hodnoty me tridy "
<< p1 << "
a pro srovnani "
<< p2 << "\n
zadejte hodnoty noveho prvku";
cin
>> p5;
ifstream is("nacti.dat",ios::in);
is >> p4; }
Konec programování = začátek testování - vytipujeme si různé kombinace vstupních parametrů a vyzkoušíme, zda se jednotlivé metody chovají podle předpokladů (nejlépe provádět přímo po implementaci každé nové metody).
Poslední úpravy 2010-11-17