\documentclass[margin=0px]{article} \usepackage{listings} \usepackage[utf8]{inputenc} \usepackage{graphicx} \usepackage{float} \usepackage[a4paper, margin=0.7in]{geometry} \usepackage{amsthm} \usepackage{fancyhdr} \usepackage{setspace} \onehalfspacing \renewcommand{\figurename}{ábra} \newenvironment{tetel}[1]{\paragraph{#1 \\}}{} \pagestyle{fancy} \lhead{\it{PTI BSc Záróvizsga tételek}} \rhead{11. Objektumelvű programozási nyelvek} \title{\textbf{{\Large ELTE IK - Programtervező Informatikus BSc} \vspace{0.2cm} \\ {\huge Záróvizsga tételek}} \vspace{0.3cm} \\ 11. Objektumelvű programozási nyelvek} \author{} \date{} \begin{document} \maketitle \begin{tetel}{Objektumelvű programozási nyelvek} Osztály és objektum. Egységbe zárás, tagok, konstruktorok. Információ elrejtése. Túlterhelés. Memóriakezelés, szemétgyűjtés. Öröklődés, többszörös öröklődés. Altípusosság. Statikus és dinamikus típus, típusellenőrzés. Felüldefiniálás, dinamikus kötés. Generikusok. Altípusos és parametrikus polimorfizmus. Objektumok összehasonlítása és másolása. \end{tetel} \section{Osztály és objektum} Az osztály egy felhasználói típus, amelynek alapján példányok (objektumok) hozhatók létre. Az osztály alapvetően attribútum és metódus (művelet) definíciókat tartalmaz. Az osztály írja le az objektum típusát: megadja a tulajdonságait és azok lehetséges értékeit (azaz a típusértékeket), valamint az objektumon végrehajtható műveleteket (típusműveletek).\\ \noindent Példa C++-ban: \begin{verbatim} //definition of Point class Point { private: int xCoord; int yCoord; public: //constructor Point(int xCoord, int yCoord) : xCoord(xCoord),yCoord(yCoord) {} void Translate(int dx, int dy) { xCoord+=dx; yCoord+=dy; } void Translate(Point delta) { xCoord+=delta.xCoord; yCoord+=delta.yCoord; } int getX() { return xCoord; } int getY() { return yCoord; } }; int main(int argc, char* argv[]) { Point point(0,0); point.Translate(5,-2); cout<; function Square (X : Element_T) return Element_T; \end{verbatim} Itt a \texttt{with function} kezdetű sor végén az \texttt{is <>} azt jelenti, hogy ha az adott típusra már létezik * művelet (pl. egész számokra), akkor nem kell külön megadni példányosításkor, a program automatikusan azt használja. A törzs: \begin{verbatim} function Square (X: Element_T) return Element_T is begin return X * X; -- The formal operator "*". end Square; \end{verbatim} \item A példányosításnak biztosítania kell mindent, amit a sablon specifikációja megkövetel tőle. A következő példában a négyzetre emelő függvényt mátrixokra alkalmazzuk, feltéve, hogy definiáltuk a mátrixszorzást. \begin{verbatim} with Square; with Matrices; procedure Matrix_Example is function Square_Matrix is new Square (Element_T => Matrices.Matrix_T, "*" => Matrices.Product); A : Matrices.Matrix_T := Matrices.Identity; begin A := Square_Matrix (A); end Matrix_Example; \end{verbatim} \end{itemize} Például a C++-ban a sablonszerződés nem így működik. Ott a sablon specifikációja az egész definíció (emiatt sablonosztályokat csak teljes egészében header fájlokban definiálhatunk). Példányosításkor ezt is ismerni kell, hogy tudjuk, hogyan példányosíthatunk. Az információelrejtés elve tehát sérül. Más nyelvekben (pl. Java, funkcionális nyelvek) nem kell a sablonokat példányosítani – mindig ugyanaz a megírt kód hajtódik végre, csak épp az aktuális paraméterekkel. Pl. Java-ban a típusparaméter fordításkor "elveszik", csak futási időben derül ki. \section{Polimorfizmus} A programozási nyelvekben és a típuselméletben a polimorfizmus egy egységes interfészre utal, amit különböző típusok valósítanak meg. Többalakúságot is jelent. A polimorf típuson végzett műveletek több különböző típus értékeire alkalmazhatók. Polimorfizmus többféleképpen is megvalósítható: \begin{itemize} \item {\textbf {Ad-hoc polimorfizmus:}} Egy függvénynek sok különböző implementációja van, amelyeket egyenként specifikálnak néhány különböző típus és kombinációja számára. Megvalósítható túlterheléssel. \item {\textbf {Paraméteres polimorfizmus:}} A kódot általánosan írják meg különböző típusok számára, és alkalmazható az összes típusra, amely megfelel bizonyos, a kódban előre megadott feltételeknek. Objektumorientált környezetben sablonnak vagy generikusnak nevezik. Funkcionális programozási környezetben egyszerűen polimorfizmusnak hívják. \item {\textbf {Altípusosság:}} A név több különböző osztály példányait jelöli, amelyeknek a függvényt deklaráló közös őse van.[3] Objektumorientált környezetben többnyire erre gondolnak, amikor polimorfizmusról beszélnek. \end{itemize} \subsection{Paraméteres polimorfizmus} A parametrikus polimorfizmus jellemzője, hogy a függvényt egyszer kell megírni, és az minden típusra egységesen fog működni. A függvény paramétereinek típusát a függvény használatakor paraméterben kell megadni, innen a paraméteres név. Szokták generikusnak is hívni, az egységes viselkedés miatt. Használata a teljes típusbiztonság megőrzésével növeli a nyelv kifejezőerejét. A paraméteres polimorfizmus nemcsak függvényekre, hanem adattípusokra is értelmezhető, tehát adattípusokra is lehetnek paraméteresek, más néven generikusok. A generikus típusok polimorfikus adattípusok néven is megtalálhatók. A parametrikus polimorfizmus nagyon gyakori a funkcionális programozásban, emiatt gyakran csak polimorfizmusnak nevezik. Az alábbi Haskell példa egy paraméteres polimorf lista adattípust mutat be, két paraméteresen polimorf függvénnyel. \begin{verbatim} class List { class Node { T elem; Node next; } Node head; int length() { ... } } List map(Func f, List xs) { ... } \end{verbatim} Objektumorientált nyelvekben kevésbé gyakori, de legtöbbjükben szintén van lehetőség paraméteres polimorfizmusra. Ezt C++-ban és D-ben template-ek, Javában genericek biztosítják. \subsection{Altípusosság} Egyes nyelvekben az altípusosság használható a polimorfizmus korlátozására. Ezekben a nyelvekben az altípusosság lehetővé teszi, hogy egy függvény egy bizonyos T típusú objektumot használjon, de ha S altípusa T-nek, akkor a függvény S típusú objektumokra is használható a Liskov-féle helyettesíti elv szerint. Az altípus jelölése néha S <: T. Megfordítva, T szupertípusa S-nek, ennek jele T :> S. Az altípusos polimorfizmus rendszerint dinamikus. A következő példában a kutya és a macska az állatok altípusa. A letsHear() eljárás állatot fogad, de altípusos objektumokkal is működik. \begin{verbatim} abstract class Animal { abstract String talk(); } class Cat extends Animal { String talk() { return "Meow!"; } } class Dog extends Animal { String talk() { return "Woof!"; } } void letsHear(final Animal a) { println(a.talk()); } int main() { letsHear(new Cat()); letsHear(new Dog()); } \end{verbatim} A következő példában Number, Rational, és Integer típusok úgy, hogy Number :> Rational és Number :> Integer. Egy függvény, aminek paramétere Number, úgy működik Integer vagy Rational paraméterrel, mint Number paraméterrel. Az aktuális típus elrejthető a felhasználó elől, és objektumazonossággal férhető hozzá. Valójában, ha a Number típus absztrakt, akkor nem is lehetnek olyan objektumok, amelyek aktuális típusa Number. Lásd: absztrakt osztály, absztrakt adattípus. Ez a típushierarchia számtoronyként is ismert a Scheme programozási nyelvből, és rendszerint még több típusból áll. Az objektumorientált nyelvek az altípusos polimorfizmust öröklődéssel valósítják meg. Tipikus implementációkban az osztályok tartalmaznak virtuális táblát, ami hivatkozza az osztály interfészének polimorf részét megvalósító függvényeit. Minden objektum tartalmaz egy referenciát erre a táblára, amire mindig szükség van, ha valami egy polimorf függvényt hív. Ez a mechanizmus példa a: \begin{itemize} \item Késői kötésre, mert a virtuális függvényhívások csak a híváskor kapcsolódnak; \item Egyszeri küldésre, mivel a virtuális függvényhívások csak az első argumentumuk virtuális tábláját veszik figyelembe, így a többi argumentum dinamikus típusa nincs figyelembe véve. \end{itemize} Néhány objektumrendszer, például a Common Lisp Object System többszörös küldésre is képes, így a hívások az összes argumentumokban polimorfak lesznek. \end{document}