C++ nepřináší jen "velké" vlastnosti, jakými jsou podpora objektově orientovaného programování nebo šablony. Oproti C nabízí celou řadu drobných vylepšení a některá z nich si dnes probereme.
13.2.2006 09:00 | Jan Němec | czytane 21961×
RELATED ARTICLES
KOMENTARZE
Komentář
C++ umožňuje jednořádkový komentář uvozený //.
// Tohle je komentář ve stylu C++
/* Tohle je komentář ve stylu C */
Je ovšem pravda, že komentář uvozený // umožňuje i norma C z roku 1999 a často jej tolerují i starší
překladače C. C++ komentář je možné vložit do C komentáře, lze tedy psát například
/*
Tuhle funkci nepotřebujeme, ale zatím ji nebudeme mazat.
// Komentář k funkci
void funkce(void) {
// Komentář k implementaci
}
*/
Tradiční řešení ve stylu C je trochu neohrabané, neboť komentář /* */ nelze vkládat do sebe.
#if 0
Tuhle funkci nepotřebujeme, ale zatím ji nebudeme mazat.
/* Komentář k funkci */
void funkce(void) {
/* Komentář k implementaci */
}
#endif
Hlavičkové soubory
Hlavičkové soubory standardní knihovny jazyka C jsou v C++ dostupné buď původním způsobem tj. například
nebo pomocí předpony c a bez .h.
U souborů specifických pro standardní knihovnu C++ tuto volbu nemáme, inkludují se bez předpony i bez
přípony.
Inline funkce
Volání funkce na úrovni strojového kódu vyžaduje určitou režii spojenou s předáváním parametrů, adresy
volajícího kódu, návratové hodnoty i s provedením skoků na adresu volané funkce a zpět. V případě
velmi jednoduchých funkcí typu sečti dvě čísla je tato režie větší než doba strávená vykonáním těla
funkce. V C se považuje za standardní řešení makro, které se na textové úrovni rozvine v místě volání.
C++ nabízí navíc klíčové slovo inline, kterým doporučujeme překladači, aby na úrovni přeloženého
kódu funkci v místech volání rozvinul, podobně jako makro na úrovni kódu zdrojového. Funkce potom bude
součástí volajícího kódu, existovat tedy bude v tolika instancích, kolikrát je volána.
inline int plus(int x, int y) {
return x + y;
}
Je zřejmé, že přílišnou duplikací kódu (ať už pomocí inline funkcí,
maker nebo dokonce prostého kopírování na úrovni zdrojového kódu) můžeme
výsledný program naopak zpomalit. Z hlediska keše na úrovni procesoru je
výhodnější malé výkonné jádro programu a to může být důležitější než ušetření
režie při volání funkce.
Přístupnost globálních identifikátorů
V C++ je možné zpřístupnit překrytý globální identifikátor pomocí čtyřtečky.
#include <stdio.h>
const char *s = "globální řetězec";
int main(void) {
const char *s = "lokální řetězec";
printf("V C++ je přístupný %s i %s.\n", s, ::s);
return 0;
}
Při procedurálním programování ve stylu C v dobře navrženém programu podobné překrytí globálního
identifikátoru není příliš pravděpodobné, ale při použití objektově orientovaného programování
podobný konflikt hrozí častěji. Je zcela přirozené definovat třeba třídu Socket s metodou
listen, která přes čtyřtečku může zavolat překrytou knihovní funkci listen. Později si ukážeme, že
čtyřtečka v C++ zapadá do obecnější koncepce prostorů identifikátorů.
Ternární operátor
Ternární operátor ?: vrací v C++ l-hodnotu, pokud je jeho druhý i třetí parametr l-hodnota.
(polozka < 0 ? maDati : dal) += polozka;
V C tomu tak není, a tak je třeba rozepsat kód do čitelnější podoby s if a else.
if (polozka < 0) maDati += polozka; else dal += polozka;
Definice proměnných
V C++ je možné definovat lokální proměnnou kdekoli v bloku, nikoli jen na jeho začátku.
Běžně se toho využívá a proměnná se často definuje až v místě prvního použití.
Definice
ovšem nesmí být přeskočena pomocí break nebo goto, pokud zároveň nepřeskočíme celý blok, v němž je
proměnná definována.
void funkce1(void) {
int i;
i = 1;
// V C++ OK
int j;
}
void funkce2(void) {
// chyba, přeskočení definice
goto konec;
int j;
konec:;
}
void funkce3(void) {
// OK, přeskočení celého bloku
goto konec;
{
int j;
}
konec:;
}
Je zajímavé, že g++ bez problémů přeloží i test funkce2 (že by chyba?),
ale stačí místo typu int použít třeba std::string
(#include <string>) a překlad skončí takhle:
c.cpp: In function 'void funkce2()':
c.cpp:17: error: jump to label 'konec'
c.cpp:15: error: from here
c.cpp:16: error: crosses initialization of 'std::string j'
Proměnnou lze dokonce definovat i v řídících strukturách if, switch, for a while. V tom případě má
platnost pouze v následujícím bloku nebo příkazu.
for (int i = 0; i < 10; i++) {
printf("%i\n", i);
}
// Tady už i není definované
Známou chybou starší, ale dosud používané verze MS Visual C++ 6.0 je prodloužení platnosti proměnné,
jako kdyby byla definována těsně před řídící strukturou. Programátorům, kterým záleží na maximální
přenositelnosti kódu mezi různými překladači, bych proto doporučil podobné definice nepoužívat.
V gcc funguje vše správně.
Domácí úkoly
-
Vyzkoušejte, jak je to s platností proměnné definované v řídící struktuře v případě Vašeho překladače.
Napište korektní kód, který půjde přeložit pomocí g++, ale nikoli v MS Visual C++ 6.0 a nekorektní kód,
kde tomu bude právě naopak.
-
Definujte nějakou velmi jednoduchou funkci a volejte ji v cyklu. Změňte ji na inline a ověřte, zda
to má vliv na rychlost programu. Zkuste pomocí zpětného inženýrství zjistit, jestli se překladač vůbec řídil
vaším doporučením a jestli je funkce opravdu inline.
Pokračování příště
V příštím dílu se podíváme na reference a na volání funkcí s různými sadami parametrů.