1 Hernyák Zoltán Programozási Nyelvek II. Eszterházy Károly Főiskola Számítástudományi tsz
2 void LekerInfo( ??? x ) { string s = x.info(); } void LekerInfo( ??? x ) { string s = x.info(); } class TElso:TValamilyenOs { public string info() { return ”Hello, én TElso vagyok!”; } } class TMasodik { public string info() { return ”Hello, én TMasodik vagyok!”; } } class TElso:TValamilyenOs { public string info() { return ”Hello, én TElso vagyok!”; } } class TMasodik { public string info() { return ”Hello, én TMasodik vagyok!”; } } Mit válasszunk „x” típusának, hogy mindkét osztályból származó példányra működjön a fenti példa?
3 void LekerInfo( Object x ) { string ret = String.Empty; if (x is TElso) ret = (x as TElso).info(); if (x is TMasodik) ret = (x as TMasodik).info(); return ret; } void LekerInfo( Object x ) { string ret = String.Empty; if (x is TElso) ret = (x as TElso).info(); if (x is TMasodik) ret = (x as TMasodik).info(); return ret; } Mi a probléma ezzel a megoldással? Ha újabb osztályok bukkannak fel, akiknek van info() metódusuk, akkor újabb ‘if’-eket kell írni…
4 A probléma: Van két (vagy több) objektumosztályom, amelyeknek vannak közös vonásaik (egyforma nevű és paraméterezésű metódusaik), de nem állnak egymással ‘rokonságban’ ezen a téren – nem egymásból lettek származtatva. Nincs olyan közös ősük, amelyiknek már megvan ez a közös metódusa, még abstract szinten sem.
5 abstract class TInfo { public abstract string info(); } class TElso:TValamilyenOs, TInfo { public override string info() { return ”Hello, én TElso vagyok!”; } } class TMasodik:TInfo { public override string info() { return ”Hello, én TMasodik vagyok!”; } } abstract class TInfo { public abstract string info(); } class TElso:TValamilyenOs, TInfo { public override string info() { return ”Hello, én TElso vagyok!”; } } class TMasodik:TInfo { public override string info() { return ”Hello, én TMasodik vagyok!”; } } Nem lehet 2 db ős egyszerre! A fenti megoldás sajnos nem működik…
6 class TElso:TValamilyenOs, TInfo { public string info() { return ”Hello, én TElso vagyok!”; } } class TMasodik:TInfo { public string info() { return ”Hello, én TMasodik vagyok!”; } } class TElso:TValamilyenOs, TInfo { public string info() { return ”Hello, én TElso vagyok!”; } } class TMasodik:TInfo { public string info() { return ”Hello, én TMasodik vagyok!”; } } interface TInfo { string info(); } interface TInfo { string info(); } void LekerInfo( TInfo x ) { string s = x.info(); } void LekerInfo( TInfo x ) { string s = x.info(); }
7 A megoldás: Az interface-ek nem osztályok! Nem lehet tőlük örökölni, mert nem tartalmaznak kidolgozott metódusokat, csak azok szignatúráját (prototípusát). Nem tartalmazhatnak mezőket, legfeljebb property-ket, de azoknak is csak a szignatúráját (mint az abstract-ban). Tartalmazhat indexelő-t is (szignatúrűját). Az interface-eket arra használjuk, hogy olyan közös tulajdonságokat írjanak le, amelyek egyébként egymással nem rokon objektumosztályok között fedezhető fel.
8 Szabályok: Az interface-ek-ben lévő metódusok és property deklarációk mindegyike kötelezően public, ezért az interface belsejében nem kell ezt külön jelölni, az osztályokban viszont ezt kötelezően public-ként kell megvalósítani! Az nincs előírva, hogy a metódust egyszerűen, vagy virtuális módon kell megvalósítani. Ha egy osztály ősei között fel van sorolva egy interface neve, akkor az adott osztály típusilag kompatibilis lesz ezzel az interface-el. Ekkor azt mondjuk, hogy az adott osztály implementálja ezt az interface-t.
9 Egy osztály implementál egy interface-t, ha - szerepel az ősei között felsorolva - az interface-ben leírt összes metódust és property-t a megfelelő szignatúrával megvalósít (tartalmazza a kidolgozását). Ha egy osztály ‘bevállal’ egy interface-t ősnek, akkor azzal kötelezettség is jár – meg is kell írni azokat a metódusokat, public módon!
10 interface TInfo { string gyerekNeve(int sorszam); double suly { get; set; } int fizetes { get; } int haviFix[int honap] { get; } interface TInfo { string gyerekNeve(int sorszam); double suly { get; set; } int fizetes { get; } int haviFix[int honap] { get; } Metódus property Indexelő
11 Az OOP nyelvek két csoportja létezik: - interface-t támogató nyelvek (Delphi, C#, Java, …) - több közös ős is lehet ( C++ ) Itt az elsőnek bemutatott megoldás működik, nem iterface-t hozunk létre, hanem egy tényleges osztályt, amelyből akár örökölni is lehet. És a TElso-nek tényleg 2 őse van. abstract class TInfo { public abstract string info(); } class TElso:TValamilyenOs, TInfo { public override string info() { … } } abstract class TInfo { public abstract string info(); } class TElso:TValamilyenOs, TInfo { public override string info() { … } }
12 A közös őssel gondok vannak: class TEgyikOs { public int X=0; } class TMasikOs { public double X=0.0; } public class TEgyutt:TEgyikOs, TMasikOs {... } class TEgyikOs { public int X=0; } class TMasikOs { public double X=0.0; } public class TEgyutt:TEgyikOs, TMasikOs {... } TEgyutt e = new TEgyutt(); e.x = 12; // ??? TEgyutt e = new TEgyutt(); e.x = 12; // ???