EAF I C++ nyelvi elemek felsorolása 1 Alapvet típusok int egész ill természetes számok (83, -1320) m veletek: + - * / % ==!= < <= > >= megjegyzés: az osztás eredménye egész float valós számok (-1320.345) m veletek: + - * / ==!= < <= > >= megjegyzés: az osztás eredménye valós bool logikai értékek (false, true) m veletek: &&! ==!= char karakterek ( a 3 \ ) m veletek: ==!= string karakterláncok ( valami ) m veletek: size(length) + [] c_str() substr() ==!= string str esetén (std névtér és #include <string>) str.size() az str hossza (karaktreinek száma) str[i] az str i-edik karaktere str + vége két karakterlánc összef zése str.c_str() str átalakítása C stílusú lánccá str.substr(i,j) str részének kivágása megjegyzés: Karakterlánc számmá konvertálása atoi(str.c_str()) Karakterlánc-konstans sortörése: Ez itt egy nagyon hosszú \ másik sorba is átnyúló szöveg
EAF I C++ nyelvi elemek felsorolása 2 Elemi programok Értékadás változó := kifejezés értékadást változó = kifejezés; alakban írjuk. Szimultán értékadások A szimultán értékadásokat közönséges értékadások szekvenciájaként (lásd szekvencia) lehet leírni. Ezeket a közönséges értékadásokat írjuk egy sorba! Értékadás értéke A C++ nyelv értékadásainak értéke is van, mégpedig az értékül adott kifejezés értéke. Más sóval egy értékadás egyszerre utasítás is, és kifejezés is. Ezért lehet például olyan értékadásokat is írni, mint változó1 = változó2 = kifejezés; amely mindkét változónak a kifejezés értékét adja. Olyan szimultán értékadások kódolásánál használjuk, ahol minden változó ugyanazt az értéket kapja meg. Gyakori hiba, hogy a programozó változó == kifejezés egyenl ség-vizsgálat helyett változó = kifejezés formát használ. Sajnos mivel az értékadásnak is van értéke, és egy tetsz leges érték könnyen konvertálódik logikai értékké ezt a fordító program nem jelzi hibaként, és az eredmény nem a várt egyenl ség-vizsgálat eredménye lesz, ráadásul a változó is elveszíti az értékét. Gondoljunk például arra, hogy el akarjuk dönteni, hogy egy i változó egyenl -e 1-gyel, de az i==1 kifejezés helyett rosszul az i = 1 értékadást használjuk. Ennek az értékadásnak az értéke 1, amit a C++ true logikai értéknek tekint. A vizsgált logikai kifejezés mindig igaz lesz, az i változó új értéket kap, és a fordító nem jelez hibát. Speciális értékadások ++i, i++ i = i+1 --i, i-- i = i-1 Vigyázat! Kifejezésként használva az i++ az i kezdeti értékét a ++i az i megnövelt érétkét képviseli. Program leállítása 1-es hibakóddal exit(1); Megjegyzések kódba illesztése Egy soros megjegyzés esetén Több soros megjegyzés esetén /* utasitás // megjegyzés megjegyzés */
EAF I C++ nyelvi elemek felsorolása 3 Programszerkezetek Szekvencia Az utasítások (utasításblokkok) egymás utáni elhelyezésével fejezhet utasításokat pontosvessz (;) zárja le, az utasításblokkokat kapcsos zárójel (). ki. Az Elágazás Közönséges elágazás if(feltétel) ág_1 else ág_2 Egyszer bb esetben if(feltétel) else ut_1; ut_2; A ki nem írt else ág üres utasítású ágat jelent: if(feltétel)ut_1; Sok ágú elágazás A sokágú elágazást egymásba ágyazott if-else elágazásokkal kódolhatjuk. Tudni kell azonban, hogy így az absztrakt elágazással ellentétben, amelyik nem-determinisztikus és ha egyik feltétel sem teljesül, akkor abortál ez egy determinisztikus és ha egyik feltétel sem teljesül, akkor üres programként m köd kódot kapunk. Ez azonban nem baj, mert ha az absztrakt elágazás helyes volt, akkor annak valamelyik feltétele biztos teljesül, és bármelyik determinisztikus változat is helyes. Megjegyezzük még, hogy amennyiben az elágazás feltételei teljes és páronként diszjunkt rendszert alkotnak, akkor a kód teljesen azonos az absztrakt változattal. A kódban használhatunk sok ág után egy külön else ágat is, amely az absztrakt változathoz képest egy extra lehet séget biztosít. if(feltétel_1) ág_1 else if(feltétel_2) ág_2 else if(feltétel_3) else ág_n+1
EAF I C++ nyelvi elemek felsorolása 4 Speciális sokágú elágazás Ciklus switch (kifejezés) case konstans1 : utasítássorozat1 ; break; case konstans2 : utasítássorozat2 ; break; case konstans3 : case konstans4 : utasítássorozat34 ; break; default : utasítássorozat5 ; while(feltétel) mag Ciklust tartalmazó nevezetes összetett utasítások A for utasítás a program_1; while(feltétel) mag; program_2; kód egyszer bb írására használható. Formája: for(program_1;feltétel;program_2) mag Általában az úgynevezett számlálós ciklusokhoz, illetve az iteratív szerkezet adatok feldolgozásához használjuk. for(i=0;i<n;i++) mag az i az úgynevezett ciklus számláló. Ha a ciklusmag egyetlen utasításból áll, akkor használható az alábbi forma: for(i=0;i<n;i++) utasítás; A do-while utasítás a mag; while ( feltétel ) mag kód egyszer bb írására használható. Formája: do mag while ( feltétel ) Egyrészt adatbevitel ellen rzésénél használjuk do adatbevitel if(kritérium) üzenet while ( kritérium ) Másrészt amikor a programot alkalmassá tesszük arra, hogy tetsz leges sokszor futtathassuk: do program cout << Folytatja? (I/N) ; char ch; cin >> ch; while (ch!= N && ch!= n );
EAF I C++ nyelvi elemek felsorolása 5 Szabványos be- és kimenet #include <iostream> cin >> változó1 >> változó2; cout << kifejezés1 << kifejezés2; cout << endl; Karakterláncok beolvasása Az üres karakterláncot nem tudunk a >> operátorral beolvasni. Ilyenkor a beolvasásnak másik formáját kell használni: getline(cin,str); Ügyeljünk azonban arra, hogy ha vegyesen használjuk a két olvasási módot, akkor a getline alkalmazása el tt ürítsük ki a billenty zet puffert, mert abban benn maradhatnak a korábbi beolvasásból maradt elválasztó karakterek, els sorban a sorvége karakter. A kiürítés történhet egy külön getline(cin,str) utasítással. Szerkesztett formátumú beolvasás, kiírás A formátumjelz flageket a cin.setf(), cout.setf(), cin.unsetf(), cout.sunetf() függvények paramétereként kell felsorolni. A setf() beállítja, az unsetf() kikapcsolja ket, a kett között érvényben vannak. Némelyikük alapértelmezett módon be van kapcsolva. A flageket a jellel elválasztva. Minden flag elé az ios:: min sítést kell írni. A manipulátorok csak az adott adat mozgatásra vonatkoznak. ket a << operátorral kell a standard kimenetre küldeni. Manipulátorok setw(int w), width(int w) setprecision(int p), precision(int p) setfill(char c) endl Formátumjelz flagek scientific, fixed, right, left, dec, hex, oct, showpoint, showpos skipws : mez szélesség számábrázolás pontossága.. kitölt karakter sorvége lebeg pontos. fixpontos. tömörítés. számrendszer tizedespont, el jel látszódjon-e elválasztó jelek átlépése..
EAF I C++ nyelvi elemek felsorolása 6 Struktúra A rekord típusnak megfeleltetett szerkezet: struct Nev tipus1 mezo1; tipus2 mezo2; ; Nev d; A d.mezo1 kifejezés (a mezo1 a szelektor függvény) állhat értékadás jobb- illetve baloldalán. Az egyik esetben felhasználjuk d.mezo1 kifejezés által képviselt értéket, a másik esetben megváltoztathatjuk azt. Statikus és dinamikusan lefoglalt tömbök Statikus egydimenziós tömb (vektor): int t[100]; int n; cin >> n; for(int i=0;i<n;i++) cin >> t[i]; // statikusan lefoglalt tömb // tényleges hosszúság // n értékének megadása // t feltöltése Dinamikusan lefoglalt egydimenziós tömb (vektor): int* t; int n; cin >> n; t = new int[n]; for(int i=0;i<n;i++) cin >> t[i]; delete[] t; // véges hosszú tömb neve // tényleges hosszúság // n értékének megadása // tomb lefoglalása futás közben // t feltöltése // t felszabadítása Statikus kétdimenziós tömb (mátrix): Elem t[10][20]; //statikusan lefoglalt mátrix int n,m; // tényleges méret cin >> n >> m; // n,m értékének megadása for (int i=0;i<n;i++) // t feltöltése for (int j=0;j<m;j++) cin>>t[i][j];
EAF I C++ nyelvi elemek felsorolása 7 Dinamikusan lefoglalt kétdimenziós tömb (mátrix): Elem** t; // véges méret mátrix int n,m; // tényleges méret cin >> n >> m; // n,m értékének megadása t=new Elem*[n]; for (int i=0;i<n;i++) // t feltöltése t[i]=new Elem[m]; for (int j=0;j<m;j++) cin>>t[i][j]; for (int i=0;i<n;i++) delete[] t[i]; delete[] t; // t felszabadítása Fügvények és paraméterátadás A függvény egy olyan programkód-részlet, amelyet akkor hajthatunk végre, ha a programunk egy adott pontján (amely a függvény láthatósági körén belül van) a függvény nevére történ hivatkozással meghívjuk azt. Ilyenkor a program végrehajtása addig felfüggeszt dik, amíg a függvényhez tartozó kód le nem fut. Deklaráció Egy függvényt az alábbi formájú kódrészlet deklarál. tipus fuggvenynev(tipus1 p1, tipus2 p2, ); Egy függvényt a típusa, a neve és a paraméterváltozóinak típusai együttesen határozzák meg, ezért lehet például több eltér funkciójú, de ugyanolyan nev függvényt definiálni. A függvény típusa és a paraméterváltozóinak típusai írják le, hogy a típus hogyan kommunikál az t hívó programmal, azaz hogyan kap attól kezd értéket illetve hogyan tud visszaadni eredményt. (A teljes igazsághoz hozzátartozik, hogy a különböz programrészek úgynevezett globális változókon keresztül is kommunikálhatnak, de ennek a lehet ségnek a kihasználása sok veszélyt rejt magában, ezért mi nem használjuk.) Egy paraméterváltozó akkor kimen jelleg (a benne keletkezett érték a hívó programban lekérdezhet ), ha a típusának neve el tt nem szerepel a const szó, és a típusa vagy egy típusszerkezetre utal (tömb, struktúra), vagy a típusnév után egy & jel áll (hivatkozás szerinti paraméter). Az ilyen paraméterváltozók képesek adat bevitelre is, és visszaadásra is. Minden más esetben a paraméterváltozó kizárólag bemen jelleg (a hívó programban adható meg számára kezd érték). Tehát akkor is, ha egy típusnév áll a változó el tt & jel nélkül, és akkor is, ha a const szó megel zi a típusnevet (amit ilyenkor akár még & jel is követhet). Az olyan bemen paraméter esetén, amelynek lehetséges értékei nagy memória helyet (?) foglalnak, ajánlott a const szó és az & jel együttes használata (pl. string). Az eredmény visszaadására van a fentieken kívül még egy lehet ség. Maga a függvény képes egy kiszámolt értéket (kimen adatot) úgynevezett visszatérési értékként el állítani ennek az értéknek a típusát adja meg a függvény deklarációjában a függvény neve elé írt típus. Erre az értékre a függvény meghívásakor a függvény nevének megfelel formába (lásd függvény hívása) felírt kifejezésével tudunk hivatkozni. Speciális esetben lehet egy függvény típusa void, ami azt jelöli, hogy a függvénynek nincs visszatér értéke, kizárólag a paraméterein keresztül tudunk kommunikálni vele.
EAF I C++ nyelvi elemek felsorolása 8 Tömbök, mint függvény paraméterek void fv(elem t[][20], int &n, int &m) t[i][j] void fv(elem** &t, int &n, int &m) t[i][j] Definíció Egy függvény definíciójának formája az alábbi: tipus fuggvenynev(tipus1 p1, tipus2 p2, ) A kapcsos zárójelek között kell elhelyezni azt a kódot (függvény törzs), amelynek végrehajtását képviseli majd a függvény. Ez a kód ugyanúgy használhatja a paraméterváltozókat, mint a kódban definiált egyéb változókat azzal a megkötéssel, hogy számolhat a paraméterváltozók kívülr l megadott kezd értékével, továbbá ha egy paraméterváltozó definíciójában szerepelt a const szó, akkor nem állhat olyan kifejezésben, ahol új értéket kaphat. (Ezt a fordító egyébként jelzi.) Ha a függvény típusa nem void, azaz van visszatérési értéke, akkor a függvény kódjában kiszámolt visszatérési értéket egy return utasítás után (akár kifejezés formájában) kell leírni. Amikor a vezérlés a return utasításhoz ér, akkor a függvény kódjának végrehajtása megszakad, és a vezérlés visszatér return utasítás utáni értékkel a függvény hívásának helyére. Ügyeljünk arra, hogy a függvény végrehajtása mindig ilyen return utasítással végz djön. Abban az esetben, ha a függvény típusa void, üres return utasítással (return;) jelezzük a végrehajtás végét. Hívás Egy függvény hívása a nevének () zárójelekkel ellátott fuggvenynev(kifejezés1, kifejezés2, ) leírásból áll, a zárójelek között az aktuális paraméterek felsorolásával. Ha a függvény típusa void, akkor ez a hívás egy önálló utasításként jelenik meg, ha nem, akkor egy olyan kifejezésbe ágyazva, ahol egyébként a függvény típusának megfelel kifejezés állhatna. Erre a pontra helyettesít dik be majd a függvény visszatérési értéke, amelyet a beágyazó kifejezés felhasznál. Az aktuális paraméter lista kifejezéseknek a felsorolása. Ezek száma megegyezik a formális paraméterek számával (kivéve, ha vannak alapértelmezés szerinti értékekkel ellátott paraméterek), és a sorrendjüket annak tudatában kell meghatározni, hogy els kifejezés az els formális paraméterváltozóval, a második a másodikkal, stb. kerül majd párba. Fontos, hogy a kimen adatokat visszaadó paraméterek esetén az aktuális paraméternek változónak kell lenni, hiszen csak ez tudja értékül kapni a visszaadott értéket.
EAF I C++ nyelvi elemek felsorolása 9 Program paraméterek Ezek után már nyilvánvaló, hogy a programjaink main() függvénye egy ugyanolyan függvény, mint amelyekr l itt szó esett. Ennek a függvénynek is lehet paramétere, de az kizárólag az alábbi módon: int main(int argc, char *argv[]) Honnan kaphat bemen értékeket a main() függvény, és hova jut el a visszatérési értéke? Azon operációs rendszerb l illetve rendszerbe ahonnan indítjuk a programot. Parancssorból egy program a projekt nevével indítható, és e név után tetszés szerinti bemen értéket (szavakat) írhatunk szóközzel elválasztva. Az argc paraméterváltozóból azt olvashatjuk ki, hogy a program indításának parancssorában hány bejegyzés volt (programnév + paraméterek), az argv[i] pedig az i-edik paramétert tartalmazza. Függvények elhelyezése a programkódban Amikor egy függvényt csak egyetlen forrásállományban akarunk felhasználni (meghívni), akkor a forrásállomány elején deklaráljuk a függvényt, és ugyanennek a forrásállománynak a végén definiáljuk azt. Ha a programunk több állományból áll és több helyen hívjuk meg ugyanazt a függvényt, akkor a függvény deklarációját (más függvény-deklarációkkal együtt) egy külön fejállományban helyezzük el, a függvény-definíciót pedig egy ugyanilyen nev forrásállományban, a fejállományt beinklúdoljuk a függvény-definíciókat tartalmazó forrásállományba, és az összes olyan forrásállományba, ahol a függvényt meg akarjuk hívni. Szöveges fájlok A szöveges fájlok olyan karakteres állományok, amelyekben bizonyos nem látható karakterek a szöveg tördeléséért felel sek. Ezeket a fájlokat kétféleképpen használhatjuk: vagy olvasásra, vagy írásra. Mindkét m velet sorban, egymás után történik Nemcsak karakterenként, hanem nagyobb szintaktikai egységenként is, például soronként, szavanként, stb. olvashatunk illetve írhatunk. Szöveges fájl deklarálása, nyitása, ellen rzése, zárása #include <fstream> ifstream f; // deklaráció; lehetne ofstream is f.open(fnev.c_str()); // nyitás if (f.fail()) // ellen rzés cout << "Nincs módosító fájl" << endl; char ch; cin>>ch; exit(1); f.close(); // lezárás
EAF I C++ nyelvi elemek felsorolása 10 Olvasás, írás szöveges fájlra Az olvasásra, írásra majdnem ugyanazok a szabályok érvényesek, mint a standard bemenet illetve kimenet használata esetén. Lényeges különbség az, hogy itt egy olvasás a soron következ szintaktikai egységre, azaz elválasztó jelekkel (szóköz, tabulátor, sorvége) határolt részre vonatkozik. Általános formája beolvasásnál: f >> valtozo; Kiírásnál: f << kifejezes; Karakterek beolvasása szöveges fájlból Az ifstream x; char dx; x >> dx; olvasás alapértelmezés szerint átlépi az elválasztó jeleket. Ha az összes karaktert akarjuk egymás után beolvasni, akkor az olvasás megkezdése el tt ki kell kapcsolni ezt a tulajdonságot: #include <iomanip> ifstream x; x.unsetf(ios::skipws) vagy a x.get(dx); utasítást kell alkalmazni. A kiírás egyformán m ködik a x<<dx illetve az x.put(dx) utasítással. Sorok beolvasása szöveges fájlból string sor; getline(f, sor, \n );
EAF I C++ nyelvi elemek felsorolása 11 Osztály A tantárgy els félévében az osztályoknak egy egyszer sített változatát használjuk. Osztály és metódus definíció // osztály definíció class O public: // metódusok deklarációi O(); // konstruktor ~O(); // destruktor Tipus11 Metod1(); Tipus12 Metod2(); ; private: // adattagok Tipus21 tag1; Tipus22 tag2; // metódusok deklarációi Tipus31 Bels Metod1( ); Tipus32 Bels Metod2( ); // metódusok definíciói O::O() O::~O() Tipus11 O::Metod1() Tipus12 O::Metod2() Tipus31 O::Bels Metod1( ); Tipus32 O::Bels Metod2( ); Egy osztály-definíció után már tudunk osztály típusú változókat, úgynevezett objektumokat definiálni. Ezekre az objektumokra mindig végrehajtódik az osztály konstruktora. Ha a konstruktor paramétereket igényel, akkor azokat az objektum definíciójánál meg kell adni: O o( ); Az osztály-definíció után az osztály publikus részben deklarált függvényeket, az úgynevezett metódusokat meghívhatjuk az osztály egy adott objektumára. Egy metódusok hívásakor a metódusneve elé kell írni azt az objektumot (alapértelmezett objektum), amelyre a metódust meghívjuk. o.metod1( )
EAF I C++ nyelvi elemek felsorolása 12 A privát rész metódusai viszont csak más metódusokból hívhatóak meg, és alapértelmezett objektuma az t hívó metódus alapértelmezett metódusa. Ezért a hívásuknál nem kell felt ntetni az alapértelmezett objektumot. Az osztályban deklarált metódusokat definiálni kell. Ezek mint azt az el bb láttuk abban különböznek a szokásos függvényekt l, hogy mindegyiknek alapértelmezés szerinti paramétere az osztály egy objektuma. Azt az objektumot, amelyre a metódust meghívták, az adattagok reprezentálják; az adattagok pillanatnyi értékei határozzák meg az objektum értékét. A metódus törzsében ennek az objektumnak az értékéhez az azt reprezentáló adattagokon keresztül, közvetve lehet hozzáférni úgy, hogy az adattagok nevei önálló változónevekként jelennek meg a függvénytörzsben. Ha a metódus más objektumokat is használ, akkor azok adattagjaira a struct szerkezetnél látott módon hivatkozhatunk; az adattag nevei mez nevekként jelennek meg az objektum neve után. o.a1 A programkódunk más részein, a metódosok definícióján kívül, semmilyen formában sem lehet viszont használni a privát adattagokat. Osztályok elhelyezése a programkódban Kétféle elhelyezést engedünk meg. Az els az, amikor az osztály szolgáltatásait (osztályt, mint típusnevet, valamint az osztály publikus metódusait) használó forrásállomány elején definiáljuk az osztályt, és ugyanebben a forrásállományban az egyéb függvény-definíciók között definiáljuk az osztály metódusait. A másik az, amikor egy osztály-definíciót egy külön fejállományban, az ahhoz tartozó metódus-definíciókat egy ugyanilyen nev forrásállományban helyezzük el, és a fejállományt beinklúdoljuk mind a metódus-definíciókat tartalmazó forrásállományba, mind az összes olyan állományba, ahol az osztály szolgáltatásait használni akarjuk. (B vebbet lásd még a modulokra bontásról szóló részben.) Konstans metódusok Olyan metódusok, amelyek nem változtatják meg az alapértelmezett objektum adattagjait. Ezt a formális paraméter lista mögött elhelyezett const szó jelzi. A fordító program ellen rzi. Inline metódus definíció A metódusnak az osztálydefinícióban történ definiálása, amit a metódus deklarációjának helyébe írunk. Csak egyszer függvénytörzs esetén alkalmazuk. Konstruktorok és destruktor Minden osztálynak vannak speciális metódusai, az osztály nevével megegyez konstruktorai illetve ezek ellentét párja, a destruktor. (Ha elfelejtenénk definiálni ilyeneket, akkor is lesz egy alapértelmezett konstruktor illetve destruktor.) A konstruktorok feladata egy adott objektumot reprezentáló adattagok létrehozása, a destruktoré azok megsz ntetése. Egy osztálynak több (paraméterezésükben eltér ) konstruktora is lehet. Ezek törzsében olyan kódot írhatunk, amely az általunk megadott módon inicializálja az adattagokat. Különösen el nyös ez akkor, amikor egy típus osztállyal történ megvalósításánál a típusértéket (az
EAF I C++ nyelvi elemek felsorolása 13 objektum értékeket) reprezentáló adattagokra teljesülnie kell egy invariáns állításnak, amit már az objektum létrehozásakor érvényesíteni akarunk. Destruktorból csak egy van. Egyszer osztályok készítésénél, azaz statikus reprezentációjú típus (lásd implementációs tanácsok) megvalósításánál csak akkor definiálunk destruktort (különben az alapértelmezett destruktor van érvényben), amikor a konstruktorban olyan inicializáló utasítást használtunk, amelynek van befejez párja. (Például fájloknál az openclose utasításpár.) Adattagok inicializálása a konstruktor fejében A konstruktorok definíciójában az alapértelmezett objektum adattagjainak a formális paraméter listát követ kett spont után elhelyezett listában is adhatunk kezd értéket, ami után következik majd a függvény törzse. O::O(): tag1(érték1), tag2(érték2),