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 36920×

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ů

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ář

13.9.2017 8:00 /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 – tentokrát netradičně v pondělí: 18. září od 18:00 v Radegastovně Perón (Stroupežnického 20, Praha 5).
Přidat komentář

3.9.2017 20:45 /Redakce Linuxsoft.cz
PR: Dne 21. září 2017 proběhne v Praze konference "Mobilní řešení pro business". Hlavní tématy konference budou: nejnovější trendy v oblasti mobilních řešení pro firmy, efektivní využití mobilních zařízení, bezpečnostní rizika a řešení pro jejich omezení, správa mobilních zařízení ve firmách a další.
Přidat komentář

15.5.2017 23:50 /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, který se bude konat ve čtvrtek 18. května od 18:00 v Radegastovně Perón (Stroupežnického 20, Praha 5).
Přidat komentář

12.5.2017 16:42 /Honza Javorek
PyCon CZ, česká konference o programovacím jazyce Python, se po dvou úspěšných ročnících v Brně bude letos konat v Praze, a to 8. až 10. června. Na konferenci letos zavítá např. i Armin Ronacher, známý především jako autor frameworku Flask, šablon Jinja2/Twig, a dalších projektů. Těšit se můžete na přednášky o datové analytice, tvorbě webu, testování, tvorbě API, učení a mentorování programování, přednášky o rozvoji komunity, o použití Pythonu ve vědě nebo k ovládání nejrůznějších zařízení (MicroPython). Na vlastní prsty si můžete na workshopech vyzkoušet postavit Pythonem ovládaného robota, naučit se učit šestileté děti programovat, efektivně testovat nebo si v Pythonu pohrát s kartografickým materiálem. Kupujte lístky, dokud jsou.
Přidat komentář

2.5.2017 9:20 /Eva Rázgová
Putovní konference československé Drupal komunity "DrupalCamp Československo" se tentokrát koná 27. 5.2017 na VUT FIT v Brně. Můžete načerpat a vyměnit si zkušenosti z oblasti Drupalu 7 a 8, UX, SEO, managementu týmového vývoje, využití Dockeru pro Drupal a dalších. Vítáni jsou nováčci i experti. Akci pořádají Slovenská Drupal Asociácia a česká Asociace pro Drupal. Registrace na webu .
Přidat komentář

1.5.2017 20:31 /Pavel `Goldenfish' Kysilka
PR: 25.5.2017 proběhne v Praze konference na téma Firemní informační systémy. Hlavními tématy jsou: Informační systémy s vlastní inteligencí, efektivní práce s dokumenty, mobilní přístup k datům nebo využívání cloudu.
Přidat komentář

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

> Poslední diskuze

18.9.2017 14:37 / Rojas
high security vault

15.9.2017 7:33 / Wilson
new zealand childcare jobs

31.8.2017 12:11 / Jaromir Obr
Re: ukůládání dat ze souboru

30.7.2017 11:12 / Jaromir Obr
Národní znaky

27.7.2017 12:24 / Jaromir Obr
Cteni/zapis

Více ...

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