P°ßtelskΘ nedorozum∞nφ nad kßvou

Nemohu se ubrßnit pocitu, ₧e se Java stala n∞Φφm jako nßbo₧enstvφm. Jestli₧e se o nφ nevyjßd°φte dostateΦn∞ uctiv∞, vrhnou se na vßs jejφ p°φznivci jako na kacφ°e. Nenφ to nic novΘho, podobn² osud potkal p°ed Φasem Pascal, C++, Forth a jinΘ jazyky. Jednφm z prvnφch z nich byl nepochybn∞ Fortran: Kdo by se nepamatoval na Φlßnek o skuteΦn²ch programßtorech, kte°φ pou₧φvajφ prßv∞ tento jazyk, a pojφdaΦφch kolßΦ∙, kte°φ pou₧φvajφ Pascal.

ProblΘm je, ₧e °ada argument∙ v podobn²ch diskusφch vychßzφ z neporozum∞nφ nebo z neznalosti Φehokoli jinΘho krom∞ zbo₧≥ovanΘho jazyka. Proto jsem velice rßd, ₧e se argumentace ve prosp∞ch Javy ujal pan ╚ada, kter² velmi dob°e znß nejen Javu a C++, o kterΘ nßm zde p∙jde, ale i °adu dalÜφch souvislostφ, a to jak po teoretickΘ, tak i po praktickΘ strßnce.

O co vlastn∞ jde

╚lßnky äJak jsem potkal Javuô a äCo mß Java proti C++ô vznikly na zßklad∞ poznßmek, kterΘ jsem si d∞lal, kdy₧ jsem se s tφmto jazykem seznamoval. Nekladl jsem si jin² cφl ne₧ poukßzat na mφsta, kterß mohou b²t pro cΘΦka°e z n∞jak²ch d∙vod∙ zajφmavß nebo nebezpeΦnß. Nic vφc a nic mΘn∞.

╚lßnek pana ╚ady se vyjad°uje k °ad∞ problΘm∙; jß se zde pokusφm na n∞kterΘ z nich odpov∞d∞t.

O p°et∞₧ovßnφ operßtor∙

Tvrzenφ, ₧e p°et∞₧ovßnφ operßtor∙ mß smysl jen pro matice a podobnΘ matematickΘ struktury a pro aritmetickΘ operßtory, vypadß na pohled p°esv∞dΦiv∞, skuteΦnost je ale slo₧it∞jÜφ. ProhlΘdneme-li si pozorn∞ standardnφ knihovnu jazyka C++, zjistφme ₧e tΘm∞° ka₧dou z t°φd v nφ provßzφ skupina p°etφ₧en²ch operßtor∙. N∞kterΘ z nich jsou metody, jinΘ obyΦejnΘ funkce. Uve∩me si alespo≥ n∞kolik p°φklad∙:

n     P°etφ₧en² operßtor indexovßnφ slou₧φ k p°φstupu k prvk∙m dvoustrannΘ fronty (deque) a asociativnφho pole (map).

n     P°etφ₧en² p°i°azovacφ operßtor umo₧≥uje p°enos vÜech prvk∙ z jednoho kontejneru do jinΘho.

n     P°etφ₧enΘ operßtory == a != slou₧φ pro porovnßvßnφ obsahu kontejner∙. (Nap°. dva seznamy jsou si rovny, jestli₧e obsahujφ stejnΘ prvky ve stejnΘm po°adφ.)

n     Dφky tomu, ₧e m∙₧eme p°et∞₧ovat operßtory ==, !=, ++, -- a * (dereferencovßnφ), lze v C++ snadno definovat iterßtory, tedy pomocnΘ datovΘ struktury, kterΘ umo₧≥ujφ zachßzet jednotn²m zp∙sobem s kontejnery obsahujφcφmi äposloupnostiô, tedy s poli, seznamy, frontami ap. Pak m∙₧eme snadno vytvo°it nap°. Üablonu funkce, kterß bude um∞t set°φdit jak äobyΦejnΘô cΘΦkovskΘ pole tak seznam nebo dvoustrannou frontu.

Za vylo₧enou lah∙dku pova₧uji pou₧itφ p°etφ₧en²ch operßtor∙ pro vstupnφ a v²stupnφ operace. Kdykoli mßm v Jav∞ napsat n∞co jako

System.out.println(a);  
System.out.println(b);

vzpomenu si na eleganci zßpisu

cout << a << endl << b << endl;

a tiÜe (nebo i nahlas) zanadßvßm.

Hlavnφ sφla operßtor∙ pro vstupy a v²stupy v C++ ale spoΦφvß v tom, ₧e si je mohu rozÜφ°it û p°etφ₧it û i na svΘ vlastnφ datovΘ typy a zachßzet s nimi zcela stejn∞ jako s typy vestav∞n²mi.

Samoz°ejm∞, operßtory lze p°et∞₧ovat i nesmysln²m zp∙sobem. Lze definovat operßtor *, kter² bude sΦφtat, lze definovat operßtor =, kter² bude p°enßÜet data zleva doprava atd.

OvÜem skuteΦnost, ₧e n∞co lze zneu₧φt nebo pou₧φt nesprßvn²m zp∙sobem, jeÜt∞ p°ece nenφ d∙vod k zßkazu. Logika älze to zneu₧φt, tedy se to zneu₧φvß, a proto to zakß₧emeô, mi p°ipomφnß logiku zßkona, kter² zakazoval vypalovat soukrom∞ alkohol a za provinilΘho pova₧oval ka₧dΘho, kdo m∞l destilaΦnφ p°φstroj nebo jeho äpodstatnou Φßstô. To bychom toti₧ museli zakßzat i metody: Kdo nßm zabrßnφ definovat metodu Plus(), kterß bude d∞lit? Dovedeme-li tuto logiku do absurdity, m∞li bychom zakßzat programovßnφ jako celek, nebo¥ jen tak lze zabrßnit psanφ poΦφtaΦov²ch vir∙, trojsk²ch ko≥∙ a jin²ch lah∙dek.

Virtußlnφ a nevirtußlnφ metody

Dovolφm si oponovat nßzoru, ₧e nevirtußlnφ metody jsou n∞co p°φÜernΘho a₧ zr∙dnΘho. Je to jen dalÜφ vyjad°ovacφ prost°edek, kter² C++ programßtorovi nabφzφ, a lze jej velice elegantn∞ vyu₧φt. Ne₧ se ale pustφme do ·vah na toto tΘma, °ekn∞me si n∞kolik slov o polymorfismu jako takovΘm.

Za tφmto oznaΦenφm se skr²vß jedno z pravidel objektovΘho programovßnφ, kterΘ °φkß, ₧e na mφst∞, kde oΦekßvßme instanci p°edka (bßzovΘ t°φdy), lze pou₧φt instanci potomka (odvozenΘ t°φdy), nebo¥ odvozenß t°φda by m∞la p°edstavovat zvlßÜtnφ p°φpad (specializaci) bßzovΘ t°φdy. To znamenß, ₧e p°i pou₧itφ objektu ve skuteΦnosti nemusφme znßt jeho t°φdu; prost∞ mu poÜleme zprßvu (zavolßme jeho metodu) a on zareaguje sprßvn²m zp∙sobem. P°edstavme si nap°., ₧e pracujeme s grafick²mi objekty, kterΘ jsou instancemi t°φd odvozen²ch od spoleΦnΘho p°edka û t°φdy GrafickyObjekt. Mßme jich pln² zßsobnφk a chceme je vÜechny nakreslit. PoÜleme jim tedy vÜem po °ad∞ zprßvu änakresli seô, tj. zavolßme odpovφdajφcφ metodu, a oΦekßvßme, ₧e objekt, kter² p°edstavuje Φtverec, se nakreslφ jako Φtverec, zatφmco objekt, kter² p°edstavuje kruh, se opravdu nakreslφ jako kruh, ani₧ se o to musφme zvlßÜ¥ starat.

Syntakticky bude odpovφdajφcφ p°φkaz v Jav∞ i v C++ poka₧dΘ stejn², bude to volßnφ metody se stejn²m identifikßtorem (nap°. Nakresli()) a se stejn²mi parametry. Je v∞cφ programu, aby se postaral o volßnφ sprßvn²ch metod odpovφdajφcφch skuteΦnΘmu typu instance. Technick² prost°edek, kter²m se toho dosahuje, se oznaΦuje jako äpozdnφ vazbaô.

Tolik na ·vod, ze kterΘho by m∞lo b²t jasnΘ, ₧e polymorfismus mß smysl pouze v p°φpad∞, ₧e je ve h°e d∞diΦnost. V Jav∞ tvo°φ vÜechny t°φdy jedinou d∞dickou hierarchii, proto je tak trochu logickΘ, ₧e vÜechny metody vyu₧φvajφ pozdnφ vazbu.

Na druhΘ stran∞ v C++ mohou existovat zcela samostatnΘ t°φdy, tedy t°φdy, kterΘ nele₧φ v ₧ßdnΘ d∞dickΘ hierarchii. Typick²m p°φkladem m∙₧e b²t knihovnφ t°φda complex<T> reprezentujφcφ komplexnφ Φφsla vytvo°enß z dvojice Φφsel typu T. ProΦ by takovß t°φda m∞la obsahovat n∞jakΘ spoleΦnΘ vlastnosti vÜech objekt∙?

Proto₧e tato t°φda nenφ potomkem ₧ßdnΘ t°φdy a proto₧e nep°edpoklßdßme, ₧e by se mohla stßt p°edkem n∞jakΘ t°φdy, nenφ nejmenÜφ d∙vod pou₧φvat pro jejφ metody pozdnφ vazbu û tedy deklarovat je jako virtußlnφ.

NicmΘn∞ i v polymorfnφch t°φdßch mohou mφt nevirtußlnφ metody svΘ opodstatn∞nφ. Ostatn∞ neuÜkodφ, podφvßme-li se na mo₧nosti, kterΘ nßm v souvislosti s virtußlnφmi a nevirtußlnφmi metodami C++ nabφzφ a jak² majφ v²znam.

Definujeme-li v p°edkovi:

n     Φist∞ virtußlnφ metodu bez implementace (v Jav∞ a obΦas i v C++ se naz²vß äabstraktnφô), definujeme tφm jejφ rozhranφ a p°ikazujeme potomk∙m, ₧e musφ definovat jejφ implementaci;

n     Φist∞ virtußlnφ metodu s implementacφ (to je konstrukce, kterß v Jav∞ nemß analogii), definujeme tφm jejφ rozhranφ a nabφzφme potomk∙m implicitnφ implementaci, kterou ale nelze volat pomocφ pozdnφ vazby û potomek ji musφ zavolat s plnou kvalifikacφ;

n     virtußlnφ metodu (äobyΦejnouô), definujeme tφm jejφ rozhranφ a implementaci, kterou mohou potomci zm∞nit, je-li to pot°ebnΘ;

n     nevirtußlnφ metodu, definujeme tφm jejφ rozhranφ a implementaci, kterß je pro potomky zßvaznß.

K poslednφmu bodu je t°eba poznamenat, ₧e nejde o zßvaznost syntaktickou (jako je klφΦovΘ slovo final v Jav∞), nebo¥ p°ekladaΦ se nevzbou°φ, jestli₧e nevirtußlnφ metodu v potomkovi p°edefinujeme. Existujφ i situace, kdy to mß smysl, v∞tÜinou tφm ale zp∙sobφme chybu û program se bude chovat jinak, ne₧ jsme si p°ßli.

Vφcenßsobnß d∞diΦnost a rozhranφ

Vφcenßsobnß d∞diΦnost se v C++ opravdu pou₧φvß p°edevÜφm k implementaci rozhranφ. Lze pro ni nalΘzt i jinß pou₧itφ, nebo¥ p°edstavuje zajφmavou alternativu ke sklßdßnφ objekt∙ û nap°φklad standardnφ vstupn∞-v²stupnφ proud iostream je spoleΦn²m potomkem t°φd istream a ostream, kterΘ p°edstavujφ samostatn² vstupnφ, resp. samostatn² v²stupnφ proud. To ale nenφ p°φliÜ podstatnΘ; podφvejme se na p°φklad, na kterΘm pan ╚ada p°edvßdφ, k jak²m problΘm∙m m∙₧e vφcenßsobnß d∞diΦnost vΘst. Pro pohodlφ Φtenß°e û ale i svΘ û ho zde zopakuji. Nejprve definujeme abstraktnφ t°φdu Interface, kterß nahrazuje javskΘ rozhranφ:

class Interface {public:  
   virtual void metoda()=0;  
};

Pak definujeme t°φdu Object, kterß by m∞la slou₧it jako spoleΦn² p°edek vÜech t°φd v naÜem programu:

class Object { public:  
  virtual void xxx() {  
     printf("Metoda vsech objektu...\n");  
  }
};

Nakonec definujeme t°φdu Xxx, kterß implementuje rozhranφ Interface a kterß je potomkem t°φdy Object:

class Xxx:  
public Object, public Interface {  
 public:
  virtual void metoda() {  
    printf("metoda tridy Xxx\n");  
  };
};

Nakonec se podφvßme na funkci use(), kterß  pracuje s rozhranφm Interface a kterß p∙sobφ problΘmy:

void use(Interface* o)  
{ // P∙vodnφ implementace p. ╚ady  
 ((Object*)o)->xxx(); // !  
 o->metoda();
}

P°edßme-li tΘto funkci jako parametr ukazatel na instanci t°φdy Xxx, zavolß se v p°φkazu, oznaΦenΘm vyk°iΦnφkem, metoda metoda(), nikoli metoda xxx(). To je velice nep°φjemnß chyba, jejφ₧ hledßnφ v programu m∙₧e trvat velmi dlouho.

Co se vlastn∞ stalo?

P°etypovßnφ (Object*)o p°ekladaΦi vlastn∞ °φkß: äZde mßÜ ukazatel o na t°φdu Interface; bu∩ tak laskav a zachßzej s nφm jako s ukazatelem na t°φdu Object.ô Tyto dv∞ t°φdy spolu nijak nesouvisφ a v dob∞ p°ekladu nelze obecn∞ zjistit, zda o nßhodou nebude za b∞hu obsahovat ukazatel na instanci odvozenΘ t°φdy, kter² je zßrove≥ potomkem t°φdy Object.  Uveden² postup tedy p°edstavuje jedinou alespo≥ trochu rozumnou interpretaci po₧adovanΘho p°etypovßnφ.

V²sledkem je, ₧e volßnφ metody xxx()p°ekladaΦ p°elo₧φ jako volßnφ prvnφ virtußlnφ metody t°φdy Object, tj. metody metoda().

My jsme si ale p°ßli n∞co jinΘho: Cht∞li jsme zachßzet s ukazatelem na rozhranφ jako s ukazatelem na instanci n∞jakΘ t°φdy, kterß je potomkem t°φdy Object, a zavolat jejφ zd∞d∞nou metodu xxx(). To samoz°ejm∞ jde, musφme ale zapomenout na analogii s Javou a °φci si o to tak, jak se sluÜφ a pat°φ v C++.

P°edevÜφm bychom m∞li se m∞li rozlouΦit s p°etypovacφm operßtorem (typ), p°evzat²m z jazyka C. Jeho ·koly û a n∞co navφc û si mezi sebe rozd∞lily operßtory dynamic_cast, static_cast, const_cast a reinterpret_cast. Proto₧e nßm jde o p°etypovßnφ mezi ukazateli na polymorfnφ t°φdy v rßmci jednΘ d∞dickΘ hierarchie, pou₧ijeme operßtor dynamic_cast:

Object *uo = dynamic_cast<Object*>(o);  
if(uo) uo ->xxx();            // OK

Nynφ ji₧ program bude fungovat bez problΘm∙.

Poznamenejme, ₧e zatφmco operßtor (typ) se v C++ vyhodnocuje u₧ v dob∞ p°ekladu, operßtor dynamic_cast se volß za b∞hu programu. Tento operßtor nejprve zjistφ, zda mß po₧adovanΘ p°etypovßnφ smysl, a pokud ano, provede jej. Pokud ne, vrßtφ 0. Proto jsme vrßcenou hodnotu ulo₧ili do pomocnΘ prom∞nnΘ a p°ed pou₧itφm testovali jejφ hodnotu.

Pou₧itφm operßtoru dynamic_cast lze vy°eÜit i dalÜφ problΘmy v p°φkladech, kterΘ pan ╚ada uvßdφ ve svΘm, Φlßnku a kterΘ obsahujφ p°etypovßnφ ukazatel∙ na objekt.

Existujφ v C++ t°φdy?

To je otßzka, na kterou nenφ v∙bec snadnΘ odpov∞d∞t û zßle₧φ na tom, co si pod tφm p°edstavujeme. Polo₧me si n∞kolik otßzek, kterΘ by nßm mohly pomoci najφt odpov∞∩.

n     M∙₧eme za b∞hu programu poslat t°φd∞ zprßvu? û M∙₧eme; v C++ existujφ metody t°φd, naz²vanΘ podobn∞ jako v Jav∞ ästatickΘô.

n     Mß t°φda svou datovou reprezentaci v programu? û M∙₧e ji mφt. Sklßdß z datov²ch slo₧ek t°φdy (ästatick²chô dat) a pop°φpad∞ z tabulky virtußlnφch metod a informacφ nezbytn²ch pro dynamickΘ urΦovßnφ typu za b∞hu programu (ovÜem pokud mß naÜe t°φda alespo≥ jednu virtußlnφ metodu).

n     Chovß se instance objektovΘho typu v C++ jako äΦernß sk°φ≥kaô, kterß p°ijφmß zprßvy a reaguje na n∞? û Odpov∞∩ znφ ano, pokud samoz°ejm∞ s instancφ zachßzφme korektn∞. Nap°φklad nekorektnφ p°etypovßnφ m∙₧e zp∙sobit problΘmy, ale o tom hovo°φm v oddφlu äVφcenßsobnß d∞diΦnost a rozhranφô.

n     M∙₧e program vytvo°it instanci t°φdy, kterß nebyla v dob∞ psanφ programu znßma, kterou naprogramoval n∞kdo jin², kterou a kterou umφstil nap°. do dynamickΘ knihovny? û M∙₧e, ale nenφ to zdaleka tak jednoduchΘ jako v Jav∞ nebo v jin²ch Φist∞ objektov²ch jazycφch. Musφ b²t spln∞ny jistΘ dodateΦnΘ a ΦßsteΦn∞ omezujφcφ p°edpoklady, nap°. ₧e p∙jde o t°φdu odvozenou od pevn∞ danΘho p°edka, ₧e odpovφdajφcφ dynamickß knihovna bude obsahovat urΦitΘ pomocnΘ funkce atd.

n     StaΦφ t°i obvykle uvßd∞nΘ principy objektovΘho programovßnφ û zapouzd°enφ, d∞diΦnost, polymlorfizmus û k tomu, abychom uznali, ₧e jazyk podporuje objektovΘ programovßnφ? û Na tuto otßzku nech¥ si odpovφ Φtenß° sßm.

V zßjmu objektivity je ale nutno dodat, ₧e nepolymorfnφ t°φdy v C++, tedy t°φdy, kterΘ neobsahujφ ₧ßdnΘ virtußlnφ metody, se opravdu podobajφ spφÜe strukturßm s metodami ne₧ objekt∙m û nefunguje pro n∞ mj. dynamickß identifikace typ∙ (RTTI). Lze si ovÜem jen t∞₧ko p°edstavit, ₧e se v jakΘkoli rozumnΘ d∞dickΘ hierarchii vyskytujφ nepolymorfnφ t°φdy.

Super

Hlavnφ ·Φel klφΦovΘho slova super opravdu nenφ potlaΦenφ pozdnφ vazby, jak snad z mΘ poznßmky v Φlßnku äJak jsem potkal Javuô mohlo vypl²vat. Jak znßmo, toto super zp°φstup≥uje slo₧ky p°edka, nadt°φdy.

Mimochodem, p°φklad, na kterΘm pan ╚ada pou₧itφ super ukazuje, nenφ prßv∞ nejÜ¥astn∞jÜφ. I kdy₧ technicky lze t°φdu komplexnφch Φφsel zavΘst jako potomka t°φdy reßln²ch Φφsel, logicky to nenφ nejlepÜφ, nebo¥ v matematice je jejich vztah p°esn∞ opaΦn² û reßlnß Φφsla jsou zvlßÜtnφm p°φpadem komplexnφch Φφsel (s nulovou imaginßrnφ Φßstφ). Kdybychom opravdu n∞kde pou₧ili komplexnφ Φφsla odvozenß od reßln²ch Φφsel, znamenalo by to, ₧e

n     v mφstech, kde se oΦekßvß pouze reßlnΘ Φφslo, nßm program dovolφ pou₧φt i jakΘkoli komplexnφ Φφslo,

n     v mφstech, kde se oΦekßvß komplexnφ Φφslo, nßm program nedovolφ pou₧φt Φφslo reßlnΘ.

Obojφ je nesmyslnΘ, ovÜem hlavnφho tΘmatu diskuze, v²znamu klφΦovΘho slova super, se to v podstat∞ net²kß.

Vra¥me se tedy ke klφΦovΘmu slovu super a k polymorfismu. Java obecn∞ neumo₧≥uje potlaΦit pozdnφ vazbu, tj. p°edepsat, ₧e chceme volat zd∞d∞nou metodu, nikoli metodu implementovanou v potomkovi. Jedinou situaci, kterou takto lze oznaΦit, ukazuje nßsledujφcφ p°φklad:

class Predek {  
  void f(){/* ... */}  
}

class Potomek extends Predek {  
  void f(){/* ... */}  
  void g(){super.f();}
}

Kdybychom v metod∞ g() potomka nepou₧ili klφΦovΘ slovo super, volala by se metoda f() t°φdy Potomek. Takto zavolßme metodu p°edka, tedy vy°adφme (alespo≥ ΦßsteΦn∞) pozdnφ vazbu. Tento trik ovÜem umo₧≥uje pouze vyu₧φt metodu p°edka k implementaci metody potomka, neumo₧≥uje programov∞ zavolat metodu p°edka pro instanci potomka. Neumo₧≥uje takΘ volat metodu ze vzdßlen∞jÜφho p°edka.

Reference a garbage collector

Automatickß sprßva pam∞ti, garbage collector, je velice pohodlnΘ za°φzenφ. Kdy₧ si na n∞j zvyknete, nebude se vßm chtφt vracet se k systΘm∙m, kterΘ ho neobsahujφ. NicmΘn∞ v C++ jej lze pom∞rn∞ snadno nahradit.

V b∞₧n²ch p°φpadech staΦφ zapouzd°it ukazatel na dynamicky alokovan² objekt do automatickΘho ukazatele, instance pomocnΘho objektovΘho typu, jeho₧ destruktor se postarß o uvoln∞nφ pam∞ti objektu. Takov² automatick² ukazatel si m∙₧eme snadno naprogramovat sami; standardnφ knihovna jazyka C++ ale obsahuje Üablonu t°φdy auto_ptr<T>, kterß implementuje ukazatel na typ T. Tento automatick² ukazatel obsahuje i p°φznak vlastnictvφ a o uvoln∞nφ pam∞ti se pokusφ pouze ukazatel, kter² objekt ävlastnφô.

Ve slo₧it∞jÜφch p°φpadech se pro dynamicky alokovanΘ objekty pou₧φvß tzv. poΦφtßnφ referencφ. Objekt se v tom p°φpad∞ starß o svΘm uvoln∞nφ z pam∞ti sßm û obsahuje celoΦφselnou prom∞nnou, ve kterΘ si poΦφtß, kolik ukazatel∙ na n∞j existuje, a v p°φpad∞, ₧e tento poΦet klesne na nulu, spßchß sebevra₧du nap°. p°φkazem

delete this;

Je jasnΘ, ₧e jde o zp∙sob pom∞rn∞ nepohodln² a nßchyln² k chybßm, na druhΘ stran∞ ale o zp∙sob velice efektivnφ.

FunkΦnφ parametry

V Φlßnku äJak jsem potkal Javuô jsem jako zp∙sob p°edßvßnφ funkΦnφho parametru p°edvedl automaticky generovan² k≤d z JBuilderu, ve kterΘm se p°edßvanß metoda s dan²m prototypem äzabalφô do anonymnφ t°φdy. To je zcela standardnφ javskß konstrukce, nejde o ₧ßdnΘ rozÜφ°enφ.

Souhlasφm s tφm, ₧e zp∙sob, kter² pan ╚ada ukazuje, je na prvnφ pohled elegantn∞jÜφ. NicmΘn∞ zp∙sob, kter² se pou₧φvß v JBuilderu, umo₧≥uje, aby handler, podprogram, kter² se starß o odezvu na n∞jakou udßlost, byl metodou okna nebo obecn∞ objektu, kter² p°edstavuje souΦßst grafickΘho rozhranφ, ve kterΘm je komponenta umφst∞na. To umo₧≥uje mj. sdφlenφ handler∙ û n∞kolik komponent m∙₧e p°i r∙zn²ch udßlostech volat t²₧ handler. (M∙₧eme nap°. po₧adovat, aby se p°i dvojkliku myÜφ na vstupnφ °ßdku stalo totΘ₧ jako p°i stisknutφ tlaΦφtka vedle tΘto °ßdky.) Nepsat stejn² k≤d vφcekrßt, to je p°ece starß programßtorskß zßsada.

P°ekladaΦ a programßtor

Jednφm ze zßkladnφch rys∙ jazyka C++ je, ₧e jeho p°ekladaΦ poklßdß programßtora za myslφcφho, samostatnΘho a svΘprßvnΘho Φlov∞ka, kter² vφ, co chce. Proto se mu sna₧φ vyhov∞t, nehledß d∙vod, proΦ jeho program oznaΦit za chybn², a dovoluje mu °adu äpotencißln∞ nebezpeΦn²chô operacφ, jako je p°φmΘ zachßzenφ s ukazateli, p°etypovßnφ ukazatele na jednu t°φdu na ukazatel na jinou t°φdu, p°edefinovßnφ nevirtußlnφch metod v odvozenΘ t°φd∞ apod. V tomto p°φstupu k programßtorovi se C++ v²razn∞ odliÜuje nejen od Javy, ale i od Pascalu, Ady a °ady jin²ch programovacφch jazyk∙. Proto takΘ v p°φpad∞ mnoha potencißln∞ nebezpeΦn²ch konstrukcφ p°ekladaΦ hlßsφ pouze varovßnφ nebo ani to ne û spolΘhß na kßze≥ a znalosti programßtora.

Java zdaleka tak liberßlnφ nenφ, i kdy₧ ji v ₧ßdnΘm p°φpad∞ nelze oznaΦit za vylo₧en∞ restriktivnφ. To nenφ odsudek, to je prostΘ konstatovßnφ skuteΦnosti.

Podle m²ch zkuÜenostφ jsou mezi programßtory dv∞ v²raznΘ skupiny. Jedna z nich dßvß p°ednost jazyk∙m, kterΘ poskytujφ volnost v²razov²ch prost°edk∙ a mo₧nost zvolit si vlastnφ osobit² styl, a to i za cenu, ₧e mohou ud∞lat chybu. K tomu jsou ochotni dodr₧ovat jistou vlastnφ disciplφnu, kterß je p°i prßci s takov²m nßstrojem nezbytnß.

Druhß skupina preferuje spφÜe jazyky, kterΘ programßtora vedou, nutφ ho pracovat urΦit²m p°edem dan²m stylem, ale na druhΘ stran∞ umo₧≥ujφ snßze navrhovat strukturu programu a zamezujφ n∞kter²m druh∙m chyb.

Obojφ mß svΘ v²hody a nev²hody a p°φsluÜnost ke kterΘkoli z t∞chto skupin podle m²ch zkuÜenostφ naprosto nevypovφdß o kvalit∞ programßtora. Mo₧nß, ₧e souvisφ s jeho postojem ke sv∞tu, ale obßvßm se, ₧e to je spφÜe filozofick² problΘm.

Myslet ve svΘm jazyku

K tomu, abychom mohli ·sp∞Ün∞ programovat v n∞jakΘm jazyku û a nemusφ to b²t jen C++ nebo Java û nestaΦφ znßt klφΦovß slova a zßkladnφ knihovnφ funkce nebo t°φdy. Ka₧d² jazyk mß svou vnit°nφ logiku, a tu je p°i nßvrhu programu t°eba brßt v ·vahu. Jinak se dostaneme do situace, budeme d∞lat z Javy C++, z C++ Pascal a podobn∞ û a budeme nßramn∞ p°ekvapeni, ₧e se v naÜem programu objevujφ äzßhadnΘô a änesmyslnΘô chyby.

Miroslav Virius (virius@km1.fjfi.cvut.cz)