A CSharp nyelvet használhatjuk úgy is mint egy szimpla nem objektum orientált nyelv. Ilyenkor, a Main() metódus önmagában áll, esetleg vannak mellette újabb metódusok. Ezeket a metódusokat is egy osztályon belül írjuk, de ettől még messze áll a program az objektum orientált programtól.
Az objektum orientált programozásban újabb osztályokat hozunk létre, az osztályokból objektumokat képzünk, egy meglévő osztályból készítünk egy újabb osztályt, stb.
A következőkben bevezetés kapunk az osztályok, objektumok használatába.
A következő példákban egy Dolgozo nevű osztállyal fogunk dolgozni, amelynek konkrét példánya például Jóska, Mari, Kati, stb.
Első körben hozzunk létre a Main() metóduson kívül egy változót. Legyen ez a „Joska” fizetése. A metódusokon kívül, de az osztályon belül létrehozott változókat az osztály adatmezőjének szoktuk nevezni.
Hozzuk létre a Dolgozo osztályban a Fizetes mezőt. Típusa double lesz, hátha számolni kell ezzel az értékkel később:
class Dolgozo { double Fizetes; }
Most még szükségünk van a Main() metódusra, ahol elérjük az osztály mezőjét.
class Dolgozo { double Fizetes; static void Main() { } }
A Dolgozo osztályt példányosítanunk kell. A Dolgozo osztály nem ír le egyetlen konkrét dolgozót sem. Egy dolgozó, akárki lehet. Megnevezünk egy dolgozót. A példában legyen ez most Jóska. Ő már egy konkrét dolgozó. Egy munkahelyen ilyenkor gondolunk valakire. A C# programban ugyanígy van. Létrehozunk egy Jóska nevű dolgozót. A C# programban ez egy Joska nevű objektum lesz. A programozás során amikor létrehozom a Joska nevű objektumot, annak helyet is kell foglalnunk egyben:
Dolgozo Joska = new Dolgozo();
A Joska nevű objektum létrehozása hasonlít egy változó deklarációhoz: Dolgozo Joska. Az egyenlőség jel után a new operátorral helyett foglalok számára. A new után meghívom a Dolgozo() nevű metódust. Ilyen metódust persze nem deklaráltunk, de ez automatikusan létrejön egy osztály deklarációja során, csak éppen nem csinál semmit. Később megnézzük mire jó ez a metódus.
A létrejött objektum után adhatunk Jóskának fizetést:
Joska.Fizetes = 400000;
Ha már van fizetése ki tudjuk íratni azt:
Console.WriteLine(Joska.Fizetes);
Most már csak az a kérdés, hogy ezt a három sor kódot hol helyezzük el az eddigi kódunkban?! Ehhez létrehozzuk egy már szokásos Main() metódust, a Joska nevű objektumot ott hozzuk létre. Teljes kód:
using System; class Dolgozo { Double Fizetes; public static void Main() { Dolgozo Joska = new Dolgozo(); Joska.Fizetes = 400000; Console.WriteLine(Joska.Fizetes); } }
A dolgozónak persze több adatát is tárolhatjuk. Ezek lehetnek név, település ahol lakik, stb.
using System; class Dolgozo { double Fizetes; string Nev; string Telepules; public static void Main() { Dolgozo Joska = new Dolgozo(); Joska.Fizetes = 400000; Joska.Nev = "Nagy József"; Joska.Telepules = "Szolnok"; Console.WriteLine(Joska.Fizetes); Console.WriteLine(Joska.Nev); Console.WriteLine(Joska.Telepules); } }
Ellenőrző kérdések
Eddig mindig úgy dolgoztunk, hogy egyetlen osztályunk volt amit a fenti példában Dolgozo osztálynak neveztünk el. Az objektum orientáltság másik technikája, hogy ha például dolgozókkal fogunk operálni a programunkban, akkor annak önálló, külön osztályt hozunk létre. Így lesz egy főosztályunk mondjuk „Program” és egy „Dolgozo” osztályunk. A Program osztályban lesz továbbra is a program belépési pontja, vagyis itt helyezzük el a Main() metódust. A Dolgozo viszont ezen osztályon kívül egy önálló osztály:
class Dolgozo { } class Program { static void Main() { } }
Írjuk be a „Fizetes” és „Nev” mezőt a „Dolgozo” osztályunkba és ugyanúgy a Main() metódusban készítsünk egy Joska nevű példányt, amit használunk:
using System; class Dolgozo { public double Fizetes; public string Nev; } class Program { static void Main() { Dolgozo Joska = new Dolgozo(); Joska.Fizetes = 400000; Joska.Nev = "Nagy József"; Console.WriteLine(Joska.Fizetes); Console.WriteLine(Joska.Nev); } }
Vegyük észre, hogy a Dolgozo osztályban betettem még két public kulcsszót! Erre azért van szükség, mert a Program osztályból nem érhető el egy másik osztály mezője vagy metódusa, ha arra nem adok engedélyt a public kulcsszóval. Kipróbálhatjuk a kíváncsiság kedvéért a public nélkül programunkat. A fentiekből következik, hogy a mezők és a metódusok alapesetben nem érhetők el egy másik osztályból.
Egy osztály mezőit ha publikussá tesszük, akkor más osztályból is meg lehet változtatni annak értéket. Ezt általában nem szeretnénk. Ezért nem szoktuk engedélyezni public elérést. De akkor hogyan férünk hozzá annak értékéhez? A válasz egyszerű: metódusokon keresztül. A fenti programban például be kell állítani a fizetés összegét. Akkor készítünk erre a célra egy metódust.
void BeallitFizetes() { Fizetes = 400000; }
Ez működik is, de ez a metódus mindig a 400000-s értéket állítja be. Ezért szeretnénk a beállítandó összeget paraméterként átadni. A változtatások után a metódusunk így nézhet ki:
void BeallitFizetes(double AtvettFizetes) { Fizetes = AtvettFizetes; }
A Joska nevű objektumnál maradva, ekkor a metódust például így hívjuk:
Joska.BeallitFizetes(400000);
Nézzük ezek után a teljes programot:
using System; class Dolgozo { private Double Fizetes; public void BeallitFizetes(double AtvettFizetes) { Fizetes = AtvettFizetes; } } class Program { static void Main() { Dolgozo Joska = new Dolgozo(); Joska.BeallitFizetes(400000); } }
Vegyük észre a „Fizetes” mező deklarációja elé private kulcsszót tettem, hiszen ezt csak metódussal akarom elérhetővé tenni. A fizetést kiíratását kihagytam, mert most az nem működne, hiszen nem tudunk hivatkozni a Main() metódusban a Fizetes mezőre. Ezt is egy metódussal oldjuk meg. Készítsünk a Dolgozo osztályban egy FizetesKiir() metódust:
class Dolgozo { private Double Fizetes; public void BeallitFizetes(double AtvettFizetes) { Fizetes = AtvettFizetes; } public void FizetesKiir() { Console.WriteLine(Fizetes); } } class Program { static void Main() { Dolgozo Joska = new Dolgozo(); Joska.BeallitFizetes(400000); Joska.FizetesKiir(); } }
Néha szükség lehet arra, hogy az éppen beállított fizetést lekérdezzük. Erre egy olyan metódust kell írnunk ami az lekérdezi. Ha van egy ilyen metódust, akkor a fizetés kiíratását is a Main() metódusban végezhetjük el.
class Dolgozo { private Double Fizetes; public void BeallitFizetes(double AtvettFizetes) { Fizetes = AtvettFizetes; } public double LekerFizetes() { return Fizetes; } } class Program { static void Main() { Dolgozo Joska = new Dolgozo(); Joska.BeallitFizetes(400000); Console.WriteLine(Joska.LekerFizetes()); } }
Vegyük észre, hogy a mezőket private a metódusokat public kulcsszóval deklaráltuk. A mezőket nem szeretnénk csak metódusokon keresztül elérni. Persze lehet egy metódus is private elérésű, ha csak az adott osztályon belül szeretnénk használni. A fentieknek megfelelően a „Nev” mezőt (amit eddig kihagytunk) is beilleszthetjük, amelyre írhatunk metódust. Esetleg betehetünk egy FizetesEmeles() metódust:
using System; class Dolgozo { private double Fizetes; private string Nev; public void BeallitFizetes(double AtvettFizetes) { Fizetes = AtvettFizetes; } public double LekerFizetes() { return Fizetes; } public void FizetesEmel(double AtvettEmeles) { Fizetes = Fizetes + AtvettEmeles; } public void BeallitNev(string AtvettNev) { Nev = AtvettNev; } public string LekerNev() { return Nev; } } class Program { static void Main() { Dolgozo Joska = new Dolgozo(); Joska.BeallitNev("Nagy Jóska"); Joska.BeallitFizetes(400000); Console.WriteLine(Joska.LekerNev()); Console.WriteLine(Joska.LekerFizetes()); Joska.FizetesEmel(50000); Console.WriteLine("Emelet fizetés: " + Joska.LekerFizetes()); } }
Egy osztály mezőit vagy metódusokon keresztül vagy tulajdonságaikon keresztül érjük el. Tulajdonságokat akkor használhatunk, ha az adott mezőt be kell állítani, vagy le kell kérdezni. A objektum orientált programozás elvei szerint az osztály mezői nem lehetnek publikusak. Helyette hozzuk létre a tulajdonságot.
Az alábbi példában egy nev mezőt hozunk létre, amelynek meghatározunk egy Nev metódust. A Nev metódusban a metódusokhoz hasonlóan létrehozok két függvényt. Ezek azonban nem rendelkeznek visszatérési értékkel és bemenő paraméterrel. Ezekből kettőt hozhatunk létre. Az egyik neve set, a másik neve get.
A get-et arra használhatjuk, hogy lekérdezzük az adott mezőt. A set-et arra használhatjuk, hogy beállítsuk egy mező értékét. A nev mező beállítását így írhatjuk le:
set { nev = value; }
Lekérdezés megvalósítása:
get { return nev; }
A set esetén a value automatikusan deklarált változó. A tulajdonságnak megadott értéket tartalmazza automatikusan.
A tulajdonság beállítása hasonlít egy publikus mező használatához. Egyszerűen értékadást használunk:
objektumnev.Nev = "Nagy József";
Ha értékadást hajtunk végre a Nev metóduson, akkor az adott érték a value változón keresztül a nev mezőbe kerül. Ha hivatkozunk a Nev tulajdonságra, akkor get hajtódik végre, amivel megkapjuk a nev mező értékét:
string DolgozoNev = objektumnev.Nev;
A teljes példaprogram:
using System; class Dolgozo { string nev; public string Nev { get { return nev; } set { nev = value; } } }
class Dolgozo { public string Nev { get; set; } }
A fenti példákban létrehoztunk egy „Nev” mezőt, aminek a Main() metódusban értéket adtunk. Előfordulhat, hogy elfelejtjük meghívni a BeallitNev() metódust, vagy egyéb más okok miatt szeretnék a mezőinknek kezdőértéket adni. Erre persze létrehozhatunk egy metódust ami ezt megteszi, például Elokeszit() vagy más néven. Erre a célra az objektum orientált programok azonban már tartalmaznak egy metódust. Ennek a neve megegyezik az adott osztály nevével és konstruktornak hívjuk. A konstruktor egyik jellegzetessége, hogy soha nincs visszatérési értéke, ezért nem kell jelezni azt sem, hogy nincs visszatérési érték.
A fenti dolgozó példánál maradva a Dolgozo osztály konstruktora a Dologozo(). A Dolgozo osztályba elhelyezhetem a mezők kezdő értékadásait:
Dolgozo() { Nev = "Névtelen"; Fiezetes = 0; }
Programunk ezek után így nézhet ki:
using System; class Dolgozo { private string Nev; private double Fizetes; public Dolgozo() { Nev = "Névtelen"; Fizetes = 0; } public void BeallitFizetes(double AtvettFizetes) { Fizetes = AtvettFizetes; } public double LekerFizetes() { return Fizetes; } public void FizetesEmel(double AtvettEmeles) { Fizetes = Fizetes + AtvettEmeles; } public void BeallitNev(string AtvettNev) { Nev = AtvettNev; } public string LekerNev() { return Nev; } } class Program { static void Main() { Dolgozo Joska = new Dolgozo(); Joska.BeallitNev("Nagy Jóska"); Joska.BeallitFizetes(400000); Console.WriteLine(Joska.LekerNev()); Console.WriteLine(Joska.LekerFizetes()); Joska.FizetesEmel(50000); Console.WriteLine("Emelet fizetés: " + Joska.LekerFizetes()); } }
Ha most elfelejtenénk a nevet beállítani, akkor a lekért név „Névtelen” lenne, amiből tudhatjuk, hogy még nem volt beállítva.
Inheritance
Egy már meglévő osztályt minden tagját szeretnénk örökölni, de újakat szeretnénk felvenni.
using System; class Allat { protected string Beszed; public string beszel() { return Beszed; } } class Macska : Allat { public Macska() { Beszed = "Miau"; } } class Kutya : Allat { public Kutya() { Beszed = "Vau"; } } class Program { public static void Main() { Macska Jazmin = new Macska(); Console.WriteLine("Jazmin beszél: {0}", Jazmin.beszel()); Kutya Bodri = new Kutya(); Console.WriteLine("Bodri beszél: {0}", Bodri.beszel()); } }
A Dolgozo osztály beallitKezdoFizetes() metódusát szeretném átírni az örökített Mernok osztályban. Ehhez a metódust virtuálissá kell tennem. A Mernok osztályon belül az átírást pedig az override kulcsszóval valósítom meg.
Többalakúság (Polimorfizmu, Polymorphism)
A virtuális metódusok megvalósítják a többalakúságot.
using System; class Dolgozo { protected int Fizetes; public virtual void beallitKezdoFizetes() { Fizetes = 500000; } public int lekerFizetes() { return Fizetes; } } class Mernok:Dolgozo { public override void beallitKezdoFizetes() { Fizetes = 850000; } } class Belepesipont { static void Main() { Dolgozo Joska = new Dolgozo(); Joska.beallitKezdoFizetes(); Console.WriteLine("Jóska alapfizetése: " + Joska.lekerFizetes()); Mernok Gabor = new Mernok(); Gabor.beallitKezdoFizetes(); Console.WriteLine("Gábor mérnöki alapfizetése: " + Gabor.lekerFizetes()); } }
Néha szeretnénk meghívni az örökölt osztályban az ős osztály eredeti metódusát. Ezt a base kulcsszóval tehetjük meg:
using System; class Dolgozo { protected int Fizetes; public virtual void beallitKezdoFizetes() { Fizetes = 500000; } public int lekerFizetes() { return Fizetes; } } class Mernok : Dolgozo { public override void beallitKezdoFizetes() { base.beallitKezdoFizetes(); Fizetes = Fizetes + 350000; } } class Belepesipont { static void Main() { Dolgozo Joska = new Dolgozo(); Joska.beallitKezdoFizetes(); Console.WriteLine("Jóska alapfizetése: " + Joska.lekerFizetes()); Mernok Gabor = new Mernok(); Gabor.beallitKezdoFizetes(); Console.WriteLine("Gábor mérnöki alapfizetése: " + Gabor.lekerFizetes()); } }
A példában a base.beallitKezdoFizetes() utasítás az ősosztály metódusát hívja. Így ha változik a Dolgozo kezdőfizetése, a Mernok kezdőfizetés alapértelmezetten több lesz.
Az absztrakt osztályt az abstract szóval definiáljuk. Akkor használjuk, ha egy osztályt nem példányosításra szántunk, hanem eleve ősosztálynak.
Ha a metódust abstract kulcsszóval deklaráljuk akkor az absztrakt osztályban nem implementálhatjuk (csak a fejrészét írjuk meg). A származtatott osztályban a metódusok fejlécében az override kulcsszót kell használnunk.
abstract class Dolgozo { abstract public double LekerFizetes(); abstract public void BeallitFizetes(double AtvettFizetes); } class Mernok : Dolgozo { double Fizetes=20; override public double LekerFizetes() { return Fizetes; } override public void BeallitFizetes(double AtvettFizetes) { Fizetes = AtvettFizetes; } } class Belepesipont { public static void Main() { Mernok Joska = new Mernok(); Joska.BeallitFizetes(500000); Console.WriteLine(Joska.LekerFizetes()); Console.WriteLine("Valami"); } }
Másik példa az absztrakt osztályokra:
using System; abstract class Dolgozo { protected int Fizetes; abstract public void beallitasFizetes(int atvettFizetes); abstract public int lekerFizetes(); } class Mernok : Dolgozo { override public void beallitasFizetes(int atvettFizetes) { Fizetes = atvettFizetes; } override public int lekerFizetes() { return Fizetes; } } class Program { static void Main() { Mernok Joska = new Mernok(); Joska.beallitasFizetes(500000); } }
Miért érdemes használni absztrakt osztályokat? Az absztrakt osztályok használata az átláthatóságot szolgálhatja.
abstract class Alakzat { public abstract void Rajzol(); } class Kor : Alakzat { public override void Rajzol() { //Rajzoló utasítások } }
A fenti példában az Alakzat osztályon értelmetlen még futtatni a Rajzol metódust. De a Kor osztályon már van értelme.
Absztrakt metódust akkor használunk, ha az adott néven szeretnénk egy metódus kötelező megvalósítását. A megvalósítást azonban nem adjuk meg. Absztrakt metódust viszont csak absztrakt osztályban hozhatunk létre.
A delegált egy függvénytípus-definíció.
Események kezelésére szoktuk használni. Amikor elindul a program, nem szeretnénk az eseménykezelő metódust futtatni. Csak szeretnénk rá hivatkozni, hogy az adott esemény bekövetkezésekor a megadott metódust szeretnénk végrehajtani. Hogy ezt megtehessük egy delegáltat kell létrehoznunk.
Az alábbi példában a delegált használatára látunk egy példát.
using System; public delegate void Fizet(); class Dolgozo { int fizetendo; public Dolgozo() { Fizet fizet = null; fizet += new Fizet(normalfizetes); fizet += new Fizet(tulorafizetes); fizet(); } private void normalfizetes() { fizetendo += 600000; } private void tulorafizetes() { fizetendo += 150000; } public int Fizetendo { get { return fizetendo;}} } class Program { public static void Main() { Dolgozo Joska = new Dolgozo(); Console.WriteLine(Joska.Fizetendo); } }
A delegált fejrésze meghatározza a számára megadható metódusokat is. A delegáltak csak olyan metódust vehetnek fel, amelyeknek a bemenő paraméterei és a visszaadott értéke egyezik vele.
public delegate void Fizet();
A példában szereplő delegált csak olyan metódust vehet fel, amelynek nincs visszatérési értéke és nincs bemenő paramétere.
A fizet delegált objektum két metódust is tartalmaz. Ezt akkor tehetjük meg, ha a delegált visszatérési értéke void (összetett delegált). Egyébként egyszerű delegáltról beszélünk.
using System; class Jarmu { string Rendszam; long Ar; string Szin; public Jarmu() { Rendszam = "Nincs megadva"; Ar = 0; Szin = "Szüke"; } public T leker<T>(int kert) { if (kert == 1) return (T)(object) Rendszam; else if (kert == 2) return (T)(object) Szin; else return (T)(object) Ar; } } class Program { public static void Main() { Jarmu kocsi1 = new Jarmu(); Console.WriteLine("Rendszám: {0}", kocsi1.leker<string>(2)); } }
using System; class Dolgozo { string nev; double penz; double ora; public Dolgozo() { this.nev = "névtelen"; this.penz = 0; this.ora = 0; } public void dolgozik() { Console.WriteLine("dolgozom..."); this.penz += 10; this.ora += 1; } public void kiirPenz() { Console.WriteLine("Ennyi penzem van: " + this.penz); Console.WriteLine("Ennyit dolgoztam: " + this.ora); } public void beallitNev(string nev) { this.nev = nev; } public string lekerNev() { return this.nev; } } class Program01 { static void Main() { Console.WriteLine("============ Dolgozó szimulátor ============"); Console.WriteLine("Parancsok: "); Console.WriteLine(" dol - dolgozik"); Console.WriteLine(" pen - mennyi pénze van"); Console.WriteLine(" v, vege - vége"); Dolgozo joska = new Dolgozo(); joska.beallitNev("Nagy József"); string valasz = ""; do { Console.Write(joska.lekerNev() + "> "); valasz = Console.ReadLine(); if(valasz.Equals("dol") ) { joska.dolgozik(); }else if (valasz.Equals("pen")) { joska.kiirPenz(); } }while(!(valasz.Equals("vege") || valasz.Equals("v"))); } }
using System; class Dolgozok { public string nev; public double fizetes; public Dolgozok() { nev = "Névtelen"; fizetes = 0; } public virtual void beallitAlapfizetes() { fizetes = 400000; } } class Mernok : Dolgozok { public override void beallitAlapfizetes() { fizetes = 80000; } } class Program01 { public static void Main() { Dolgozok janos = new Dolgozok(); Console.WriteLine(janos.nev); Console.WriteLine(janos.fizetes); } }