# OOP poznámky ke zkoušce ![](https://i.imgur.com/ZVH539A.png) - tohle tak fuguje protože deklarace y na řádku 23 platí od toho místa dolů, to znamená že na řádku 21 se používá stará deklarce ![](https://i.imgur.com/9wkja6M.png) - při dědění se nejprve vyhodnocnocuje konstruktor rodičovské třídy, pak až toho zděděného. Desktruktory se vyhodnocují přesně naopak (první zděděné, pak nadřazené) - nezapoměň u příkladu v C že se předává hodnotou! - striktní jmenná typová ekvivalence - musí mít přesně stejné typ (stejné jméno typu) - volná jmenná typová ekvivalence - ekvivalentní jsou i aliasy na stejné jméno - všechny typy v C jsou mutable, pokud neuvedeme const - deklarace v pythonu platí pro celý blok: ```python= c = 42 def foo(): print(c) # works def bar(): print(c) # fails, variable usage before definition c = 121 foo() bar() ``` - C# = nekteré typy jsou value types, ostatní reference, pass by value - Python = reference types, pass by sharing - ![](https://i.imgur.com/2VFVYrl.png) - velikost unionu je rovna velikosti největší položky - ![](https://i.imgur.com/9MQiDdr.png) - pole = prvky za sebou v paměti, většinou homogenní (stejný typ) - list (seznam) = rekurzivní struktůra ($1 : (2 : [])$), nebo linked list - head = první prvek - tail = list bez prvního prvku - improper list = rekurze nekončí připojením do prázdného listu ($(1 : 2)$) - v C# klíčovým slovem "var" řekneme překladači, že má odvodit typ - věci uložené na heapu nemají jméno, nedá se přistupovat jinak než nepřímo (ukazateli) - ukazetelová aritmetika = $ptr + index \to$ k ptr se přičte $index∗sizeof(*ptr)$ - přiřazovací příkaz $=$ vrací hodnu (dá se použít ve výrazech) - k typové konverzi dochází jen pokud dojde ke skutečné změně typu ```c= // C int i = 5; int j = (int) i; // není explicitní typová konverze ``` ```c= // C int i = 5; long j = (short) i; // explicitní i implicitní konverze ``` ```python= i = 5 f = 1.5 a = i + i # bez konverze b = f + f # bez konverze c = i + f # implicitní konverze f = 2 # bez konverze (reassignment) ``` - Referential transparency = libovolný výraz můžeme nahradit jeho hodnotou bez vlivu na chování programu - Podprogram má pouze jeden vstupní bod ![](https://i.imgur.com/f9d5gPj.png) - C# a python $\to$ mají default parametry, při volání se dají použít poziční i pojmenované parametry (poziční musí být první, po vynechnání parametru nebo použítí pojmenovovaného parametru už nesmíme použít poziční) - C# `params` keyword $\to$ pro proměnlivý počet argumentů stejného typu - Obdržálkovi asociační brikule - asociace zleva-doprava - asociace zprava-doleva - asociace zleva = zleva-doprava - asociace doprava = zprava-doleva (xDDD) - typy parametrů - in $\to$ předané vstupní parametry (hodnotové parametry) - out $\to$ výstupní parametry (return value, pass-by-value-result) - in-out $\to$ vstupní parametry které jsou funkcí upraveny (například při pass-by-reference) - předávání parametrů: - pass-by-value (předávání hodnotou, in) $\to$ hodnota se zkopíruje do parametru - pass-by-reference (předávání odkazem, in-out) $\to$ je předán odkaz na proměnnou, můžeme modifikovat objekt se kterým má proměnná vazbu, nebo do proměnné přidělit jinou hodnotu - pass-by-sharing (předání sdílením, in-out) $\to$ předává se odkaz na objekt, ne odkaz na proměnou. Objekt můžeme modifikovat, nelze ale přiřadit jiný objekt do původní proměnné. Python předává sdílením. - pass-by-result (předání výsledkem, out) $\to$ parametr podprogramu nepředává hodnotu, hodnoty uložené do parametru se **po skončení běhu podprogramu** propragují do původní proměnné - pass-by-value-result (předání hodnotou-výsledkem, in-out) $\to$ jako pass-by-result ale parametr podprogramu předává i hodnotu pomocí pass-by-value - pass-by-name (předání jménem, in-out) $\to$ textové nahrazení (jako makra v C). Výrazy použity jako parametry volání se nevyhodnocují, ale nahradí se jako text do podprogramu, až při běhu podprogramu dochází k jejich vyhodnocení ```c= // C-like int[] C = { 1, 2, 3 }; int i = 0; void foo(int x) { i = 2; x = 5; // x = 5 -> C[i] = 5 -> C[2] = 5 -> C = { 1, 2, 5 } } foo(C[i]); ``` - C# předávání parametrů - value types (int, bool, enum, struct...) $\to$ pass-by-value - reference types (class, string) $\to$ pass-by-sharing - modifikátory in (refrence), ref (reference), out (result) - C# `in` keyword $\to$ zamezí přiřazení do parametru, modifikace povolena (v C# 6.0 není) - C# `out` keyword $\to$ pass-by-value-result - C# `ref` keyword $\to$ pass-by-reference - C# keywords pro paremetry je nutné uvést i při volání funkce (`foo(out x)`) - C `const` zamezí modifikace a přirazení (jde obejít pomocí ukazatelů) - přetížené podprogramy (overloading) $\to$ existuje více podprogramů se stejným jménem, ten správný je vybrán pomocí protokolu (C#) - protokol = profil parametrů (počet, pořadí a typ parametrů) + návratový typ podprogramu - overriding $\to$ přepsání existujícího podprogramu (Python) - typy polymorfismu - ad-hoc $\to$ overloading podprogramů, proměnlivý počet parametrů - parametrický $\to$ generické parametry - podtypový $\to$ dědičnost metod - Generické funkce - C++ $\to$ při překladu se vytvoří separátní kód pro každý použitý typ - Java $\to$ generické parametry musí být třídy (možnost omezit množinu tříd), takže vytváří jen jednu kopii - C# $\to$ umí pracovat i s primitivními typy, pro ty vygeneruje kód zvlášť - Koprogramy (coroutines) - více vstupních bodů - kontrola nad tím kde se pokračuje ve výpočtu - ADT (abstraktní datový typ) - matematický model datového typu, který je definován svými hodnotami a operacemi nad ním - ADT (user definied) - skrýtá reprezentace - rozhrání v jedné programové jednotce a není závislé na implementaci - uživatele mohou vytvářet hodnoty tohoto typu - OOP bylo zavedeno kvůli dědičnosti, ať lidé nemusí modifikovat ADT ![](https://i.imgur.com/Eq3Fvle.png) - skrývání informací (information hidign) $\to$ informace které uživatel nepotřebuje jsou skryty (vnitřní reprezentace). Uživatele nemohou změnami poškodit struktůru a nemusí se učit vnitřní reprezentaci. Při změně kodu rozhrání zůstavá stejné - zapouzdění (encapsulation) $\to$ pod stejným jménem spojuje data a operace na nich. **Často zahrnuje information hiding** - v Python: - encapsulation $\to$ class - information hiding $\to$ není, ale: - _bar $\to$ neměly by se používat, ale pořád jsou přístupné - __bar $\to$ skoro private, při překladu jsou mangled (před jméno atributu se přidá _nazevtridy), s mangled jménem se ale pořád dají accesovat ```python= class Test: def __init__(self): self.count = 0 def increment(self): self.count += 1 test_object = Test() test_object.increment() # Both are identical in functionality Test.increment(test_object) # . before methods used the left operand as a call parameter for the method ``` ![](https://i.imgur.com/PrfmXMB.png) - v C#: - encapsulation $\to$ class, struct - information hiding $\to$ private - když v C# chceme zviditelnit atribut: - `public` keyword $\to$ porušujeme information hiding - gettery/settery $\to$ metody pro přístup k private atributům - properties $\to$ jako atributy, ale můžeme jim nastavit způsob přístupu - generuje skryté atributy - properties samotné jsou vždy public - `public string Name { get; set; }` $\to$ přístupný veřejně jako object.Name - `public string Name { private get; private set; }` $\to$ přístupný jen ve třídě pro kterou je deklarován - `public string Name { get; }` $\to$ set jenom v konstruktoru - možnost uvést vlastní get/set funkce (musíme vytvořit vlastní skrytý atribut) - ```c#= public string Name { get { return _name; } set { _name = value; } } ``` - třídy můžou být Generic ```c#= class Stack<T> { private List<T> items = new List<T>(); } ``` - Konstruktory - nemají návratový typ - název se musí shodovat s názvem třídy - když neexistuje konstruktor, vytvoří se default konstruktor který hodnoty inicializuje na default value danou typem - Destruktory (finalizers) - Volají se na konci života objektu (Garbage collection, ne nutně hned po ztrátě odkazu na objekt), nelze je volat explicitně - Pokud chceme uvolňovat drahé prostředky, tak radši implementovat metodu `Dispose()` z interfacu `IDisposable` - `static` atributy a metody $\to$ nepatří instanci ale třídě samotné, existuje jen jedna kopie - statické třídy - mají jen statické členy - nelze je inicializovat - nemají konstruktor - class based OOP = C#, python - prototype based OOP = js, Lisp - C# dědičnosti $\to$ jsou zděděny všechny atributy i metody, přístupnost zaleží na modifikátoru - `public` $\to$ přístupný kdekoliv - `private` $\to$ přístupný jen ve třívě, ve které je deklarován (přesto je ale zděděn) - `proteccted` $\to$ přístupný jak ve třídě deklarace, tak i v třídách které jsou potomky třídy - C# potomci před spuštěním svého konstruktoru volají rodičovský konstruktor, implicitně se volá konstruktor bez parametrů - C# má dva druhy vazeb pro objekty - statická (časná) vazba - zděděné typy metody **skrývají**, dá se volat pomocí base - deklarace původní metody zůstane nezměněná, metodě která tuto metodu skrývá se musí přidat klíčové slovo `new` - dynamická (pozdní) vazba - překrývání metod (metod overriding) - původní třída musí mít klíčové slovo `virtual`, překrývající metoda `override` ```c#= Device d = new SoundDevice(); d.PrintStatus(); // statická = při překladu dojde k vazbě proměnné d na typ Device, zavolá se metoda z Device // dynamická = za běhu se zjistí typ proměnné d, výsledkem je typ SoundDevice, odkud se zavolá metoda ``` ![](https://i.imgur.com/dKXJT7f.png) - Abstraktní třídy - klíčové slova `abstract` - nelze instancovat - mohou obsahovat i neabstraktní metody - Abstraktní metody - nemají implementaci (pouze deklarace) - implicitně jsou virtual, je nutno překrýt v potomcích - Vícenásobná dědičnost - v C# nejde, nutno řešit pomocí interface - v Pythonu je, kolize metod je řešena pořadím deklarací tříd - C# Interface - podobné abstraktním třídám - všechny metody a atributy mají jen deklaraci a jsou public by default - nelze deklarovat static, abstract, virtual - třídy interfacy implementují, nedědí, nepoužívá se keyword `override` - Je možno tvořit hierarchii interfaců (navzájem se rozšiřují) - Když se dědí metoda se stejným názvem z více interfaců, tak musíme pro každý interface implementovat metodu zvlášť - Interface je typ, můžeme vytvářet hodnoty typu Interface - možnost implementovat z více interfaců, případně implementovat vícekrát jeden interface pro různé typy při používání generik ```c#= class Test : ITest<Bool>, ITest<Int> {} ``` - C# třída Object (System.Object) - všechny objekty z ní dědí implicitně - implementuje metody pro práci s objekty (CompareTo(), Equals()..), ty jsou virtuální a je možné je překrýt - - C# porovnání typů - `test is Test` $\to$ vrací True pokud je typu `Test` nebo rodičovského typu - `test.GetType() == typeof(Test)` $\to$ přesná ekvivalence - C# přetypování objektů - typecast `(Test) test` $\to$ vyhodí Exception když nelze převést - `(test as Test)` $\to$ vrací `null` když nelze převést ![](https://i.imgur.com/wuqAWGt.png) - C# všechny value types dědí ze třídy `System.ValueType` - C# boxing - převod proměnné na typ `object`, proměnná se alokuje na haldě - používá se pro metody, které berou parametry obecného typu Object (např `String.Concat("Answer", 42)`) - Mixins - rozšiřují funkcionalitu tříd - sdíleno mezi třídami nehierarchicky - porušuje principy OOP - V Pythonu lze jako mixin přidat metody jako `__init__`, a comparison metody (`_le_`, `__ge__`, `__eq__`...) - C# Mixins - interface s implementací - **nedědí se**, při použití nutno přetypovat `this` na typ mixinu ```c#= ((Test)this).TestMethod() ``` - C# exceptions - všechny musí dědit z třídy System.Exception - try, catch, finally - chytají se specific exception, zachytí se když je testovaná třída exception nad třidou té vyhozené - finally se spustí i když je v `try` return, break, nebo continue - ve finally nesmí být return, break ani continue - `throw new Exception("Message", e)` - throw $\to$ rethrowne poslední zachycenou expception - vyjímka se propaguje nahoru až do metody `Main`, pokud tam není zachycena, pak padá program - podmínka u zachycení expcetion ![](https://i.imgur.com/aBIcwrH.png) - Java exceptions - můžeme používat return, break a continue v bloku `finally` - všechny expcetion musí dědit z `Throwable` - 2 podtřídy - Error $\to$ JVM chyby - Exception $\to$ mimo jiné uživatelsky definované expceptions, RuntimeException zodpovídají za většinu runtime expcetions - Kontrolované vs nekontrolované vyjímky - Nekontrolované $\to$ Error a RuntimeException - Kontrolované - ostatní `Throwable` - musí být zachyceny přímo v metodě kde nastala, nebo v hlavičce metoda musí uvést, že zde může nastat chyba daného typu ```java= void method() throws Expception {} ``` - Python expceptions - try, except, finally, else - možnost zachytávat více typů vyjímek v jednom catch bloku - místo `throw` klíčové slovo `raise` - else blok se spustí pokud v try bloku nedošlo k vyjímce ![](https://i.imgur.com/48PW8Vk.png) ![](https://i.imgur.com/EvS2QwP.png) ![](https://i.imgur.com/p6Z96eD.png) ![](https://i.imgur.com/2IV94JQ.png)