XXII. Diel C++ - OOP, Polymorfizmus a Triedy III.

Michal Kyžňanský  /  17. 03. 2006, 00:00

Pokračujeme v našom seriáli o programovaní v C++ vysvetlením polymorfizmu ako takého a jeho aplikácie virtuálnych funkcii v triedach. Vysvetlíme si pojem dynamická (neskoršia väzba) a statická väzba. Polymorfizmus otvára dvere k množstvu nových možností v uľahčovaní a sprehľadňovaní programov. Nebudú chýbať samozrejme názorné príklady.

Polymorfizmus funkcii

Je vylepšenie týkajúce sa jazyka C++ (klasické C ho neobsahuje), ktoré umožňuje vytvárať a volať funkcie s rovnakým názvom, ale odlišnými parametrami. V skratke znamená polymorfizmus – “mnohotvárnosť”, teda zdieľanie jedného mena funkcie, ktorá nemusí, ale zväčša vykonáva rovnakú/podobnú vec, avšak s rozdielnym počtom a typom parametrov. Raz som narazil na jedno krásne vysvetlenie, že tieto funkcie sú ako slovesá vo vete – Mama perie v pračke. Mafián perie špinavé peniaze. Tento príklad ukazuje, že funkcie, v ktorých je uplatnení polymorfizmus sa podobajú čiastočne na homonymá z jazykového hľadiska. Ale dosť bolo slovenčiny :).

Pri používaní klasického polymorfizmu nie je nutné používať žiadne špeciálne nové príkazy ani nič podobné. Vytvoríme si na začiatok 4 funkcie s rovnakým názvom vypis. Každá však bude mať iné parametre. A compiler a linker zapoja svoju inteligenciu a podľa toho, s akými parametrami voláme funkciu vypis, tak práve tá funkcia vypis s adekvátnymi parametrami bude použitá.


//funkcia vypis s obmenami parametrov
void vypis(int a, int b){
ShowMessage(a + b); } //funkcia vypis s obmenami parametrov
void vypis(int pocet, AnsiString meno){
ShowMessage(pocet + " " + meno);
}

//funkcia vypis s obmenami parametrov
void vypis(double cislo){
ShowMessage(cislo/10);
}

//funkcia vypis s obmenami parametrov
void vypis(AnsiString c, AnsiString d){
ShowMessage(c + d);
}



A teraz vložíme do formulára komponent Button, ktorého telo bude obsahovať iba volanie funkcie. Vyskúšajte si to s ktorýmkoľvek parametrom funkcie vypis. Príklad všetkých štyroch funkcii vyzerá takto:

vypis(150,140);
vypis(12,"rohliky");
vypis(150);
vypis("Michal","Kyžňanský");

//použitie v tele funkcie Button1Click

void __fastcall TForm1::Button1Click(TObject *Sender)
{
//vypis(150,140);
//vypis(12,"rohliky");
vypis(150);
//vypis("Michal","Kyžňanský");
}


Virtuálne funkcie

Začneme od začiatku tým, že volanie funkcii tried nemusí byť reprezentované len priamo (premenou typu trieda a operátorom “.“ napríklad pocitac.vypis(); ), ale aj pomocou pointera – ukazovateľa. Trieda pocitac aj trieda procesor majú definovanú vlastnú funkciu vypis, ktorá vykonáva odlišnejšie operácie, ale to zatiaľ nie je podstatné aké. Skúsime si vytvoriť takýto zápis v programe a sledovať jeho priebeh.

Príklad
//1. Definovanie premenných typu pocitac a processor – obe 
//sú triedy vytvorené v minulom dieli
pocitac pc;
procesor cpu;

//2. Definovanie pointru typu
pocitac *p = &pc;

p->vypis();

//2. Priradenie pointru *p objektu typu processor - cpu
p = &cpu;

p->vypis();





Pri prvom zápise p->vypis(); je jasné, že sa zavolá funkcia vypis()*p definovaná v triede pocitac. Ale logicky je vidno, že v druhom zápise po priradení pointru *p objektu iného typu v našom prípade typu cpu, ktorý je premennou typu trieda – procesor by sa mala pri druhom zápise zavolať funkcia vypis deklarovaná v triede procesor. Avšak sa tak nestane. Je to spôsobené tým, že imlicitne sa používa tzv. statická väzba.

Statická väzba

Znamená, že program v tomto prípade nesleduje čomu je pointer priradení, je pre neho podstatná iba deklarácia základná, kde sme pointru *p priradili objekt typu pocitac a teda nemôže ukazovať na objekt iného typu.

Neskoršia väzba alebo dynamická väzba

Vyžaduje použitie pri deklarácii funkcie slovíčko virtual, teda podľa toho je pomenovanie virtuálne funkcie. Aj použitie by bolo trošku odlišné. Dynamická väzba existuje preto, že niekedy je potrebné viackrát prepínať medzi funkciami, ktoré konajú podobnú prácu a preto sa pre ne hodí rovnaké meno. Pomocou pointerov je to elegantné riešenie a existencia dynamickej väzby je rozšírením pre kvalitnejšie architektonické možnosti programov. Avšak statická väzba je preto implicitná, lebo je vhodnejšia z hľadiska nárokov. Príklad pre použitie dynamickej väzby s virtuálnymi funkciami:

Príklad
//na formulár si umiestnime komponentu Button – spúšťanie 
//a Edit - vstup

void __fastcall TForm1::Button1Click(TObject *Sender) {

int typ;

//1. Deklarácia pointeru typu pocitac/alebo
//processor nezáleží na tom

pocitac *p;

typ = Edit1->Text.ToInt();

//2. Použijeme prepínač, ktorý ošetrí situácie a
//podľa nich priradí pointeru deklaráciu.

switch(typ){

case 1:
p = new pocitac;
break;

case 2:
p = new procesor;
break;
}

//3. Teraz je už pointeru priradená deklarácia podľa
//našej voľby a program vie, ktorú z variantov funkcie
//vypis chceme použiť

p->vypis();
}


Stiahnuť zdrojové kódy : Statickú väzbu / Dynamickú väzbu.

Nabudúce začneme hovoriť o hlavičkových súboroch, ktoré nám C++ štandardne ponúka. Začneme hlavičkovým súborom math.h a jeho použitím.

Súvisiace články:

Prehľad všetkých dielov

Michal Kyžňanský
e-mail: kyznansky@

Neprehliadnite: