1 Hernyák Zoltán Programozási Nyelvek II. Eszterházy Károly Főiskola Számítástudományi tsz
2 Ha egy ‘A’ típus kompatibilis egy ‘B’ típussal, akkor minden olyan helyen, ahol egy ‘B’ típusú kifejezés (változó) szerepelhet, ott szerepelhet egy ‘A’ típusú kifejezés (változó) is. Pl: az ‘int’ kompatibilis típus a ‘double’-val, ezért: void Kiszamol(double x) {... } … az alábbi módokon meghívható: double a = 10; Kiszamol( a ); double a = 10; Kiszamol( a ); int b = 10; Kiszamol( b ); int b = 10; Kiszamol( b );
3 Az OOP-ben egy ‘B’ objektumosztály kompatibilis egy ‘A’ objektumosztállyal, ha az ‘B’-nak az ‘A’ őse. Ez egy tranzitív tulajdonság! class A_oszt {... } class B_oszt:A_oszt {... } class A_oszt {... } class B_oszt:A_oszt {... } A B CD E
4 Az OOP-ben egy ‘B’ objektumosztály kompatibilis egy ‘A’ objektumosztállyal, ha az ‘B’-nak az ‘A’ őse. A fenti egyébként természetes, hiszen ekkor B-nek minden mezője és metódusa meg lesz, ami az A-ban definiált (öröklődés). Ezért természetes, hogy minden olyan helyen, ahol egy A példány használható, ott egy B példány is.
5 class MainClass { static void Kiir(TElso x) { Console.WriteLine(x); } static void Main() { TElso e = new TElso(); TMasodik m = new TMasodik(); Kiir(e); // ??? Kiir(m); // ??? } class MainClass { static void Kiir(TElso x) { Console.WriteLine(x); } static void Main() { TElso e = new TElso(); TMasodik m = new TMasodik(); Kiir(e); // ??? Kiir(m); // ??? } class TElso {... } class TMasodik {... } class TElso {... } class TMasodik {... }
6 class MainClass { static void Kiir(TElso x) { Console.WriteLine(x.szam); } static void Main() { TElso e = new TElso(); TMasodik m = new TMasodik(); Kiir(e); // ??? Kiir(m); // ??? } class MainClass { static void Kiir(TElso x) { Console.WriteLine(x.szam); } static void Main() { TElso e = new TElso(); TMasodik m = new TMasodik(); Kiir(e); // ??? Kiir(m); // ??? } class TElso { public int szam=10;... } class TMasodik:TElso {... } class TElso { public int szam=10;... } class TMasodik:TElso {... }
7 class MainClass { static void Kiir(TElso x) { Console.WriteLine(x.szam); } static void Main() { TElso e = new TElso(); TMasodik m = new TMasodik(); Kiir(e); // ??? Kiir(m); // ??? } class MainClass { static void Kiir(TElso x) { Console.WriteLine(x.szam); } static void Main() { TElso e = new TElso(); TMasodik m = new TMasodik(); Kiir(e); // ??? Kiir(m); // ??? } class TElso { public int szam=10;... } class TMasodik:TElso {... } class TElso { public int szam=10;... } class TMasodik:TElso {... }
8 TElso e; e = new TElso(); TElso e; e = new TElso(); TMasodik m = new TMasodik(); e = m; e = new TMasodik(); TElso e = new TMasodik(); Két lépéses példányosítás… Típuskompatibilitás ! Ekkor melyik VMT lesz az ‘e’ pédányhoz hozzárendelve? TMasodik m = new TElso(); Ez típushelyes értékadás?
9 A VMT-t a konstruktor rendeli a példányhoz. Ezért hogy melyik VMT kerül a példányhoz hozzárendelésre, azt az a konstruktor dönti el, amelyik a példányosítás során meghívásra kerül, és nem az azonosító típusa.
10 class MainClass { static void Kiir(TElso x) { Console.WriteLine(x.szam()); } static void Main() { TElso e = new TElso(); TMasodik m = new TMasodik(); Kiir(e); // mit fog kiirni ? Kiir(m); // ??? } class MainClass { static void Kiir(TElso x) { Console.WriteLine(x.szam()); } static void Main() { TElso e = new TElso(); TMasodik m = new TMasodik(); Kiir(e); // mit fog kiirni ? Kiir(m); // ??? } class TElso { public int szam() { return 10; }... } class TMasodik:TElso {... } class TElso { public int szam() { return 10; }... } class TMasodik:TElso {... }
11 TElso e = new TElso(); TMasodik m = new TMasodik(); Kiir(e); // mit fog kiirni ? Kiir(m); // ??? TElso e = new TElso(); TMasodik m = new TMasodik(); Kiir(e); // mit fog kiirni ? Kiir(m); // ??? class TElso { public int szam() { return 10; }... } class TMasodik:TElso { new public int szam() { return 20; }... } class TElso { public int szam() { return 10; }... } class TMasodik:TElso { new public int szam() { return 20; }... } public void Kiir(TElso x) { Console.WriteLine(x.szam()); } public void Kiir(TElso x) { Console.WriteLine(x.szam()); } Korai kötés !
12 TElso e = new TElso(); TMasodik m = new TMasodik(); Kiir(e); // mit fog kiirni ? Kiir(m); // ??? TElso e = new TElso(); TMasodik m = new TMasodik(); Kiir(e); // mit fog kiirni ? Kiir(m); // ??? class TElso { public virtual int szam() { return 10; }... } class TMasodik:TElso { public override int szam() { return 20; }... } class TElso { public virtual int szam() { return 10; }... } class TMasodik:TElso { public override int szam() { return 20; }... } public void Kiir(TElso x) { Console.WriteLine(x.szam()); } public void Kiir(TElso x) { Console.WriteLine(x.szam()); } Késői kötés !
13 TElso e = new TElso(); TElso m = new TMasodik(); Kiir(e); // mit fog kiirni ? Kiir(m); // mi a VMT ? TElso e = new TElso(); TElso m = new TMasodik(); Kiir(e); // mit fog kiirni ? Kiir(m); // mi a VMT ? class TElso { public virtual int szam() { return 10; }... } class TMasodik:TElso { public override int szam() { return 20; }... } class TElso { public virtual int szam() { return 10; }... } class TMasodik:TElso { public override int szam() { return 20; }... } public void Kiir(TElso x) { Console.WriteLine(x.szam()); } public void Kiir(TElso x) { Console.WriteLine(x.szam()); } Késői kötés !
14 TElso e = new TElso(); TElso m = new TMasodik(); TMasodik x = new TMasodik(); TElso e = new TElso(); TElso m = new TMasodik(); TMasodik x = new TMasodik(); class TElso { public int szam =0; public TElso() { szam = 10; }... } class TMasodik:TElso { public TMasodik() { szam = 20; }... } class TElso { public int szam =0; public TElso() { szam = 10; }... } class TMasodik:TElso { public TMasodik() { szam = 20; }... } public void Kiir(TElso x) { Console.WriteLine( x.szam ); } public void Kiir(TElso x) { Console.WriteLine( x.szam ); }
15 TElso e = new TElso(); TElso m = new TMasodik(); TMasodik x = new TMasodik(); TElso e = new TElso(); TElso m = new TMasodik(); TMasodik x = new TMasodik(); class TElso { public int szam =0; public TElso() { szam = 10; }... } class TMasodik:TElso { new int szam = 0; public TMasodik() { szam = 20; }... } class TElso { public int szam =0; public TElso() { szam = 10; }... } class TMasodik:TElso { new int szam = 0; public TMasodik() { szam = 20; }... } public void Kiir(TElso x) { Console.WriteLine( x.szam ); } public void Kiir(TElso x) { Console.WriteLine( x.szam ); }
16 public void Kiir(TElso x) { if (x is TElso)...; if (x is TMasodik)...; } public void Kiir(TElso x) { if (x is TElso)...; if (x is TMasodik)...; } A típusellenőrzés az ‘is’ operátorral történik. Alakja: is Az ‘is’ logikai igaz (true) vagy hamis (false) értéket ad meg. Logikai igaz, ha a megadott példány kompatibilis típus a megadott osztállyal.
17 public void Kiir(TElso x) { if (x is TElso)...; if (x is TMasodik)...; } public void Kiir(TElso x) { if (x is TElso)...; if (x is TMasodik)...; } Ebben a példában az (x is TElso) biztosan igaz értéket ad meg, hiszen ezt már a fordítóprogram leellenőrízte, hogy ezt a metódust TElso kompatibilis példánnyal hívják-e meg (formális és aktuális paraméterlista- ellenőrzés közben). Az (x is TMasodik) igaz értéket ad meg, ha az aktuális paraméterlistában TMasodik, vagy belőle származta- tott típusú példány szerepelt.
18 public void Kiir(TElso x) { if (x is TElso) (x as TElso).Kiir(); if (x is TMasodik) (x as TMasodik).Feltolt(); } public void Kiir(TElso x) { if (x is TElso) (x as TElso).Kiir(); if (x is TMasodik) (x as TMasodik).Feltolt(); } A típuskényszerítés az ‘as’ operátorral történik. Alakja: as A kifejezés ezen részén az adott azonosító úgy viselkedik, mintha a megadott osztályú lenne ( ekkor működik az adott osztályra a korai kötés is ). A késői kötés működéséhez ez a típus- kényszerítés nem szükséges – az e nélkül is működik.
19 public void Kiir(TElso x) { if (x is TElso) ((TElso)x).Kiir(); if (x is TMasodik) ((TMasodik)x).Feltolt(); } public void Kiir(TElso x) { if (x is TElso) ((TElso)x).Kiir(); if (x is TMasodik) ((TMasodik)x).Feltolt(); } A típuskényszerítés történhet a C-s formában is Alakja: (OSZTÁLY)PÉLDÁNY Sajnos a ‘.’ (pont) operátor magasabb prioritású, mint a típuskényszerítés, ezért az alábbi forma nem megfelelő: (TMasodik)x.Feltolt(); Ez szintaktikailag nem helytelen, de jelentése szerint a Feltolt() által visszaadott értéket típuskényszeríti ‘TMasodik’ típusra…
20 class TElso { public int szam = 10;... } class TMasodik:TElso { public new int szam = 0;... } class TElso { public int szam = 10;... } class TMasodik:TElso { public new int szam = 0;... } public void Kiir(TElso x) { if (x is TMasodik) Console.WriteLine( (x as TMasodik).szam ); else Console.WriteLine( x.szam ); } public void Kiir(TElso x) { if (x is TMasodik) Console.WriteLine( (x as TMasodik).szam ); else Console.WriteLine( x.szam ); }
21 class TElso { public int szam() { return 10; }... } class TMasodik:TElso { new public int szam() return 20; }... } class TElso { public int szam() { return 10; }... } class TMasodik:TElso { new public int szam() return 20; }... } public void Kiir(TElso x) { if (x is TMasodik) Console.WriteLine( (x as TMasodik).szam() ); else Console.WriteLine( x.szam() ); } public void Kiir(TElso x) { if (x is TMasodik) Console.WriteLine( (x as TMasodik).szam() ); else Console.WriteLine( x.szam() ); }
22 Ha a típuskényszerítés nem végrehajtható, mert a példány mégsem kompatibilis a megadott típussal, akkor futási hiba keletkezik (InvalidCastException). Ezért típuskényszerítés ( ‘as’ ) mindig ellenőrizzük le, hogy a kompatibilitás fennáll-e az ‘is’ operátorral!!!!
23 C#-ban ha egy osztálynak nincs megjelölt őse, akkor a nyelv automatikusan az Object osztályt rendeli hozzá ősnek! class A_oszt {... } class A_oszt {... } Object A BC D class A_osztaly:Object {... } class A_osztaly:Object {... }
24 E miatt minden példány mindig kompatibilis az Object típussal ! if (x is Object)... public static void Akarmi(Object x) {... } public static void Akarmi(Object x) {... } if (x is Object) (x as Object)... Tetszőleges osztály tetszőleges példánya átadható paraméterként, hiszen biztosan kompatibilis lesz az Object típussal…
25 class ArrayList { public void Add(Object item) {... } class ArrayList { public void Add(Object item) {... } class Stack { public void Push(Object item) {... } public Object Pop() {... } class Stack { public void Push(Object item) {... } public Object Pop() {... } class Console { public static void WriteLine(Object item) {... } class Console { public static void WriteLine(Object item) {... }
26 Stack st = new Stack();... TSajat t = new TSajat(); st.Push( t ); // működik... Stack st = new Stack();... TSajat t = new TSajat(); st.Push( t ); // működik... TSajat x = st.Pop(); // nem működik ! TSajat x = st.Pop() as TSajat; // nem biztoságos TObject o = st.Pop(); if (o is TElso) t = o as TElso; // biztonságos TObject o = st.Pop(); if (o is TElso) t = o as TElso; // biztonságos
27 static void Beallit(TElso x) { x.eletkor = 11; x.suly = 23.4; if (x is TMasik) x.suly = 23.4; (x as TMasik).suly = 23.4; if (x is TMasik) (x as TMasik).suly = 23.4; } static void Beallit(TElso x) { x.eletkor = 11; x.suly = 23.4; if (x is TMasik) x.suly = 23.4; (x as TMasik).suly = 23.4; if (x is TMasik) (x as TMasik).suly = 23.4; } class TElso { public int eletkor = 10; } Class TMasik:TElso { public double suly = 20.4; } class TElso { public int eletkor = 10; } Class TMasik:TElso { public double suly = 20.4; } TElso e = new TElso(); Beallit( e ); TMasik m = new TMasik(); Beallit( m ); TElso f = new TMasik(); Beallit( f ); TElso e = new TElso(); Beallit( e ); TMasik m = new TMasik(); Beallit( m ); TElso f = new TMasik(); Beallit( f ); Mikor mi fog történni?