Maturitní otázka č. 2
2. Programování – Objekty
1. Co je objekt, jak vzniká a jak jej nahradit v ne-objektových jazycích
Objekt je základním stavebním kamenem objektově orientovaného programování (OOP). Představuje softwarový model reálného nebo abstraktního prvku (např. auto, uživatel, bankovní účet). Skládá se ze dvou hlavních částí:
- Datová část (Atributy/Vlastnosti): Představují aktuální stav objektu (např. barva auta, rychlost).
- Funkční část (Metody): Představují chování objektu, tedy operace, které může objekt provádět nebo které lze provádět s ním (např. nastartuj, zrychli).
Vznik objektu:
Objekt vzniká procesem zvaným instanciace (vytvoření instance). Vychází se z tzv. třídy (Class), což je obecný předpis (šablona nebo "formička"), podle které se objekt v operační paměti vytvoří. Při vzniku se alokuje paměť a zavolá se speciální metoda zvaná konstruktor. V mnoha jazycích se k tomu používá klíčové slovo "new".
Nahrazení v ne-objektových jazycích:
V procedurálních jazycích, jako je čisté C, objekty neexistují. Můžeme je ale simulovat (nahradit) pomocí datových struktur (např. "struct" v C), které sdružují více proměnných různých typů pod jedno jméno. Metody (chování) se pak nahrazují běžnými volně stojícími funkcemi, kterým jako jeden z parametrů předáváme ukazatel právě na tuto strukturu, aby funkce věděla, s jakými daty má pracovat.
2. Koncepce objektově orientovaného programování (OOP)
Koncepce OOP vznikla jako reakce na složitost údržby rozsáhlých procedurálních programů. Cílem je modelovat program tak, aby odpovídal myšlení člověka v reálném světě. OOP stojí na čtyřech základních pilířích:
- Zapouzdření (Encapsulation): Sdružuje data a metody do jednoho celku (objektu) a skrývá vnitřní implementaci před okolním světem. K datům se přistupuje pouze přes definované metody (tzv. gettery a settery). Tím se zabrání nechtěnému přepsání nebo poškození dat zvenčí.
- Dědičnost (Inheritance): Umožňuje vytvářet nové třídy na základě již existujících (rodičovských) tříd. Nová třída (potomek) přebírá všechny atributy a metody rodiče a může si přidat vlastní nebo existující upravit. To masivně snižuje duplicitu kódu (např. třída "Pes" dědí ze třídy "Zvíře").
- Polymorfismus (Polymorphism): Znamená "mnohotvárnost". Umožňuje používat jednotné rozhraní pro různé typy objektů. Například metoda "VypisZvuk()" se zachová jinak, pokud ji zavoláme na objektu Pes (štěkne) a jinak u objektu Kočka (zamňouká), ačkoliv název metody je stejný.
- Abstrakce (Abstraction): Skrývání složitých detailů a zobrazování pouze nezbytných vlastností objektu. Uživatel auta nepotřebuje znát přesný princip spalovacího motoru, stačí mu vědět, že po sešlápnutí pedálu auto zrychlí.
3. Objektově orientované programovací jazyky
Dnes je podpora OOP standardem u většiny populárních jazyků. Dělíme je na:
- Čistě objektové: Vše v jazyce je objekt, dokonce i základní datové typy. Příkladem je Ruby nebo Smalltalk.
- Multi-paradigmatické (s podporou OOP): Kombinují objektový přístup s procedurálním nebo funkcionálním. Patří sem většina komerčně používaných jazyků: Java, C#, C++, Python, PHP nebo JavaScript.
4. Konstruktory, destruktory a přetížení (Overloading)
Konstruktor: Je speciální metoda, která se spouští zcela automaticky přesně v momentě vytváření nové instance třídy (objektu). Jeho hlavním úkolem je inicializovat objekt – nastavit výchozí hodnoty atributů a alokovat potřebné zdroje. Obvykle nenese návratový typ a často se jmenuje stejně jako samotná třída (např. v Javě, C#) nebo má speciální název (např. __init__ v Pythonu).
Destruktor: Speciální metoda volaná automaticky před samotným zánikem objektu (když program končí nebo je objekt smazán z paměti). Slouží k úklidu – uzavření souborů, ukončení síťových spojení nebo uvolnění explicitně alokované paměti. V jazycích s tzv. Garbage Collectorem (C#, Java) se destruktory v tradičním pojetí nepoužívají tak často jako např. v C++, protože paměť se uvolňuje automaticky.
Přetížení (Overloading): Jde o situaci, kdy máme v jedné třídě více metod (nebo konstruktorů) se zcela STEJNÝM názvem, ale liší se v tzv. signatuře – tedy v počtu nebo v datových typech vstupních parametrů. Kompilátor při volání sám určí, která verze se má spustit, na základě toho, s jakými daty ji voláme.
5. Praktická ukázka: Třída s atributy, přetíženým konstruktorem a metodou
Jako ukázku využijeme jazyk C# (popřípadě syntaxe odpovídá i Javě), protože nativně ukazuje přetížení konstruktorů. Vytvoříme třídu Auto splňující všechny požadavky zadání:
public class Auto {
// a. Čtyři atributy aspoň dvou různých datových typů (string a int/double)
public string Znacka;
public string Model;
public int RokVyroby;
public double Cena;
// b. Předpis konstruktoru s přetížením
// Konstruktor 1 (základní - předáme jen značku a model)
public Auto(string znacka, string model) {
this.Znacka = znacka;
this.Model = model;
// Defaultní hodnoty pro zbytek
this.RokVyroby = 2024;
this.Cena = 500000.0;
}
// Konstruktor 2 (přetížený - předáme všechny parametry)
public Auto(string znacka, string model, int rokVyroby, double cena) {
this.Znacka = znacka;
this.Model = model;
this.RokVyroby = rokVyroby;
this.Cena = cena;
}
// c. Aspoň jedna metoda, která není konstruktorem
public void VypisInformace() {
Console.WriteLine($"Vozidlo {Znacka} {Model}, rok: {RokVyroby}, cena: {Cena} Kč.");
}
}
V tomto kódu vidíme zapouzdření vlastností (zde pro jednoduchost public, v praxi by byly private/protected a měly by property). Máme dva konstruktory – jeden pro rychlé vytvoření nového vozu (stačí model a značka), druhý pro detailní specifikaci. Metoda VypisInformace() následně zpracovává vnitřní data objektu a vypisuje je uživateli.