PB161 - Týden 2 - Principy OOP, zapouzdření, dědičnost
-
Upload
happycerberus -
Category
Documents
-
view
742 -
download
0
Transcript of PB161 - Týden 2 - Principy OOP, zapouzdření, dědičnost
PB161PB161 – Zapouzdření, dědičnost, 27.9.2010 1
/51
Principy OOP, zapouzdření, dědičnost
PB161PB161 – Zapouzdření, dědičnost, 27.9.2010 2
/51
Co nás dnes čeká…
Více o objektovém návrhuKonstruktor, referencePrincip a implementace zapouzdřeníDědičnost
PB161PB161 – Zapouzdření, dědičnost, 27.9.2010 3
/51
Připomenutí
Třída je podklad pro tvorbu objektůObjekt je paměťová instance třídyTřída obsahuje datové atributy a metody pro práci
s nimi
Objekt mouse1
Třída CMouseAtribut m_size
Metoda feed
PB161PB161 – Zapouzdření, dědičnost, 27.9.2010 4
/51
Připomenutí (2)
Objekt má svůj stav (v datových atributech)● s atributy lze typicky pracovat jen přes metody
(zapouzdření)
Lze volat metody objektu● manipulují s atributy objektu
● const metody lze volat i nad konstantním objektem
PB161PB161 – Zapouzdření, dědičnost, 27.9.2010 5
/51
Deklarace vs. definice
Deklarace zavádí nové jméno entity do programu● typicky v hlavičkovém souboru (*.h)
Definice poskytuje unikátní popis (implementaci) entity ● funkce, typ, třída, instance...● typicky ve zdrojovém souboru (*.cpp)
Jen jedna definice (implementace), možno více deklaracíDeklarace může být zároveň definice
● např. deklarace metody přímo doplněná jejím tělem
PB161PB161 – Zapouzdření, dědičnost, 27.9.2010 6
/51
Ukázka třídy rozdělené do H a CPP
cmouse.h cmouse.cpp
deklarace
deklarace
deklarace i definice
definice
definice
import deklarací
PB161PB161 – Zapouzdření, dědičnost, 27.9.2010 7
/51
Výpis na standardní výstup
Z C znáte printf(“Dnes je %d. zari”, den);V C++ na výstup zapíšete takto:
Práci se standardním výstupem budeme dělat detailněji v 4. přednášce
Standardní výstup je objekt cout
Operátor << davá na cout řetězcovou reprezentaci argumentu těsně za nímAnalogie
<stdio.h>
PB161PB161 – Zapouzdření, dědičnost, 27.9.2010 8
/51
Konstruktor - motivace
Motivace: Naše třída má několik atributů● Jaká bude jejich hodnota při vytvoření objektu?● většinou neinicializovaná => nepříjemné
Možným řešením je speciální metoda „clean()“● ale „zbytečné“ volání hned po vytvoření objektu
C++ nabízí elegantní řešení - konstruktor
PB161PB161 – Zapouzdření, dědičnost, 27.9.2010 9
/51
Konstruktor
Metoda, která je automaticky volána při vytváření objektuZajistí, že objekt bude od začátku v konzistentním stavu
● můžeme inicializovat atributy na defaultní hodnotu● můžeme je nastavit na speciální hodnoty● můžeme otevřít spojení na server…
Konstruktor může mít argumenty a může být přetížen● inicializace uživatelem zadanými hodnotami● více konstruktorů s různými argumenty (přetížení)
PB161PB161 – Zapouzdření, dědičnost, 27.9.2010
10/51
Konstruktory - syntaxe
jméno metody jako třída
Implementace konstruktorů
Deklarace konstruktorůs 0, 1 a 2 parametry
bez návratové hodnoty
PB161PB161 – Zapouzdření, dědičnost, 27.9.2010
11/51
Defaultní konstruktor
Co když není definován žádný konstruktor?● automaticky existuje defaultní konstruktor● nemá žádné argumenty● CClass object;
Definováním uživatelského konstruktoru se odstraní defaultní konstruktor bez argumentů● pokud chceme konstruktor bez parametrů, musíme ho
definovat
PB161PB161 – Zapouzdření, dědičnost, 27.9.2010
12/51
Kostruktory - ukázka
constructorDemo.cpppoužití konstruktoruneinicializovaná proměnnádefaultní konstruktorkonstruktor s argumentypřetížení konstruktoru
PB161PB161 – Zapouzdření, dědičnost, 27.9.2010
13/51
Reference na proměnnou
Alternativní jméno pro objekt/proměnou (~alias)● často použito pro předávání referencí● není ukazatel na objekt, ale má podobné použití● změna proměnné obsahující referenci na objekt změní tento
objekt
Typově bezpečnější analogie k ukazateli na objekt● jde o referenci s konkrétním typem, ne např. void*● v C lze samozřejmě také ukazatel s konkrétním typem● nelze ale ukazatel na strukturu houseMouse nebo fieldMouse
PB161PB161 – Zapouzdření, dědičnost, 27.9.2010
14/51
Předávání argumentů referencí
Alternativa k předávání argumentů funkce ukazatelem● volání odkazem: void foo(int* pX) { *pX = 10; } ● volání referencí: void foo(int& x) { x = 10; }
Zavolání funkce vypadá jako volání hodnotou● při předávání referencí není vytvářena kopie objektu
● změna argumentu uvnitř funkce se ale projeví i mimo funkci
PB161PB161 – Zapouzdření, dědičnost, 27.9.2010
15/51
Konstantní reference
Konstantní reference (const typ&)● umožňuje specifikovat záměr programátoru o
nakládání s objektem (referencí, ale nebude měněn)
Kontrolováno během překladu● konstatní reference na nekonstantní objekt - chyba
● změna nekonstantního objektu přes konstantní referenci - chyba
PB161PB161 – Zapouzdření, dědičnost, 27.9.2010
16/51
Reference - ukázka
referenceDemo.cppvíce referencí na jedinou proměnnounutnost inicializace referencepředání argumentu referencízměna hodnoty mimo funkcikonstantní reference
PB161PB161 – Zapouzdření, dědičnost, 27.9.2010
17/51
ZapouzdřeníDědičnostAbstrakcePolymorfismus
PB161PB161 – Zapouzdření, dědičnost, 27.9.2010
18/51
Zapouzdření
Zapouzdření je styl programování● snaží se minimalizovat viditelnost proměnných/funkcí● aby nedocházelo k nezáměrným/nevhodným změnám● uživatel používá jen podmnožinu vybraných funkcí
Kombinace několika vlastností ● abstrakce dat/metod (abstraction)
● skrytí dat/metod (hidding)● zapouzdření dat (data encapsulation)
PB161PB161 – Zapouzdření, dědičnost, 27.9.2010
19/51
Abstrakce dat/metod (abstraction)
Datová abstrakce● data mohou být použita, aniž by uživatel znal způsob
jejich reprezentace v paměti
● např. databáze jako soubor na disku nebo vzdáleném serveru
Funkční abstrakce● metoda může být použita, aniž by uživatel znal způsob
její implementace
● např. metoda pro vykreslení objektu
PB161PB161 – Zapouzdření, dědičnost, 27.9.2010
20/51
Skrytí dat/metod (hidding)
Pro okolí jsou vnitřní data třídy skryta ● atribut třídy může být pro okolí nepřístupný
Nemusejí být ani metody pro přímé získání a nastavení hodnoty atributu● atribut se může projevovat jen vlivem na chování
ostatních funkcí
Pro okolí jsou interní metody skryty● nejsou součástí veřejného rozhraní třídy
PB161PB161 – Zapouzdření, dědičnost, 27.9.2010
21/51
Zapouzdření dat (encapsulation)
S daty lze pracovat jen prostřednictvím obalujících funkcí● nelze přímo číst/nastavit hodnotu datového atributu● např. dostupná pouze CMouse::feed(), ne CMouse::setSize()
Obalující metody mohou kontrolovat● validitu argumentů, konzistentnost vnitřního stavu před změnou…● metoda může nadstavovat více vnitřních atributů zároveň
Uživatel třídy není omezován detaily vnitřní logiky
PB161PB161 – Zapouzdření, dědičnost, 27.9.2010
22/51
Výhody zapouzdření
Implicitní tlak na dělitelnost a nezávislost kóduImplementace třídy se může vyvíjet bez nutnosti
změny okolního kódu ● rozhraní zůstává neměnné
Vnitřnosti třídy jsou lépe chráněny vůči chybám ● programátor je omezen a kontrolován překladačem
Příprava pro další OOP vlastnosti
PB161PB161 – Zapouzdření, dědičnost, 27.9.2010
23/51
Zapouzdření v C++
C++ poskytuje nástroje pro zapouzdření dat ● ale umožňuje i porušit (tj. přímý přístup)
Realizováno prostřednictvím přístupových práv● k atributům
● k metodám
Základní přístupová práva● public – všichnu mohou číst/modifikovat/používat● private – nikdo kromě vlastní třídy nemůže
číst/používat
● protected, friend – specializovanější (později)
PB161PB161 – Zapouzdření, dědičnost, 27.9.2010
24/51
Syntaxe přístupových práv
Struktura
Třída
změna z public na private
změna z private na public
PB161PB161 – Zapouzdření, dědičnost, 27.9.2010
25/51
Přístupová práva
Právo platí, dokud není nastaveno jinéstruct v C++ má všechny položky defaultně public
● z důvodu zpětné kompatibility s C● lze přenastavit na private
class v C++ má všechny položky defaultně private● ponechte pro atributy private● je nutné explicitně nastavit public pro veřejné metody
PB161PB161 – Zapouzdření, dědičnost, 27.9.2010
26/51
Přístupová práva - public
K položce s právem public má přístup kdokoli● atribut může být čten a měněn kýmkoli● metoda může být volána „zvenčí“
Jako public typicky neoznačujeme atributy● podporujeme zapouzdření
Jako public označujeme metody, které jsou součástí rozhraní● deklarace existujících public metod by se neměly měnit
● někdo je nejspíš používá● implementaci měnit můžeme (tělo je skryto)
PB161PB161 – Zapouzdření, dědičnost, 27.9.2010
27/51
Přístupová práva - private
K položce s právem private má přístup pouze sama třída● atribut nebo metoda nemůže být použit/volána „zvenčí“● výjimkou je objekt/metoda s právem friend (viz. později)● pokus o použití metody definované jako private vyvolá chybu už
během překladu
Jako private označujeme typicky všechny atributy● podporujeme zapouzdření
Jako private označujeme metody, které nejsou součástí rozhraní● nechceme, aby na nich někdo závisel
PB161PB161 – Zapouzdření, dědičnost, 27.9.2010
28/51
Přístupová práva - ukázka
accessRightsDemo.cppdeklarace veřejných a privátních atributůrozdíly class vs. structchyby překladače
● přístup k privátnímu atributu● přístup k privátní metodě
PB161PB161 – Zapouzdření, dědičnost, 27.9.2010
29/51
ZapouzdřeníDědičnostAbstrakce Polymorfismus
PB161PB161 – Zapouzdření, dědičnost, 27.9.2010
30/51
Dědičnost v OOP
Duplicita v kódu je nepříjemná● snižuje přehlednost● zvyšuje náročnost úprav (nutno na více místech)● zvyšuje riziko chyby (někde zapomeneme upravit)
Dědičnost je nástroj pro omezení duplicity v kóduZlepšuje možnost znovuvyužití existujícího kódu
PB161PB161 – Zapouzdření, dědičnost, 27.9.2010
31/51
“Dědičnost” v C
V C se duplicita kódu odstraňuje: ● vytvořením nové funkce● a vložením funkčního volání na původní místa
Znovuvyužití kódu se dosahuje ● dobrým návrhem funkčního rozhraní
● umístěním do samostatných hlavičkových souborů
PB161PB161 – Zapouzdření, dědičnost, 27.9.2010
32/51
Dědičnost v C++
V C++ existuje systematičtější podpora● lze odstranit duplicitu i pro proměnné● navíc podporuje silnou typovou kontrolu
Mechanismus umožňující vytvořit další třídu (potomek) s využitím předlohové třídy (předek)● potomek zdědí možnosti předka (atributy a metody)
● může je rozšiřovat a předefinovat (překrývat)
PB161PB161 – Zapouzdření, dědičnost, 27.9.2010
33/51
Dědičnost - postup
1. Máme dvě (nebo víc) tříd se společným chováním
2. Identifikujeme společnou logiku (metody)
3. Identifikujeme společná data (atributy)
4. Vytvoříme novou třídu (předka)● obsahující společné atributy a logiku
1. Odstraníme přesunuté atributy&metody z původních tříd
2. Původní třídy nastavíme jako potomky nového předka
PB161PB161 – Zapouzdření, dědičnost, 27.9.2010
34/51
Dědičnost - příklad
V laboratoři máme domácí a polní myš. Rozdíl mezi druhy je jen v počáteční velikosti a rychlosti přibírání po požití potravy.
Nové třídy CHouseMouse a CFieldMouseSpolečné vlastnosti přesunuty do CMouseBaseCHouseMouse a CFieldMouse potomci
CMouseBase
PB161PB161 – Zapouzdření, dědičnost, 27.9.2010
35/51
Dědičnost - syntaxe
Předek
Potomek
Hlavičkový soubor předka
Modifikátor definující způsob dědění metod
a atributů
PB161PB161 – Zapouzdření, dědičnost, 27.9.2010
36/51
Přístupová práva - protected
K položce s právem protected má přístup pouze potomek● atribut může být čten a měněn potomkem ● metoda nemůže být volána „zvenčí“
Jako protected typicky označujeme metody● které nemají být dostupné všem, ale potomkům ano● často jde o virtuální přetěžované metody (později)● méně často atributy – raději protected „setter“ metodu
PB161PB161 – Zapouzdření, dědičnost, 27.9.2010
37/51
Typová hierarchie
Dědičnost vytváří hierarchii objektů● od nejobecnějšího k nejspecifičtějším
Na místo předka může být umístěn potomek ● proměnná s typem předka může obsahovat potomka
● potomek může být argumentem funkce s typem předka
● zároveň zachována typová bezpečnost
Při dědění lze omezit viditelnost položek předka● specifikace práv při dědění
PB161PB161 – Zapouzdření, dědičnost, 27.9.2010
38/51
Specifikátory přístupových práv dědění
public (class B : public A {}; )● zděděné položky dědí přístupová práva od předka● práva zůstanou jako předtím
private (class B : private A {}; )● zděděné položky budou private, odvozená třída však
bude mít přístup ke položkám, pokud byly v předkovi public nebo protected
● nebude přístup k položkám private u předka
● v potomcích potomka už nebude přístup
PB161PB161 – Zapouzdření, dědičnost, 27.9.2010
39/51
Specifikátory dědění přístupových práv (2)
protected (class B : protected A {}; )● položky private a protected zůstanou stejné, z public se
stane protected
pokud neuvedeme (class B : A {}; )● class jako private, u struct a union jako public
virtual (class B : virtual A {}; )● lze kombinovat s jedním z předchozích, přikazuje
pozdní vazbu – (viz později)
PB161PB161 – Zapouzdření, dědičnost, 27.9.2010
40/51
Práva při dědění - ukázka
inheritanceRightsDemo.cpppřístup k private metoděpřístup při dědění public/private/protectedzměna práv pro přístup při opakovaném děděnízpůsob znepřístupnění původně public metody
PB161PB161 – Zapouzdření, dědičnost, 27.9.2010
41/51
Jak „dědit“ z více existujících tříd?
Nová třída má mít vlastnosti více objektů● v Jave se řeší pomocí interfaces
V C++ lze řešit ● pomocí násobné dědičnosti (třída má více předků)
● pomocí kompozice objektu (třída má více podčástí)
PB161PB161 – Zapouzdření, dědičnost, 27.9.2010
42/51
Syntaxe násobné dědičnosti
Syntakticky správně, je ale vhodné?
Předek 1
Předek 2
Dědíme z obou předků
PB161PB161 – Zapouzdření, dědičnost, 27.9.2010
43/51
Dědičnost vs. kompozice
Dědičnost je „Is-A“ vztah● potomek má všechny vnější vlastnosti předka A● potomka můžeme přetypovat na předka
Kompozice je „Has-A“ vztah● třída může mít jako atribut další třídu A
● hodnotou, referencí, ukazatelem
● třída obsahuje vlastnosti A a další● třída může mít víc tříd jako své atributy
PB161PB161 – Zapouzdření, dědičnost, 27.9.2010
44/51
Dědičnost vs. kompozice - ukázka
inheritanceCompositionDemo.cppnásobná dědičnostkompozicevyužití inicializační sekce konstruktorupřetypování na předka
PB161PB161 – Zapouzdření, dědičnost, 27.9.2010
45/51
Dědičnost – vhodnost použití
Dle použití lze volit mezi dědičností a kompozicíObecně preference kompozice před dědičností
● násobná dědičnost může být nepřirozená● kompozice může být kódově rozsáhlejší
Možná i kombinace● objekt obsahuje kompozicí třídy jako atributy● jednotlivé atributy mohou mít hierarchii dědičnosti
PB161PB161 – Zapouzdření, dědičnost, 27.9.2010
46/51
Shrnutí
Konstruktor je metoda pro inicializaci objektuReference je zástupné jméno (alias) na objekt
● při předávání referencí můžeme objekt trvale měnit
Zapouzdření skrývá vnitřní data a logiku● umožňuje abstrahovat uživatele od aktuální
implementace
Dědičnost umožňuje využít kód předka v potomkovi● potomek může vystupovat jako datový typ předka
Násobná dědičnost vs. kompozice
PB161PB161 – Zapouzdření, dědičnost, 27.9.2010
47/51