next up previous contents
Elõre: Függvénymezõk definiálása Fel: Programozás C++-ban Vissza: Öröklés

Többrétûség (polimorfizmus)

A többrétûség (vagy sokalakúság, sokoldalúság) a C++-ban azt jelenti, hogy egy adott õstípusból származtatott további típusok természetesen öröklik az õstípus minden mezõjét, így a függvénymezõket is. De az evolúció során a tulajdonságok egyre módosulnak, azaz például egy öröklött függvénymezõ nevében ugyan nem változik egy leszármazottban, de esetleg már egy kicsit (vagy éppen nagyon) másképp viselkedik. Ezt a C++-ban a legflexibilisebb módon az ún. virtuális függvények (virtual functions) teszik lehetõvé. A virtuális függvények biztosítják, hogy egy adott osztály-hierarchiában (származási fán) egy adott függvény különbözõ verziói létezhessenek úgy, hogy csak a kész program futása során derül, hogy ezek közül éppen melyiket kell végrehajtásra meghívni. Ezt a mechanizmust, azaz a hívó és a hívott függvény futási idõ alatt történõ összerendelését késõi összerendelésnek (late binding) nevezzük. Errõl majd a 2.9-es részben olvashatunk részletesebben.

A többrétûségnek a fordítási idõben megvalósítható formája az ún. overloading. (A szerintünk is alkalmas magyar kifejezés helyett az eredeti angol kifejezést használjuk könyvünkben. Úgy gondoljuk, hogy a szószerinti fordítás, a túlterhelés nem fejezi ki e fogalom lényegét. A overloading helyett esetleg használhatnánk az átdefiniálás kifejezést, de mint késõbb látni fogjuk, ez sem precíz megfogalmazás.) Nos, lássuk, mirõl is van szó:

A hagyományos C-ben egy adott névvel csak egy függvényt definiálhatunk. Például ha deklaráljuk az

            int    cube(int number);
függvényt, akkor kiszámíthatjuk egy egész szám köbét, de elképzelhetõ, hogy egy long, vagy egy double szám köbére van szükségünk. Természetesen írhatnánk még két további függvényt erre a célra, de a cube azonosítót már nem használhatjuk:
            long   lcube(long   lnumber);
            double dcube(double dnumber);
A C++-ban mégis lehetõség van arra, hogy ugyanolyan azonosítóval lássuk el mind a három függvényt. Ezt hívják angolul overloading-nak. Ez tehát azt jelenti, hogy lehetõségünk van arra, hogy egy azonos névvel több különbözõ függvényünk legyen, melyek természetesen különbözõ adattípusokat dolgoznak fel:
            int    cube(int    inumber);
            long   cube(long   lnumber);
            double cube(double dnumber);
Ha az azonos nevû függvények paraméterlistája különbözõ, a C++ gondoskodik arról, hogy egy adott típusú aktuális paraméterrel mindig a megfelelõ függvényváltozatot hívja meg. Így például a cube(10) hivatkozás a cube függvény egész értéket visszaadó változatát hívja meg, míg cube(2.5) hívással a duplapontosságú lebegõpontos változatot aktivizáljuk. Felhívjuk a figyelmet arra a veszélyre, hogy igen könnyen a szándékainktól eltérõ függvényváltozatot is aktivizálhatjuk. Például ha a double változatot akartuk meghívni a 2.0 értékkel, de véletlenül csak 2-t írtunk, akkor az int verzió hívását tételezi fel a C++ fordító.

Az overloading általánosabban azt jelenti, hogy egy adatokon valamilyen operáció végrehajtását jelentõ szimbólumhoz (függvényazonosítóhoz, operátorhoz) több, különbözõ típusra vonatkozó különbözõ jelentést rendelünk. Hogy egy adott adathoz egy mûvelet milyen értelmezése tartozik, az az adott adat típusától, vagy precízebben fogalmazva az adott operációt végrehajtó függvény ún. paraméter-szignatúrájától függ. Paraméter-szignatúrán azt értjük, hogy egy függvénynek mennyi és milyen típusú paramétere van, és az egyes paraméterek milyen sorrendben követik egymást. Tehát attól függõen, hogy egy függvényt milyen típusú paraméterekkel aktivizálunk, mindig az aktuális paraméterekkel megegyezõ szignatúrájú függvényváltozat hívásának megfelelõ kódot generál a C++ fordító. Ezt siganture matching-nek nevezzük. (Itt válik nyilvánvalóvá a hagyományos C programokban a modern stílusú függvénydefiniciók, illetve függvénydeklarációk fontossága: ezek nélkül a fordító program nem tudja egyeztetni az aktuális paraméterlistát a formális paraméterlistával.)

Az eddig elmondottakból nyilvánvaló, hogy az overloading nem átdefiniálást jelent, hiszen amikor az overloading által egy szimbólumhoz - a jelen példánkban a cube függvényazonosítóhoz - egy újabb jelentést rendeltünk, a korábbi jelentések nem vesztek el.


next up previous contents
Elõre: Függvénymezõk definiálása Fel: Programozás C++-ban Vissza: Öröklés