C++ referencia. Izsó Tamás február 17. A C++ nyelvben nagyon sok félreértés van a referenciával kapcsolatban. A Legyakoribb hibák:

Hasonló dokumentumok
C programozási nyelv Pointerek, tömbök, pointer aritmetika

1. Template (sablon) 1.1. Függvénysablon Függvénysablon példányosítás Osztálysablon

A C programozási nyelv III. Pointerek és tömbök.

A C programozási nyelv III. Pointerek és tömbök.

8. gyakorlat Pointerek, dinamikus memóriakezelés

Mutatók és mutató-aritmetika C-ben március 19.

OOP #14 (referencia-elv)

Járműfedélzeti rendszerek II. 3. előadás Dr. Bécsi Tamás

Programozás módszertan

C programozás. 6 óra Függvények, függvényszerű makrók, globális és

Programozás I gyakorlat. 10. Stringek, mutatók

Programozás II. 2. Dr. Iványi Péter

Osztályok. 4. gyakorlat

C++ programozási nyelv

Programozási Nyelvek: C++

Programozás BMEKOKAA146. Dr. Bécsi Tamás 5. előadás

Bevezetés a programozásba. 8. Előadás: Függvények 2.

Felhasználó által definiált adattípus

C++ programozási nyelv Konstruktorok-destruktorok

7. fejezet: Mutatók és tömbök

STL gyakorlat C++ Izsó Tamás május 9. Izsó Tamás STL gyakorlat/ 1

A C programozási nyelv V. Struktúra Dinamikus memóriakezelés

Programozás II. 4. Dr. Iványi Péter

Alprogramok, paraméterátadás

1. Alapok. Programozás II

A verem (stack) A verem egy olyan struktúra, aminek a tetejéről kivehetünk egy (vagy sorban több) elemet. A verem felhasználása

C++ programozási nyelv Konstruktorok Gyakorlat

Programozás C és C++ -ban

1. Mi a fejállományok szerepe C és C++ nyelvben és hogyan használjuk őket? 2. Milyen alapvető változókat használhatunk a C és C++ nyelvben?

OOP. Alapelvek Elek Tibor

Programozás C++ -ban

1. Öröklés Rétegelés Nyilvános öröklés - isa reláció Korlátozó öröklődés - has-a reláció

Objektumok inicializálása

C memóriakezelés. Mutató típusú változót egy típus és a változó neve elé írt csillag karakterrel hozhatjuk létre.

Bevezetés a C++ programozási nyelvbe

Programozás II gyakorlat. 6. Polimorfizmus

Adatszerkezetek Tömb, sor, verem. Dr. Iványi Péter

Programozás C- és Matlab nyelven C programozás kurzus BMEKOKAM603 Mutatók. Dr. Bécsi Tamás 7. Előadás

Kivételkezelés a C++ nyelvben Bevezetés

GENERIKUS PROGRAMOZÁS Osztálysablonok, Általános felépítésű függvények, Függvénynevek túlterhelése és. Függvénysablonok

Pénzügyi algoritmusok

Programozás II. 3. gyakorlat Objektum Orientáltság C++-ban

PROGRAMOZÁSI NYELVEK - CPP. ELŐADÁS JEGYZET

OOP: Java 8.Gy: Abstract osztályok, interfészek

Programozás. (GKxB_INTM021) Dr. Hatwágner F. Miklós március 3. Széchenyi István Egyetem, Gy r

Programozas 1. Strukturak, mutatok

1. Egyszerű (primitív) típusok. 2. Referencia típusok

Programozás alapjai. (GKxB_INTM023) Dr. Hatwágner F. Miklós augusztus 29. Széchenyi István Egyetem, Gy r

Programozás I gyakorlat

11. gyakorlat Sturktúrák használata. 1. Definiáljon dátum típust. Olvasson be két dátumot, és határozza meg melyik a régebbi.

Programozás alapjai II. (1. ea) C++

Programozás alapjai II. (1. ea) C++

Statikus adattagok. Statikus adattag inicializálása. Speciális adattagok és tagfüggvények. Általános Informatikai Tanszék

Bevezetés a programozásba II. 5. Előadás: Másoló konstruktor, túlterhelés, operátorok

Java II. I A Java programozási nyelv alapelemei

Programozás alapjai. (GKxB_INTM023) Dr. Hatwágner F. Miklós október 11. Széchenyi István Egyetem, Gy r

5. Gyakorlat. struct diak {

Web-technológia PHP-vel

Programozás. (GKxB_INTM021) Dr. Hatwágner F. Miklós április 4. Széchenyi István Egyetem, Gy r

Szövegek C++ -ban, a string osztály

3. Osztályok II. Programozás II

Bevezetés a programozásba I 10. gyakorlat. C++: alprogramok deklarációja és paraméterátadása

Memóriakezelés, dinamikus memóriakezelés

Gregorics Tibor Modularizált programok C++ nyelvi elemei 1

Bevezetés a programozásba Előadás: A const

C++ programozási nyelv

Objektum orientált kiterjesztés A+ programozási nyelvhez

ELTE SAP Excellence Center Oktatóanyag 1

Struktúrák (struct) A struktúra szerkezetét meghatározó deklaráció általános formája:

C++ Gyakorlat jegyzet 2. óra A jegyzetet Umann Kristóf készítette Horváth Gábor gyakorlata alapján. (2018. április 30.) 1. Láthatóság, élettartam

A függvények névvel rendelkező utasításcsoportok, melyeknek információkat adhatunk át, és van egy visszatérési értékük.

A C programozási nyelv II. Utasítások. A függvény.

Már megismert fogalmak áttekintése

Virtuális függvények (late binding)

Függvény pointer. Feladat: Egy tömbben soroljunk fel függvényeket, és hívjuk meg valahányszor.

Paraméter átadás regisztereken keresztül

Programozás II. 2. gyakorlat Áttérés C-ről C++-ra

Fordító részei. Fordító részei. Kód visszafejtés. Izsó Tamás szeptember 29. Izsó Tamás Fordító részei / 1

Programozás alapjai II. (4. ea) C++

Java II. I A Java programozási nyelv alapelemei

Miután létrehoztuk, szeretnénk neki beszédesebb nevet adni. A név változtatásához a következőt kell tenni:

Tömbök kezelése. Példa: Vonalkód ellenőrzőjegyének kiszámítása

Programozás alapjai. 7. előadás

Java V. Osztályszint. lyszintű ű tagok. Példányváltozó. Osztályváltozó. Általános Informatikai Tanszék Utolsó módosítás:

Java III. I I. Osztálydefiníció (Bevezetés)

A C programozási nyelv I. Bevezetés

10. gyakorlat. Pointerek Tárolási osztályok

Informatika terméktervezőknek

Mérnöki programozás 7. Szerkesztette: dr. Vass Péter Tamás

Programozás I. 3. gyakorlat. Szegedi Tudományegyetem Természettudományi és Informatikai Kar

Java III. I I. Osztálydefiníció (Bevezetés)

Programozás alapjai II. (2. ea) C++

Programozás alapjai II. (2. ea) C++

Járműfedélzeti rendszerek II. 4. előadás Dr. Bécsi Tamás

1. Jelölje meg az összes igaz állítást a következők közül!

C vagy C++? Programozási Nyelvek és Fordítóprogramok Tanszék. Pataki Norbert. Programozási Nyelvek I.

Programozás 5. Dr. Iványi Péter

Programozás C++ -ban

Függvények. Programozás alapjai C nyelv 7. gyakorlat. LNKO függvény. Függvények(2) LNKO függvény (2) LNKO függvény (3)

Programozás alapjai C nyelv 7. gyakorlat. Függvények. Függvények(2)

Átírás:

C++ referencia Izsó Tamás 2017. február 17. 1. Bevezetés A C++ nyelvben nagyon sok félreértés van a referenciával kapcsolatban. A Legyakoribb hibák: Sokan összetévesztik a pointerrel. Keveset alkalmazzák a programokban. A második pontban történt elmozdulás, ebben a cikkben én inkább az első ponttal foglalkoznék. 2. Referencia a c++-ban Referencia A referencia egy létező objektum alternatív neve. Definiálásánál meg kell adni azt az objektumot is, amelyet alternatív névvel látunk el. Későbbiek során az alternatív nevet nem ruházhatjuk másra. Kifejezésekben úgy viselkedik mint amelyik objektumnak a keresztnevét viseli. A második pontban direkt kerültem, azt a kifejezést, hogy akire hivatkozik, mivel az új névvel is ellátott objektum elérésénél nem mindig van indirekció. A tankönyvekben a következő egyszerű mintapéldával szokták a referencia felhasználását szemléltetni. void swap ( i n t * a, i n t * b ) { i n t temp = * a ; * a = *b ; *b = temp ; i n t a =2; i n t b =6; swap(&a,&b ) ; void swap ( i n t& a, i n t& b ) { i n t temp = a ; a = b ; b = temp ; i n t a =2; i n t b =6; swap ( a, b ) ; 1

Az első oszlopban pointer segítségével vesszük át a paramétereket, mivel a megváltoztatott értékeket vissza is szeretnénk kapni. Ez a módszer egyaránt alkalmazható a C és a C++ nyelvben is. A második példában pedig a C++-ban bevezetett referencia segítségével oldjuk meg a paraméter átadását. De vajon miért kellett Bjarne Stroustrup-nak egy új nyelvi elemet bevezetni? Netán azért, hogy pár rosszul képzet programozó, aki hadilábon áll a pointer jelöléssel, elkerülje a számára nehéz részeket? Egy új nyelvi elem bevezetése hátrányokkal is járhat. Egyrészt a C programozó megszokta, hogyha a skalár függvényparaméter előtt nem szerepel a címoperátor, akkor az átadott paramétert a függvény nem tudja megváltoztatni. Másrészt az & szimbólum egyrészt címképző operátor, másrészt a referencia jelölésére is felhasználjuk, így esetleg aki először találkozik vele, az összekeverheti a két fogalmat. A C++-ban nem csak a függvényeket, de az operátorokat is felül lehet definiálni. Tegyük fel, hogy van egy class Date {...; nevű osztályunk, és az inkrementál operátort úgy szeretnénk átdefiniálni, hogy a következő napra állítsa a dátumot. Mivel az operátorfüggvény megváltoztatja a paraméter értékét, ezért a paraméter címét kellene átadni. void o p e r a t o r ++( Date * d a t a ) date >day ++; / / i f ( date >day > a k t u á l i s hónap n a p j a i ) Day ma ( 2 0 1 7, 0 2, 1 7 ) ; ++&ma ; A ++&ma hibás, hiszen a &ma egy cím, és nem az objektum, hanem a objektum címe fog megváltozni. Egyébként már a void operator++( Date* today ) definícióval is baj van, mivel a pointer viselkedését nem változtathatjuk meg. Referencia esetében ez az eset nem fordul elő, mivel nem kell használni a címképző operátort. Jó tudni a referenciáról i n t a = 2 ; i n t& r a = a ; c o u t << r a << e n d l ; / / eredmény 2 r a = 1 0 ; c o u t << a << e n d l ; / / eredmény 10 i n t& harom =3; c o n s t i n t& negy = 4 ; Amíg az int& harom=3 hibás, mivel a jobb oldalon nem balérték szerepel, addig a const int& negy=4 helyes. Az utóbbi esetben létrejön egy temporális név nélküli egész változó, aminek az alternatív neve negy lesz. Ezt nagyon fontos szemelőt tartani függvényeknél a temporális értékek átadásakor. 2

Temporális paraméter átvétele referenciával c l a s s R a t i o n a l { i n t n u m e r a t o r ; i n t d e n o m i n a t o r ; p u b l i c : R a t i o n a l ( i n t n, i n t d =1) : n u m e r a t o r ( n ), d e n o m i n a t o r ( d ) { ; R a t i o n a l add_1 ( R a t i o n a l& a, R a t i o n a l& b ) { R a t i o n a l add_2 ( c o n s t R a t i o n a l& a, c o n s t R a t i o n a l& b ) { void foo ( ) { R a t i o n a l a ( 2, 5 ) ; R a t i o n a l b ( 7, 1 3 ) ; R a t i o n a l c ; c = add_1 ( a, b ) ; c = add_2 ( a, b ) ; c = add_1 ( 4, b ) ; c = add_2 ( 4, b ) ; A c = add_1(4,b) hibás mert a paraméter nem konstans referencia, ellenben a c = add_2(4,b) helyes. Habár a fordító nem talál olyan add_2 nevű függvényt, amelynek az egyik paramétere egész, a másik Rational, de a 4-et a Rational egyparaméteres konstruktorával át tudja alakítani, létrehoz egy temporális objektumot, amit már a konstans referencia fogadni tud. (Szerencsére semmi újat nem kellett megtanulnunk az előző példához képest, csak az ott megszerzett tudásunkat kellett alkalmazni.) 3. Tömb Tömbök A tömbökkel csak két műveletet tudunk végezni: 1. megállapíthatjuk a sizeof operátorral a méretét 2. lekérdezhetjük az első elemének a címét Kifejezésben a tömb neve a tömb első elemének a címét adja vissza. Ennek a típusa azonos a tömb egy elemére mutató pointer típusával. A C nyelvben csak egydimenziós tömbök vannak, de a tömb elemei lehetnek tömbök. double a r r a y [ 5 0 ] ; double * pa ; pa= a r r a y ; 3

Ha a tömb neve a függvényhívásánál a paraméterlistában szerepel sum(array,50), akkor a fentiek értelmében a tömb első elemének a címét fogja a függvény megkapni. Ezért a függvényeknél a következő definíciók azonosak. i n t sum ( i n t * t, i n t n ) ; i n t sum ( i n t t [ ], i n t n ) ; i n t sum ( i n t t [ 1 0 0 ], i n t n ) ; Általánosan úgy fogalmazhatnánk, hogyha a tömb bármely elemének a címét és az előtte és utána lévő elemek darabszámát átadjuk 1, akkor a pointer aritmetika segítségével bejárhatjuk az össze elemet 2. A fenti függvénydeklarációkban az első deklaráció fejezi ki a tömb átadásának a szemantikáját a többi jelölelés csak syntactic sugar https://en.wikipedia.org/wiki/syntactic_sugar. A syntactic sugar a nyelv oktatásában nehézségeket vet fel. i n t sum1 ( i n t * t, i n t n ) ; i n t sum2 ( i n t t [ ], i n t n ) ; i n t sum3 ( i n t t [ 1 0 0 ], i n t n ) ; char * s1 = "alma" ; char s2 [ ] = "alma" ; char s3 [ 1 0 0 ] = "alma" ; char s4 [ ] ; i n t t 1 [ ] = { 1, 2, 3 ; i n t * t 2 = t 1 ; i n t t 3 [ ] = t 1 ; Kérdések amelyeket meg kell válaszolnunk: 1. Ha sum2(int t [], int n) deklarációban az int t [] azonos jelentésű minta az int* t, akkor máshol is használhatom ezt a pointerek jelölésére (például int t3 [] = t1)? 2. Amint azt az előbb láttuk az int t [] egy pointer, akkor a char s2[] = "alma" definíció azonos-e a char* s1 = "alma" definícióval, és ugyanakkor miért hibás a int t3 [] = t1? 3. Ha a char s2[] = "alma"-nál és a sum2(int t [], int n)-nél nem kellett a tömb méretét megadni, akkor definiálhatók méret nélküli tömbök is (például char s4[])? 4. Ha int sum3(int t [100], int n) deklarációban megadtuk a tömb méretét, akkor ez a függvény csak száz elemű tömböt képes átvenni? A kérdések megválaszolását az olvasóra bízom. 1 Természetesen az első elemet és a tömb méretét szoktuk átadni 2 Kihasználjuk, hogy az elemek a memóriában címfolytonosan helyezkednek el. 4

4. Referencia tömbökre i n t meret ( i n t t [ ] ) { c o u t << s i z e o f ( t ) << e n d l ; i n t t [ 1 0 0 ] ; c o u t << s i z e o f ( t ) / s i z e o f ( i n t ) << e n d l ; meret ( t ) ; A tömb jelentésének megadása alapján a foo függvényben a sizeof ( t ) a tömb tényleges méretét adja vissza, és ha azt elosztjuk egy elem méretével, akkor a tömb elemeinek számát, jelen esetben 100-at fogunk kapni. Ugyanakkor mivel kifejezésben a tömb neve a tömb első elemére mutató pointerre konvertálódik, ezért a meret() függvény a pointer méretét írja ki. Mi van ha a tömböt referenciaként vesszük át? Tömb átvétele referenciával void r f o o ( i n t (& t ) [ 1 0 0 ] ) { c o u t << s i z e o f ( t ) / s i z e o f ( i n t ) << e n d l ; i n t main ( ) { i n t a [ 1 0 0 ] ; i n t b [ 1 0 0 ] ; i n t c [ 1 0 1 ] ; r f o o ( a ) ; r f o o ( b ) ; r f o o ( c ) ; Az rfoo ( int (&t )[100]) függvény egy 100 elemű tömböt referenciaként vesz át. A referenciánál elmondtuk, hogy kifejezésekben a referencia hasonlóképpen viselkedik, mint az eredeti objektum. Ezért az rfoo () függvényben a sizeof ( t ) operator a tömb tényleges méretét adja vissza, ebből kifolyólag a program az outputra a tömb elemeinek a számát fogja kiírni. Ugyanakkor a rfoo(c) függvényhívás szintaktikailag hibás, mert referenciaként csak azonos típusú adatokat vehetünk át. C++-ban ezt az akadályt azonban könnyen áthidalhatjuk. template < i n t N> void r f o o ( i n t (& t ) [N] ) { c o u t << N << e n d l ; Ezért nem szabad a referenciát a pointerrel összetéveszteni! 5