LINUXSOFT.cz Přeskoč levou lištu
Uživatel: Heslo:  
   CZUKPL

> C/C++ (39) - Objektově orientované programování

Za nejčastější důvod proč použít C++ místo C se uvádí objektově orientované programování (OOP). Dnes se zamyslíme nad tím, co to OOP vlastně je a jak se liší od klasického procedurálního programování ve stylu C.

4.10.2006 10:00 | Jan Němec | Články autora | přečteno 37565×

Objektově orientované programování

Hned ze začátku bych rád čtenáře varoval. Objektově orientovaná programování (OOP) je stále ještě určitý fenomén. O všem, co je nebo kdy bylo moderní a populární v pozitivním i negativním smyslu a do určité míry kontroverzní (nejen ve světě počítačů), si můžeme přečíst spoustu článků silně zkreslených názorem autora. Diskuse, zda je OOP dobré nebo špatné a který objektově orientovaný jazyk je nejlepší tak silně připomínají diskuse na téma Linux kontra Windows a tahanice o nejlepší linuxovou distribuci.

Programy se obvykle snaží řešit konkrétní problém a jsou určitým modelem nějakého prostředí, ať už se jedná o implementaci algoritmu z abstraktního světa matematiky, simulaci z našeho fyzického světa nebo třeba GUI knihovnu. Z vlastní programátorské praxe vím, že OOP zjednodušuje a zpřehledňuje kód (především větších projektů) všude tam, kde objekty vyskytují i v problému samotném. Pokud píšeme Eukleidův algoritmus pro hledání největšího společného dělitele dvou čísel typu int, OOP nám nepomůže, neboť v algoritmu samotném se objekty nevyskytují. Naopak třeba při diskrétní simulaci dopravního problému se nám objekty mohou hodit pro dopravní prostředky a jejich datové struktury, semafory a podobně. Celá hierarchie typů objektů pro nejrůznější prvky GUI pak bude v každé objektově orientované knihovně grafického uživatelského rozhraní. Programovat objektově orientovaný problém pochopitelně lze i klasicky, procedurálně, ve stylu C, nicméně s OOP je to jednodušší.

Občas se setkáme s názorem, že OOP pomáhá odstraňovat nepříjemné paměťové chyby. Moje programátorská praxe to nepotvrzuje, správně procedurálně navržený kód považuji za zhruba stejně bezpečný jako kvalitní kód v duchu OOP. Rozdíly vyplývají spíše z toho, že se v C obvykle programuje poněkud nižším způsobem než v C++ a jazyky se používají na řešení odlišných problémů. I zde však platí, že klasické céčkovské problémy spojené například s chybným použitím ukazatelů a přetečením zásobníku vyvažují paměťové chyby specifické pro C++ a jeho standardní knihovnu. Odhalit programátorskou chybu, která se projevuje pádem programu v kódu C++ STL knihovny bývá často těžší než detekovat chybnou alokaci v klasickém programu v C. Celkově platí, že C klade větší nároky na obecnou schopnost programovat, C++ zase na konkrétní znalosti. Ochranu proti paměťovým chybám a automatickou správu paměti poskytují až pokročilejší jazyky jako je dnes například Java nebo C#, ale ani v jejich případě to nesouvisí s OOP (případná procedurální Java by byla bezpečná stejně) a i v jejich případě to s sebou zároveň přináší i určité nevýhody.

V OOP se vyskytují pojmy třída (anglicky class) a objekt (object). Třída znamená objektový typ, objekt pak instanci daného typu. Obojí známe již z klasického procedurálního programování. Třídám se nejvíce podobají strukturované typy (typedef struct ...) a objektům odpovídají proměnné těchto typů. Pojmy typ a proměnná se používají i v OOP.

Tři základní vlastnosti OOP

OOP není jen konkrétní syntaxe jazyka, ale především způsob programování. V C lze při troše snahy psát objektově a platí to i naopak, v objektově orientovaných jazycích jako například C++ nebo Java je možné psát klasicky procedurálně. Podpora na úrovni syntaxe jazyka OOP pouze výrazně zjednodušuje. Důležité jsou 3 ideje objektově orientovaného programování: zapouzdření, dědičnost a polymorfismus. Dnes se blíže podíváme na zapouzdření, zbylé dvě vlastnosti probereme příště.

Zapouzdření (encapsulation)

Algoritmy a datové struktury řešící jeden problém patří v kódu k sobě. Na data a metody, které netvoří rozhraní by se nemělo sahat z vnějšku. Výsledkem této snahy je třída. Ta se podobá céčkovské struktuře, ale na rozdíl od ní obsahuje i funkce. Funkcím třídy se říká metody. Třída navíc může definovat oprávnění, která omezí z vnějšku přístup k datům a volání metod. Abychom si ujasnili význam zapouzdření, ukážeme si kód, který se této zásadě příčí. Budeme jej postupně upravovat, tak aby ideji zapouzdření vyhovoval.

Představme si datovou strukturu, reprezentující množinu čísel typu int, jejíchž počet předem neznáme. Datovou strukturu opakovaně používáme třeba v nějakém matematickém algoritmu, který ladíme, takže operace potřebujeme logovat. Jedním z řešení by bylo dynamicky alokované pole, které podle potřeby zvětšujeme a případně i zmenšujeme. Abychom se vyhnuli realokaci po každém přidaném číslu, můžeme alokovat například vždy na dvojnásobek předchozí hodnoty tj. pokud máme naalokováno třeba 1024 intů a chceme přidat 1025. int, provedeme realokaci rovnou na 2048. Nejhorší implementace s použitím globálních proměnných by vypadala asi takhle:

Řešení 1

int *p;
int naalokovanoPrvku;
int pocetPrvku;

void init() {
  naalokovanoPrvku = 16;
  pocetPrvku = 0;
  p = (int *) malloc(naalokovanoPrvku * sizeof(int));
}

void loguj(int i, const char *akce) {
  printf("%s %i\n", akce, i);
}

void pridej(int cislo) {
  loguj(cislo, "pridej");
  if (naalokovanoPrvku == pocetPrvku) {
    // realokace
  }
  p[pocetPrvku++] = cislo;
}

void uber(int cislo) {
  loguj(cislo, "uber");
  // ...
}

bool obsahuje(int cislo) {
  loguj(cislo, "obsahuje");
  // ...
}

void done() {
  free(p);
  p = NULL;
}

// ...

Kód jsem navrhl schválně špatně, nevyhovuje nejen OOP, ale ani zásadám procedurálního programování. Funkce využívají globální proměnné, což je vždy potenciálním zdrojem problémů. Představme si třeba, že bychom chtěli mít dvě instance datové struktury najednou. Při takto navrženém kódu bychom potřebovali nejen dvě sady proměnných, ale i dvě sady funkcí.

Řešení 2

Chceme-li strukturu používat ve více instancích a neduplikovat kód, musíme se vzdát přímého přístupu ke globálním proměnným. Funkcím tak přibudou parametry.

// proměnné pro 1. instanci
int *struktura1_p;
int struktura1_naalokovanoPrvku;
int struktura1_pocetPrvku;

// a pro druhou instanci
int *struktura2_p;
int struktura2_naalokovanoPrvku;
int struktura2_pocetPrvku;

// definice funkcí (pro všechny instance dohromady)

void init(int **p, int *pocetPrvku, int *naalokovanoPrvku) {
  *naalokovanoPrvku = 16;
  *pocetPrvku = 0;
  *p = (int *) malloc(*naalokovanoPrvku * sizeof(int));
}

void pridej(int **p, int *naalokovanoPrvku, int *pocetPrvku, int cislo) {
  // ...
}

// ostatní funkce obdobně

// ...

// použití 1. instance

init(&struktura1_p, &struktura1_naalokovanoPrvku, &struktura1_pocetPrvku);
pridej(&struktura1_p, &struktura1_naalokovanoPrvku, &struktura1_pocetPrvku, 7);
// atd.

Řešení 3

Pokud se vám druhé řešení nelíbilo, nejste sami. Neustálé předávání tří parametrů - proměnných datové struktury je velmi otravné. Pomůžeme si první vlastností OOP, zapouzdřením. Nakročením na půl cesty k OOP je již klasická céčkovská struktura, zatím tedy stále nic nového.

struct DynamickePole {
  int *p;
  int naalokovanoPrvku;
  int pocetPrvku;
};

void init(/* v C bychom sem museli napsat "struct", v C++ ne */
  DynamickePole *d) {

  d->naalokovanoPrvku = 16;
  d->pocetPrvku = 0;
  d->p = (int *) malloc(d->naalokovanoPrvku * sizeof(int));
}

void pridej(DynamickePole *d, int cislo) {
  // ...
}

// další funkce obdobně

// použití

DynamickePole d;
init(&d);
pridej(&d, 7);
// ...
Řešení 4

Je vidět, že snaha o zapouzdření má smysl i v klasickém procedurálním kódu ve stylu C, kód z třetího řešení již je docela dobře použitelný. OOP v C++ ovšem jde dál, zapouzdřuje nejen proměnné, ale i funkce. Místo klíčového slova struct se potom většinou používá nové klíčové slovo class.

class DynamickePole {
private:
  int *p;
  int naalokovanoPrvku;
  int pocetPrvku;  
public:
  void init() {
    naalokovanoPrvku = 16;
    pocetPrvku = 0;
    p = (int *) malloc(naalokovanoPrvku * sizeof(int));
  }

  void pridej(int cislo) {
    // ...
  }

  // ...

};

// Použití

DynamickePole d;
d.init();
d.pridej(7);
// ...

Uvedený kód ještě zdaleka není ideální, ale zásadu zapouzdření už splňuje i z hlediska vysokých nároků OOP. Každý objekt třídy DynamickePole obsahuje 3 proměnné, které jsou soukromé, private. To znamená, že k nim máme přístup pouze z metod třídy DynamickePole a nikoli z vnějšku. To je důležité, jde o určitou ochranu vnitřních dat objektu, tedy dat, která netvoří rozhraní třídy. Naopak všechny metody v našem případě rozhraní tvoří, jsou tedy veřejné, public a lze je volat z vnějšku. C++ samozřejmě umožňuje i naopak definovat veřejnou proměnnou a soukromou metodu. V našem případě by mohla být soukromá třeba nějaké metoda provádějící realokaci, volali bychom ji z pridej a uber. Všimněte si, že metody se píší dovnitř třídy. Nejsou to tedy globální funkce, volat je můžeme pouze přes nějakou instanci třídy DynamickePole. Možnost vlastnit kromě proměnných i metody je hlavním rozdílem C++ třídy oproti C struktuře. Do definice třídy nemusíme psát celé tělo funkce, stačí hlavička ukončená středníkem. Metodu potom definujeme podobně jako globální funkci, překladač ovšem musí nějak poznat, ke které třídě patří. Proto v tomto případě předřadíme jméno třídy a čtyřtečku.

class DynamickePole {
// ...
public:
  void init();
// ...
}

// a někde později
void DynamickePole::init() {
  // ...
}

Domácí úkol

Zkuste si některé z řešení 1 až 4 naprogramovat, samozřejmě nejlépe řešení 4. Představte si, že se jedná o knihovnu, kterou bude používat jiný programátor a rozmyslete si, která řešení pro tento případ vyhovují.

Pokračování příště

Příště se zamyslíme nad dědičností a polymorfismem.

Verze pro tisk

pridej.cz

 

DISKUZE

OOP 4.10.2006 22:02 Aleš Dostál
  |- Re: OOP 5.10.2006 08:33 Petr Zajíc
  L Re: OOP 10.1.2007 15:00 camlost




Příspívat do diskuze mohou pouze registrovaní uživatelé.
> Vyhledávání software
> Vyhledávání článků

17.4.2018 0:46 /František Kučera
Dubnový pražský sraz spolku OpenAlt se koná již tento čtvrtek – 19. 4. 2018 od 18:00 v Kavárně Ideál (Sázavská 30, Praha), kde máme rezervovaný salonek. Tématem tohoto srazu bude OpenStreetMap (OSM) aneb svobodné mapy.
Přidat komentář

16.3.2018 22:01 /František Kučera
Kulatý OpenAlt sraz v Praze oslavíme klasicky: u limonády a piva! Přijďte si posedět, dát si dobré jídlo a vybrat z mnoha piv do restaurace Kulový blesk, který najdete v centru Prahy nedaleko metra I. P. Pavlova na adrese Sokolská 13, Praha 2. Sraz se koná ve čtvrtek 22. března a začínáme v 18:00. Heslo: OpenAlt. Vezměte s sebou svoje hračky! Uvítáme, když si s sebou na sraz vezmete svoje oblíbené hračky. Jestli máte nějaký drobný projekt postavený na Arduinu, nějakou zajímavou elektronickou součástku, či třeba i pěkný úlovek z crowdfundingové akce, neváhejte. Oslníte ostatní a o zábavu bude postaráno.
Přidat komentář

13.2.2018 0:41 /František Kučera
Únorový pražský sraz OpenAltu se koná 15. 2. 2018 a tentokrát se vydáme na návštěvu do jednoho pražského datacentra. Sejdeme se v 17:50 v severovýchodní části nástupiště tramvajové zastávky Koh-I-Noor. Po exkurzi se přesuneme do restaurace U Pštrosa (Moskevská 49), kde probereme tradiční témata (svobodný software a hardware, DIY, CNC, SDR, 3D tisk…) a tentokrát bude k vidění i IoT brána od The Things Network.
Přidat komentář

11.2.2018 23:11 /Petr Ježek
Hledáte lehký a rychlý prolížeč PDF souborů? Pokud vás již omrzelo čekat na načítání stránek či jiné nešvary, zkuste xreader.
Přidat komentář

11.2.2018 20:35 /Redakce Linuxsoft.cz
Třetí ročník odborné IT konference na téma Cloud computing v praxi proběhne ve čtvrtek 1. března 2018 v konferenčním centru Vavruška, v paláci Charitas, Karlovo náměstí 5, Praha 2 (u metra Karlovo náměstí) od 9:00 hod. dopoledne do cca 16 hod. odpoledne. Konference o trendech v oblasti cloud computingu nabídne i informace o konkrétních možnostech využívání cloudů a řešení vybraných otázek souvisejících s provozem IT infrastruktury.
Přidat komentář

15.1.2018 0:51 /František Kučera
První letošní pražský sraz se koná již tento čtvrtek 18. ledna od 18:00 v Radegastovně Perón (Stroupežnického 20, Praha 5). Vítáni jsou všichni příznivci svobodného softwaru a hardwaru, ESP32, DIY, CNC, SDR nebo dobrého piva. Prvních deset účastníků srazu obdrží samolepku There Is No Cloud… just other people's computers. od Free Software Foundation.
Přidat komentář

14.11.2017 16:56 /František Kučera
Máš rád svobodný software a hardware nebo se o nich chceš něco dozvědět? Zajímá tě DIY, CNC, SDR nebo morseovka? Přijď na sraz spolku OpenAlt – tradičně první čtvrtek před třetím pátkem v měsíci: 16. listopadu od 18:00 v Radegastovně Perón (Stroupežnického 20, Praha 5).
Přidat komentář

12.11.2017 11:06 /Redakce Linuxsoft.cz
PR: 4. ročník odborné IT konference na téma Datová centra pro business proběhne již ve čtvrtek 23. listopadu 2017 v konferenčním centru Vavruška, v paláci Charitas, Karlovo náměstí 5, Praha 2 (u metra Karlovo náměstí) od 9:00. Konference o návrhu, budování, správě a efektivním využívání datových center nabídne odpovědi na aktuální a často řešené otázky, např Jaké jsou aktuální trendy v oblasti datových center a jak je využít pro vlastní prospěch? Jak zajistit pro firmu či jinou organizaci odpovídající služby datových center? Podle jakých kritérií vybrat dodavatele služeb? Jak volit součásti infrastruktury při budování či rozšiřování vlastního datového centra? Jak efektivně spravovat datové centrum? Jak eliminovat možná rizika? apod.
Přidat komentář

   Více ...   Přidat zprávičku

> Poslední diskuze

20.2.2018 18:48 / Ivan Majer
portal

20.2.2018 15:57 / Jan Havel
Jak využíváte služby cloudu v podnikání?

16.1.2018 1:08 / Ivan Pittner
verejna ip od o2 ubuntu

15.1.2018 17:26 / Mira Harvalik
Re: Jak udělat HTML/Javascript swiping gallery do mobilu?

30.12.2017 20:16 / Michal Knoll
odmocnina

Více ...

ISSN 1801-3805 | Provozovatel: Pavel Kysilka, IČ: 72868490 (2003-2018) | mail at linuxsoft dot cz | Design: www.megadesign.cz | Textová verze