CATEGORII DOCUMENTE |
Bulgara | Ceha slovaca | Croata | Engleza | Estona | Finlandeza | Franceza |
Germana | Italiana | Letona | Lituaniana | Maghiara | Olandeza | Poloneza |
Sarba | Slovena | Spaniola | Suedeza | Turca | Ucraineana |
DOCUMENTE SIMILARE |
|
TERMENI importanti pentru acest document |
|
Zpracované otázky do předmětu DPT
Programovací techniky
Základy objektového programování
1. Objektový jazyk Pascal 4
2. Objekty a třídy 7
2.1 Třída jako zobecněný typ record 8
2.2 Vlastnosti (pole) a metody 8
3. Inicializace polí 9
4. Klíčové slovo self 12
5. Přetěžované metody 13
6. Dědičnost 14
6.1 Kompatibilita typů 15
7. Zapouzdření a chráněný přístup 16
7.2 Konstrukce property (vlastnost) 18
7.2 Indexovaná konstrukce property (vlastnost) 19
8. Zapouzdření a jednotky 20
9. Polymorfismus 21
9.1 Statická (brzká) vazba 22
9.2 Dynamická (pozdní) vazba 23
9.3 Virtuální metody 24
9.4 Dva způsoby použití virtuálních metod 25
10. Výjimky a chráněné bloky 26
Milé děti,
zde máte vypracované otázky do Delphi. Jelikož nejsem programátor, negarantuju jejich správnost. Většinu textů jsem našel na netu a posléze otestoval skutečným zdrojákem.
U zkoušky: Posedáte si kažý do jedné lavice. Přijde a napíše na tabuli 4 otázky, které zpracujete na papír. Čas není omezen, ale za 40 minut už stejně nemáte co dělat. Poté si papíry vybere a za cca hodinu si k němu chodíte popovídat. U ústní zkoušky probírá obsah písemky a ptá se na to, co mu není jasné. Je to tak na 10-15 minut.
Tip: Naučte se pořádně ty otázky a hlavně mu tam napište příklady zdrojáku k danému tématu.. Po lidech, kteří mu tam žádný příklad nenapsali chtěl napsat něco u sebe – věřte, že za lavicí se líp přemýšlí a vzpomíná.
Přeji hodně štěstí u zkoušky, dostal jsem za 1 J
Honza Matuška alias Walda
1. Objektový jazyk Pascal
Co to je vlastně objektově orientované programování? Často vypadá spíše jako náboženství než jako přístup k programování. Tento programovací styl používá oddělené objekty, které obsahují (zapouzdřují) svá data i kód. Tyto objekty jsou stavebními prvky aplikace. Obvyklým důvodem používání objektů je možnost jednodušších zásahů do programu. Fakt, že data i kód jsou jaksi pohromadě (a že si tedy každý objekt plně za svá data zodpovídá), znamená, že proces odstraňování chyb (a také modifikace vlastností objektu) má minimální efekt na okolní objekty. Jazyk objektově orientovaného programování obvykle zahrnuje implementaci alespoň tří principů:
zapouzdření – kombinace vzájemně svázaných datových položek a metod, které nad nimi pracují;
dědičnost – možnost vytvářet objekty vycházející z jiných objektů. Tento princip dovoluje vytvářet hierarchii – nejprve se vytvoří obecný objekt a postupným zpřesňováním vznikají specifičtější následníci;
polymorfismus – volání metod proměnné typu třída způsobí volání kódu patřícího k instanci objektu (viz níže), kterou proměnná právě obsahuje.
Pokud bychom se měli pokusit stanovit základní dva termíny objektově orientovaného programování, šlo by zřejmě o třídu a objekt. Třída je datový typ, který si můžete představit jako jakousi šablonu určitých objektů (třeba aut), která popisuje chování konkrétních objektů (aut). Konkrétní auta vytváříme podle této „šablony“. Třída obsahuje nějaká svá (interní) data (tzv. atributy) a své metody (tj. procedury a funkce). Třída by měla charakterizovat chování a vlastnosti několika podobných objektů (např. aut více značek). Objekt je instancí třídy, jakýmsi konkrétním výskytem (konkrétním, fyzicky existujícím exemplářem auta). Jinak řečeno, je to proměnná datového typu, který představuje třída. Objekty při běhu programu zabírají paměť pro svou reprezentaci. Vztah mezi objektem a třídou si lze představit třeba jako vztah mezi proměnnou a datovým typem.
Abychom si vše názorně předvedli (a také abychom si ukázali, jak to prakticky udělat v Object Pascalu - a tedy také v Delphi), vytvoříme třídu automobil, která bude mít následující atributy:
Značka – značka automobilu, typ = řetězec;
Rok výroby – typ = celé číslo;
Benzín – množství benzínu v nádrži, typ = celé číslo;
Kapacita – objem nádrže, typ = celé číslo.
Třída bude mít tyto metody:
Vypiš informace – vypíše všechny atributy;
Natankuj – naplní nádrž o dané množství litrů. Pokud se dané množství do nádrže nevejde, doplní nádrž na maximum a vrátí false (jako varování).
Abychom hovořili všichni o tomtéž, provedeme to tak: v Delphi vytvoříme novou aplikaci s jedním formulářem, na kterém bude jedno tlačítko.Veškerý níže uvedený kód budeme psát do modulu tohoto formuláře (standardně Unit1.pas).
type
TAuto
= class
znacka: String;
RokVyroby,
Benzin, Kapacita: Integer;
procedure
VypisInfo;
function
Natankuj(Kolik: Integer): Boolean;
end;
Podotýkám, že tento kód se bude vyskytovat v sekci interface příslušného modulu (souboru). Abychom s touto třídou mohli pracovat, je ještě nutné říci, jak budou vypadat těla zmíněných metod. Tato těla budou zapsána v sekci implementation (rozdíl mezi oběma sekcemi vysvětlíme níže), a aby kompilátor věděl, ke které třídě budou těla patřit (lze totiž mít víc různých tříd a v každé např. metodu s názvem Natankuj), používá se v Object Pascalu tzv. tečková notace:
procedure
TAuto.VypisInfo;
begin
ShowMessage( Format(`%s,
%d: %d (%d).`,
[Znacka, RokVyroby, Benzin, Kapacita]) );
end;
function
TAuto.Natankuj(Kolik:
Integer): Boolean;
begin
Result := (Benzin +
Kolik) <= Kapacita;
Benzin := Max(Kapacita,
(Benzin + Kolik));
end;
Poznámky:
Proměnné Result se používá k navrácení hodnoty funkce; v Delphi se příliš nepoužívá klasického „pascalského“ zápisu „název_funkce := návratová_hodnota.“
Funkce Max (vrací maximum ze dvou argumentů, návratový typ závisí na typu argumentů) se nachází v jednotce Math, měli byste tedy tuto jednotku zapsat do sekce uses.
Nyní ještě provedeme deklaraci proměnné typu třída a ukážeme si, jak metody volat a jak s proměnnou pracovat. Následující kód bude umístěn v sekci implementation, v jakékoliv proceduře či funkci (např. v metodě ošetřující událost OnClick nějakého tlačítka umístěného na formulář).
procedure
TwndHlavni.btnStartClick(Sender: TObject);
var
MujBlesk:
TAuto;
begin
// (A)
MujBlesk.Znacka :=
`Skoda 1000MB`; // (B)
MujBlesk.RokVyroby :=
1950;
MujBlesk.Benzin := 0;
MujBlesk.Kapacita := 5;
MujBlesk.VypisInfo;
if not
MujBlesk.Natankuj(2) then
ShowMessage(`Nepřehánějte to s
tím benzínem!`);
MujBlesk.VypisInfo;
end;
Nyní si zkuste program zkompilovat a spustit. Vše bude v pořádku, ale jen do okamžiku, než kliknete na „startovací“ tlačítko. Pak se program zboří. (Tedy – nezboří se úplně, ale fungovat nebude a bude generována tzv. výjimka – viz dále).
Proč tomu tak je? Vysvětlení příčiny je složitější a souvisí se základní myšlenkou objektově orientovaného modelu. Musíme si říci několik informací o vytváření instancí. Následující řádky jsou klíčové pro pochopení OOP.
Základní myšlenka objektově orientovaného modelu spočívá v tom, že proměnná datového typu třída (nemluvíme o instanci objektu, jen o proměnné), jako je např. MujBlesk z předchozího příkladu, neobsahuje 'hodnotu' objektu. Neobsahuje ani objekt auto ani atributy auta. Obsahuje pouze odkaz (ukazatel) na místo v paměti, kde je vlastní objekt fyzicky uložen.Vytvoříme-li proměnnou tak, jak jsme to předvedli o pár řádků výše (pomocí klíčového slova var), nevytvoříme zmíněnou fyzickou reprezentaci objektu (místo pro uložení objektu v paměti), ale jen odkaz na objekt (místo pro uložení tohoto odkazu v paměti)! Vlastní instanci musíme vytvořit ručně zavoláním jeho metody Create, což je tzv. konstruktor (procedura určená k alokování paměti a k inicializaci objektu).
Řešení je tedy prosté: mezi řádky označené (A) a (B) v předchozí proceduře vsuneme volání konstruktoru:
begin
// (A)
MujBlesk :=
TAuto.Create;
MujBlesk.Znacka :=
`Skoda 1000MB`; // (B)
Kde se vzal konstruktor Create? Je to konstruktor třídy TObject, od něhož všechny ostatní třídy (a tedy i tato) dědí (viz dále).
Když jsme objekt vytvořili, je třeba jej nakonec také zrušit. To provedeme zavoláním metody Free:
MujBlesk.VypisInfo;
MujBlesk.Free;
end;
Objekt
Jak již asi každého napadne, základem OOP je objekt. Co je to objekt? - Objekt je entita, která má svou identitu (Každý objekt lze jednoznačně odlišit od objektu jiného.) a své vlastnosti (Každý objekt má nějaký vnitřní stav a nějak se chová vůči svému okolí). Každý asi i bez této definice podvědomě tuší, co to objekt je. Objekty jsou například: strom, auto, člověk, ale také datový soubor, okno v grafickém operačním systému, tlačítko v grafickém operačním systému, různé datové struktury jako je pole, fronta, zásobník atd Je zřejmé, že všechny tyto objekty splňují podmínky uvedené v definici. Každý objekt, který má být užitečný, musí poskytovat svému okolí nějaké služby. Například auto se umí rozjet, zastavit atd. Okno v grafickém OS se umí minimalizovat, zavřít, aktivovat, atd. Datový soubor se umí otevřít, zavřít, lze do něj zapsat, lze z něj číst. Uživatel objektu k jednotlivým objektům přistupuje jako k tak zvaným 'černým skříňkám'. Nezajímá se, jakým způsobem objekty služby poskytují, ale zajímá se jen jaké služby poskytují. Například každý ví, co způsobí sešlápnutí brzdového pedálu v autě, ale málokdo by byl schopen přesně popsat, co se v motoru v tom okamžiku přesně děje. Pro zabrždění auta to prostě nemusí vědět. Stejně tak mnoho programátorů (já taky) ve svých programech běžně otevírá i zavírá soubor, ale příliš netuší, co všechno program a operační systém při otevírání souborů provádí. Právě tento přístup 'černých skříněk' k objektům v OOP je dost podstatný. Programátor, který používá objekt, se nestará o to, jak byl naprogramován. Vytvořím-li objekt v OOP, vždy se jedná o jakýsi model objektu reálného světa.
Třída objektů
Opět definice: 'Třída objektů je abstrakce množiny podobných objektů'. Je zřejmé, že některé objekty mají mnoho společných vlastností - jsou stejné třídy. Například objekt, na který se dívám při psaní tohoto textu, má mnoho společných vlastností s objektem, který sledujete vy při čtení tohoto textu - oba jsou třídy monitor. Nebo máte-li nějaký grafický OS, máte patrně na monitoru několik otevřených oken. Každé okno je objekt. Každý objekt vypadá jinak - každé okno zobrazuje něco jiného, přesto jsou si nějak podobné. Všechny objekty jsou stejné třídy. Každý objekt je nějaké třídy. Je-li objekt nějaké třídy, nazývá se instancí této třídy. Každá třída může mít libovolný počet instancí. Dále ve svých článcích budu místo pojmu objekt používat spíše pojem instance. Budu tím myslet objekt třídy, která je zřejmá, nebo kterou uvedu.
Nejčastěji se objekt srovnává se záznamem (record). Samozřejmě záznam není to samé co objekt a nyní vám popíší rozdíly mezi nimi, protože podle nich velmi dobře (podle mého mínění) pochopíte podstatu objektu.
Nejprve uvedu příklad objektu a pak si probereme jednotlivé řádky kódu.
Type TLetadlo = class //zde by mohl
být uveden předek
procedure Let(rychlost:Integer);
palivo:Integer;
maPasazery:Boolean;
end;
Objekty se uvozují klíčovým slovem class (u zánamu record). Za class může následovat uvedení předka v závorce protože objekty mohou po předkovi dědit vlastnosti, atributy a metody, ale o tom až později. Na rozdíl od záznamu mohou mít objekty procedury a funkce, kterým souhrnně říkáme metody objektu. Naproti tomu proměnným, které může záznam obsahovat také, říkáme atributy.
Metody, které jsou uvedené v deklaraci objektu mají tzv. neúplnou deklaraci, protože deklarace metody se provádí ve dvou krocích. Nejdřív se uvede její identifikátor spolu s proměnnými v těle objektu a její definice se musí uvést zvlášť v sekci implementation
procedure TLetadlo.Let(rychlost:Integer);
begin
// implementace dané procedury
end;
Je tu ještě jeden rozdíl oproti záznamu. Záznamovou proměnnou stačí deklarovat za klíčovým slovem var a už s ní můžete pracovat. Takto to u objektů nefunguje. Instance (objektová proměnná) jen ukazuje na určitou oblast paměti. Vlastní objekt vytvoříme pomocí konstruktoru a pak zrušíme pomocí destruktorů.
Pole jsou v Delphi 2 druhy: statické a dynamické.
Statické
U těchto polí můsíme již při deklaraci vědět přesnou velikost a tato deklarace se provede následovně:
var pole:array[1..10] of integer; //klasicke 1D pole
louka:array[1..20, 1..100] of Tkyticky; //toto je 2D pole
Dynamické:
U těchto polí předem nevíme velikost a tato velikost se dá v programu dynamicky nastavit podle potřeby. Nezabírá tedy v paměti zbytečně místo.
var pole:array of integer;
x:integer;
begin
SetLength(pole, 10); //nastaví velikost pole na 10, protože vychozi hodnota je nula
for x:=0 to 10 do pole[x]:=0; //inicializuje pole regulrnimi hodnotami
… //další příkazy využívající pole
end
Pozor: Touto otázkou mohla být také myšlena inicializace pole hodnot objektu a ta se ve výchozím případě provádí defaultním konstruktorem create.
Příklad: třída.create
Dojde k vytvoření instance
objektu, k jeho naplnění výchozími hodnotami, resp. k naplnění pole jeho
hodnot. Rozšířené možnosti přináší použití konstruktoru.
3.1
Konstruktor a destruktor
Konstruktor
Metodu Create jsme volali kvůli přidělení paměti objektu (vytvoření instance). Často ale objekt potřebujeme také inicializovat, tzn. zadat mu nějaké základní provozní parametry. Za tím účelem přidáváme do třídy konstruktor. Lze použít upravenou verzi metody Create nebo definovat konstruktor úplně nový. Není však příliš vhodné pojmenovat konstruktor jinak než Create, i když je to samozřejmě možné. Třebas CreateMuj apod..
Konstruktor se deklaruje užitím klíčového slova constructor. Přidáme tedy do třídy TAuto konstruktor:
type
TAuto
= class
Znacka: String;
Benzin, Kapacita:
Integer;
constructor
Create(ZZnacka: String; BBarva, BBenzin, KKapacita: Integer);
procedure VypisInfo;
function
Natankuj(Kolik: integer): Boolean;
end;
Musíme také zapsat tělo konstruktoru. To se zapisuje kamkoliv do modulu, klidně mezi další procedury a funkce. Správně bychom měli v konstruktoru každé nově vytvořené (odděděné – viz dále) třídy nejdříve vyvolat konstruktor předka a následně uvést své vlastní, specializující příkazy. Pro třídu odděděnou od TObject to jistě není třeba, ale přesto je to vhodné a formálně správné.
constructor
TAuto.Create(ZZnacka: String; BBarva, BBenzin,
KKapacita: Integer);
begin
inherited
Create;
//zde
muze dojit k otevreni instanci i
dalsich objektu…
Znacka := ZZnacka;
Benzin := BBenzin;
Kapacita := KKapacita;
end
Takhle teď bude vypadat tělo procedury btnStartClick, ve které pracujeme s objektem MujBlesk třídy TAuto:
procedure
TwndHlavni.btnStartClick(Sender: TObject);
var
MujBlesk:
TAuto;
begin
MujBlesk :=
TAuto.Create(`Skoda 1000MB`, 0, 5);
MujBlesk.VypisInfo;
if not
MujBlesk.Natankuj(2) then
ShowMessage(`Nepřehánějte to s
tím benzínem!`);
MujBlesk.VypisInfo;
MujBlesk.Free; // nebo MujBlesk.Destroy, viz text
destructoru
end;
Destruktor
Destruktor je jednoduše řečeno opakem konstruktoru. V předchozím příkladu jsme se s ním již setkali (v řádce MujBlesk.Free). Implicitní název je tedy Free. Jeho funkcí je „zničit“ objekt (uvolnit jej z paměti). Platí, že dynamickou paměť, kterou jsme alokovali v konstruktoru, bychom měli v destruktoru uvolnit. Tedy pokud máme v rámci objektu otevřené nějaké soubory, je vhodné je v desktruktoru zavřít.
V tomto případě opět použiteme třídu TAuto.
type
TAuto
= class
Znacka: String;
Benzin, Kapacita:
Integer;
constructor
Create(ZZnacka: String; BBarva, BBenzin, KKapacita: Integer);
dectructor Destroy; override; //override je, ze se nebere Destroy
z predka TObject
procedure VypisInfo;
function
Natankuj(Kolik: integer): Boolean;
end;
destructor
TAuto.Destroy;
begin
//louci se trida TAuto…
//taky muzu smazat HDD, když me chce programator znicit
//zde se mohou ukoncit i další instance, pokud nejake byly v contructoru vytvoreny
inherited
Destroy;
end
Hodně často používané rutiny by neměly mít více než tři parametry, neb tři je přesně počet proměnných, které mohou být v jeden čas umístěny do registru. Tímto se rychlosti procesorových registrů využije na maximum a optimizer dostane větší šanci vylepšit váš kód. Metody tříd však mají skrytý parametr self, kterým odkazují na konkrétní instanci dané třídy, zbývají tedy tak už jen dva parametry k umístění do registrů.
V podstatě jde o jeden typ polymorfizmu.
V Delphi mohou dvě nebo více funkcí sdílet stejné jméno tak dlouho, pokud se liší typy jejich argumentů, nebo se liší počet jejich argumentů, nebo obojí. Když dvě nebo více funkcí sdílí stejné jméno označují se jako přetížené - overload.
Je velmi snadné přetížit funkci. Prostě deklarujeme a definujeme všechny požadované verze. Správnou verzi vybere překladač podle typu nebo počtu argumentů, použitých pro volání funkce.
Příkladem může být tento požadavek: Napište 3 procedury se stejným jménem a které identifikují typ svého argumentu:
Nejprve si procedury deklarujeme:
procedure pocitej(a:integer); overload;
procedure pocitej(a:string); overload;
procedure pocitej(a:real); overload;
Implementace bude následující:
procedure TXxxx.Pocitej(a:integer);
begin
label1.caption:=‘cele cislo‘;
end
procedure TXxxx.Pocitej(a:string);
begin
label1.caption:=‘retezec‘;
end
procedure TXxxx.Pocitej(a:real);
begin
label1.caption:=‘obecne cislo‘;
end
Po zavolání:
Pocitej(25) je vysledkem „cele cislo“
Pocitej(25,454); je vysledkem „obecne cislo“
Pocitej(‘AHOJ‘); je vysledkem „retezec“
Dědičnost je proces, při němž může jeden objekt získat vlastnosti jiného objektu. Přesněji řečeno objekt může zdědit obecnou sadu vlastností a do ní může přidat takové vlastnosti, které jsou specifické pouze pro něj. Dědičnost je důležitá, protože dovoluje objektu podporovat koncept hierarchické klasifikace.
Příklad: Popis domu. Dům je částí obecné třídy nazvané budova. Budova je zase částí obecnější třídy nazvané stavba, která je opět součástí obecné třídy objektů nazvané zhotovené člověkem.
Třída potomka dědí veškeré vlastnosti spojené s rodiči a přidává si k nim své vlastní charakteristiky. Bez využití uspořádané klasifikace, by měl každý objekt definovány všechny charakteristiky, které se k němu vztahují. Prostřednictvím dědičnosti je možné zadat třídu (či třídy) do níž daný objekt patří a přiřadit mu specifické vlastnosti, které mají všechny objekty dané třídy.
// rodic
type TIdealni = class
private
a,b,c:integer;
public
property in_a: extended write a;
function vypocitej_ideal(cas:extended):extended;
end
// potomek dedi vlastnosti rodice + dalsi prida parametry
type TRealne = class(TIdealni)
private
d,e:integer;
public
property in_d: extended write d;
property in_e: extended write e;
function vypocitej_real(cas:extended):extended;
end;
Bez použítí dědění vlastností TIdealni by třída Trealne vypadala takto:
type TRealne = class
private
a,b,c,d,e:integer;
public
property in_a: extended write a;
property in_d: extended write d;
property in_e: extended write e;
function vypocitej_ideal(cas:extended):extended;
function vypocitej_real(cas:extended):extended;
end;
Z předchozího textu je zřejmé, že potomek obsahuje všechno, co obsahuje rodič (a případně ještě něco navíc). Kdybychom tedy přiřazovali z potomky do rodiče, můžeme rodiče beze zbytku naplnit a ještě zbyde něco navíc, co nepoužijeme. Naproti tomu, kdybychom se pokusili obsah rodiče přiřadit do potomka, nebude jasné, čím některé části naplnit. Z toho plyne závěr, že přiřazení potomka do rodiče je možné, zatímco přiřazení z rodiče do dcery je chybou.
Tedy platí pro vzájemné přiřazování typů:
rodic := rodič OK
rodic : = potomek OK
potomek := potomek OK
potomek := rodič NEJDE
Zapouzdření je mechanismus, který svazuje dohromady kód a data a zabezpečuje je před vnějšími zásahy či zneužitím. V objektovém programování může být kód s daty slučován takovým způsobem, že vznikají tzv. nezávislé 'černé skříňky'. Spojením kódu s daty vzniká objekt. Jinými slovy lze říci, že objekt je instrument, který podporuje zapouzdření.
Příklad:
type TIdealni = class
private
// zapouzdrene promenne a funkce, tyto polozky jsou viditelne jen v ramci objektu
uhel,rychlost:extended;
function ahoj(cas:extended):extended;
public
// zapouzdrena funkce, která je viditelna i z vnějšku objektu
function gety(cas:extended):extended;
end;
Pozor: Není nutné psát definici třídy do
zvláštní unity, stačí do unity, kde píšeme vlastní program. O zapouzdřování do
jiné unity pojednává jiná kapitola.
7.1
Specifikátory přístupu (private, protected, public)
Tyto specifikátory slouží na to, aby bylo možné omezit viditelnost jednotlivých procedur nebo funkcí mimo objekt. Tzn, že můžeme omezit přístup z venčí k určitým procedurám nebo funkcním, které slouží pouze pro vykonání nějaké akce v rámci objektu a externí manipulací by se mohla daná akce, vykonávaná objektem, poškodit.
O tom, zda budou či nebudou viditelné, rozhodují specifikátory viditelnosti třídy. Tyto specifikátory mohou být:
public - všechna data a metody, uvedené v části public, jsou viditelné ze všech ostatních jednotek, tedy jsou viditelné a použitelné z částí programu mimo objekt.
private - žádná data ani metoda, uvedené v této části, nejsou zvnějšku objektu viditelné, tedy částí programu mimo objekt je nemůžeme použít.
protected - data a metody jsou viditelné, ale jen pro potomky dané třídy. Pro ostatní třídy jsou neviditelné. Tzn, že pouze potomek může používat metody a proměnné rodiče.
Příklad (nejběžnější použítí):
type TIdealni = class
private //privatni polozky viditelne pouze v ramci objektu
uhel,rychlost:extended;
function ahoj(cas:extended):extended;
procedure volej
public //verejne polozky viditelne z oblasti mimo objekt
abc:integer;
function gety(cas:extended):extended;
end;
Pomocí property je možné „namapovat“ proměnné používané uvnitř objektu do nějakého identifikátoru, který reprezentuje danou proměnnou vzhledem k vnějšímu světu okolo objektu. Jednomu identifikátoru lze přiřazovat různé proměnné zvášť pro čtení a zvlášť pro zápis.
Př:
//namapuje in_uhlel promenne setuhel pouze na zapis
property in_uhel:extended write setuhel
//namapuje in_uhlel promenne setuhel pouze na zapis i cteni
property in_uhel:extended read setuhel write setuhel
//namapuje in_jmeno promenne aktualnijmeno na cteni a promenne novejmeno na zapis
property in_jmeno:string read aktualnijmeno write novejmeno
Použití:
// toto je v objektu
property in_jmeno:string read aktualnijmeno write novejmeno
// toto je program mimo objekt
var hand:TmujObjekt
begin
hand:=TmujObjekt.Create;
hand.in_jmeno:=’Honza’;
Edit1.Text:=hand.in_jmeno;
end;
Tato ukázka uloží do proměnné novejmeno v objektu slovo Honza a do Edit1 pole na formu vypise obsah promenne z objektu aktualnijmeno.
Indexovaná konstrukce propetry umožňuje namapovat nějakou interní funkci umístěnou v objektu volanou s parametrem, indexem, nebo pomocí jednoduché funkce číst buňky privátního pole.
Příklad na použití indexované property na čtení privátního pole:
type TObjekt = classimplementation
function TObjekt.DejBunku(i:integer):string;Pokud bude obsah pole 1->AHOJ 2->HONZA 3->NEVER a napíšeme tento program
// toto je program mimo objekt
var hand:TObjekt;
begin
hand:=TObjekt.Create;
Edit1.Text:=hand.bunka[2];
end;
do Edit1 boxu se vypíše slovo HONZA
Základním celkem, ze kterých se skládá rozsáhlejší program v Delphi, je jednotka - UNIT. Každý formulář má svou UNITu, další UNITy se k programu připojují jako knihovny. Jenotka obsahuje dvě základní části: část INTERFACE obsahuje všechny prvky programu, které se zveřejňují, tzn. které jsou k dispozici ostatním částem programu. Naproti tomu část IMPLEMENTATION obsahuje implementační detaily, které jsou před zbytkem programu skryté, neviditelné. K částem ukrytým v IMPLEMENTATION nelze přistoupit jinak, než pomocí tříd, procedur a funkcí zveřejněných v části INTERFACE.
Struktura typické unity (jednotky):Polymorfismus je obecně vlastnost, diky níž může mít totéž jmnéno (proměnné, funkce, procedury,…) více rozdílných významů. V OOP to specielně znamená, že metody objektů, i když mají stejná jmnéna, se chovají různě podle toho, v jakém kontextu jsou zavolány. Později také uvidímě, že různé objekty mohou na tutéž zprávu reagovat různě. Polymorfismus se v Delphi projevuje ve dvou rovinách podle toho, podle čeho se vybere správná verze metody:
Vybírá se podle kontextu třídy – to jsou statické, dynamické a vitruální metody..
Vybírá se podle parametru – tzn přetěžování, je uvedeno v jiné otázce
Pozn: V případě, že chceme použít
v potomkovi stejnojmenou metodu uvedenou v rodičovské třídě, napíšeme
před tuto metodu slovo inherited.
type
TRodic = class
function GetWay:string; virtual;
end;
TPotomek = class(TRodic)
function GetWay:string; override;
end;
implementation
function TRodic.GetWay:string;
begin
result:='Rodic mluvi';
end;
function TPotomek.GetWay:string;
begin
result:=inherited GetWay + 'Potomek mluvi';
end;
// Do edit boxu se vypíše text Rodic mluviPotomek mluvi
procedure TForm1.Button1Click(Sender: TObject);
var test:TRodic;
begin
test:=TPotomek.Create;
Edit1.Text:=test.GetWay();
test.Free;
end
Jedná se o vazbu, kdy překladač již při překladu kódu ví, jaké metody budou kdy vyvolány. Tedy pricipielně se jedná o to, že při volání metody potomka, která má stejné jméno jako metodu rodiče, dochází k volání metody rodiče a nikoliv potomka.
Příklad:
Definujeme si následující třídy:
type TRodic = class
function GetWay:string;
end;
type TPotomek = class(TRodic)
function GetWay:string;
end;
implementation
function TRodic.GetWay:string;
begin
result:='Rodic mluvi';
end;
function TPotomek.GetWay:string;
begin
result:='Potomek mluvi';
end;
Do pole Edit1 se vypíše text „Rodic mluvi'“ a to i přesto, že je s proměnnou test typu TRodic svázaná instance objektu TPotomek. Prostě se nejdříve použije metoda rodiče, která je staticky svázaná s níže uvedenou instancí.
procedure TForm1.Button1Click(Sender: TObject);
var test:TRodic;
begin
test:=TPotomek.Create;
Edit1.Text:=test.GetWay;
test.Free;
end;
Metody dynamické se používají ke stejnému účelu jako virtuální. Jsou označovány v deklaraci třídy jako dynamic
procedure Test5; dynamic;
Rozdílem je, že dynamické procedury jsou pomalejší, ale zabírají méně prostoru. Používají se v případě, že základní třída má mnoho metod, které se sice mohou předefinovat, ale neděje se tak příliš často, a navíc má mnoho následníků.
Příklad:
Definujeme si následující třídy:
type TRodic = class
function GetWay:string; dynamic;
end;
type TPotomek = class(TRodic)
function GetWay:string; override;
end;
implementation
function TRodic.GetWay:string;
begin
result:='Rodic mluvi';
end;
function TPotomek.GetWay:string;
begin
result:='Potomek mluvi';
end;
Do pole Edit1 se vypíše text „Potomek mluvi'“ a to i přesto, že je proměnná test typu TRodic.
procedure TForm1.Button1Click(Sender: TObject);
var test:TRodic;
begin
test:=TPotomek.Create;
Edit1.Text:=test.GetWay;
test.Free;
end;
Metody virtuální jsou označovány v deklaraci třídy jako virtual
procedure Test5; virtual;
Na rozdíl od statických metod kompilátor negeneruje kód přímo pro volání konkrétní třídy, ale používá se mechanismu pozdního svázání. Metoda, která se bude volat, je určena až za běhu. Virtuální metoda může být v následnících předefinována (override). Při předefinování musí být deklarace přesně zachována (mění se pouze implementace).
procedure Test5; override;
Pokud tedy kompilátor narazí na konstrukci Třída.VirtuálníMetoda, je možné, že byla metoda předefinována. Vygenerovaný kód musí za běhu nalézt v tabulce virtuálních metod správnou metodu a zavolat ji.
Příklad:
Definujeme si následující třídy:
type TRodic = class
function GetWay:string; virtual;
end;
type TPotomek = class(TRodic)
function GetWay:string; override;
end;
implementation
function TRodic.GetWay:string;
begin
result:='Rodic mluvi';
end;
function TPotomek.GetWay:string;
begin
result:='Potomek mluvi';
end;
Do pole Edit1 se vypíše text „Potomek mluvi'“ a to i přesto, že je proměnná test typu TRodic.
procedure TForm1.Button1Click(Sender: TObject);
var test:TRodic;
begin
test:=TPotomek.Create;
Edit1.Text:=test.GetWay;
test.Free;
end;
Virtuální a dynamické metody jsou sématicky totožné. Jejich odlišnost je pouze v implementaci volání metod při běhu programu. Virtuílní metody jsou optimalizovány pro rychlost, dynamické pro velikost programu, šetří tedy místo a jsou pomalejší.
Tvorba spolehlivých aplikací
Delphi poskytuje mechanismus, který dokáže značnou měrou přispět k větší robustnosti aplikací, což znamená, že aplikace reaguje na chyby konzistentním způsobem, dokáže podle možností zajistit zotavení ze vzniklé chyby a případně uzavřít rozpracovanou činnost bez ztráty dat nebo systémových prostředků Windows.
Vznik chyby je v Delphi je obsloužen vytvořením výjimky. Výjimka je objekt, který obsahuje informaci o tom, jaká chyba se stala a kde vznikla.
Chráněné programové bloky
Programový kód robustní aplikace musí rozpoznat vznik výjimky a musí na ní reagovat. Pokud nespecifikujeme reakci, aplikace bude ukončena zprávou identifikující chybu. Úkolem programátora je tedy identifikovat místa, kde může chyba vzniknout a definovat odpovídající reakci, především v těch částech programu, kde může chyba způsobit ztrátu dat nebo systémových prostředků.
Reakce na výjimku je vždy vázána na programový blok. Potřebujeme-li tedy pro posloupnost programových příkazů určitou reakci na chybu, uzavřeme tyto příkazy do bloku a definujeme reakci na chybu pro tento blok.
Bloky s definovanou reakcí na výjimky se nazývají chráněné bloky, protože jsou částečně chráněny proti chybám, které jinak mohou způsobit havárii aplikace nebo poškodit data. Chráněný blok začíná klíčovým slovem try a končí klíčovým slovem end.
Příklad:
try
a:=0;
b:=100/a;
Edit1.Text:=‘Tohle se nikde nenapíše‘;
except
Edit1.Text:=‘Bylo děleno nulou‘;
end
Při převodu čísel z typu string na typ extended lze použít metodu val:
var code: integer;
vystup: extended;
begin
// test vstupnich hodnot, ERROR -> defaultni hodnoty
val(Edit1.Text,vystup,code);
if code<>0 then Edit2.Text:=‘V Edit1 boxu nebylo cislo, které se da prevest‘;
Edit2.Text:=‘Obsah Edit1 boxu byl preveden na cislo a je ulozen v promenne vystup‘;
end;
Politica de confidentialitate | Termeni si conditii de utilizare |
Vizualizari: 836
Importanta:
Termeni si conditii de utilizare | Contact
© SCRIGROUP 2024 . All rights reserved