Objektno Usmjereno Programiranje Na Slovenskom

You might also like

Download as pdf or txt
Download as pdf or txt
You are on page 1of 240

Programski jezik C#

Osnove objektnega programiranja


Gregor Jere, Matija Lokar in Sreo Urani

V 0.9 marec 2009

C# . NET

Programiranje 1 VS Informatika

C# . NET

Programiranje 1 VS Informatika

C# . NET

Predgovor
Omenjeno gradivo pokriva osnove objektnega programiranja v C# . Gradivo vsekakor ni dokonano in predstavlja delovno razliico. V njem so zagotovo napake (upava, da immanj), za katere se vnaprej opraviujeva. Da bo laje spremljati spremembe, obstaja razdelek Zgodovina sprememb, kamor bova vpisovala spremembe med eno in drugo razliico. Tako bo nekomu, ki si je prenesel starejo razliico, laje ugotoviti, kaj je bilo v novi razliici spremenjeno.

Gregor Jere, Matija Lokar in Sreo Urani Kranj, november 2008

Programiranje 1 VS Informatika

C# . NET

Zgodovina sprememb
14. 11. 2008: Razliica V0.8 le prenos (e neurejeno) Matijevega, Gregorjevega (str. 1 120) in Saovega gradiva. Premisliti je e potrebno kaj in kako. 5. 3. 2009: Razliica V0.9 e vedno povsem neurejeno. Dodano nekaj gradiva, ki ga je smiselno vkomponirati. Gradivo dodano na konec in sicer: Vsebina prosojnic, ki naj bi bile spredavane letos Zgled za Avto Gradivo, ki pokriva uvod v OOP iz C++. Tam je nekaj smiselnih zgledov, ki pa jih je potrebno prepisati v C#.

Programiranje 1 VS Informatika

C# . NET

KAZALO
Objektno programiranje ...................................................................................................................................... 9 Motivacija ....................................................................................................................................................... 9 Objektno usmerjeno programiranje kaj je to .............................................................................................. 10 Objekti........................................................................................................................................................... 11 Objekti........................................................................................................................................................... 13 Programiranje v C# ....................................................................................................................................... 14 Objekti........................................................................................................................................................... 14 Klasino/objektno programiranje .................................................................................................................. 14 Od kje razredi? .............................................................................................................................................. 15 Objekt in ime spremenljivke ......................................................................................................................... 15 Ustvarjanje objektov ..................................................................................................................................... 15 C# in objekti .................................................................................................................................................. 15 Ustvarjanje objektov ..................................................................................................................................... 16 Zgled ............................................................................................................................................................. 16 Objektno programiranje ................................................................................................................................ 18 Objekti, razredi, ... ............................................................................................................................................ 19 Zdruevanje podatkov ................................................................................................................................... 19 Uporaba razreda Zajec .................................................................................................................................. 21 Dostop do podatkov v objektu ...................................................................................................................... 22 e en primer - Ulomek .................................................................................................................................. 25 Povzetek ........................................................................................................................................................ 26 Konstruktorji ................................................................................................................................................. 26 this ................................................................................................................................................................. 27 Uporaba razreda: ........................................................................................................................................... 28 Privzeti konstruktor ....................................................................................................................................... 28 Ve konstruktorjev ........................................................................................................................................ 29 Preobteene metode ...................................................................................................................................... 29 Konstruktorji razreda Zajec navzkrino sklicevanje .................................................................................. 30 e malo o this ................................................................................................................................................ 30 Zgled ............................................................................................................................................................. 31 Objektne metode ........................................................................................................................................... 34 Zgledi ................................................................................................................................................................ 37 Datum............................................................................................................................................................ 37 Fibonaccijevo zaporedje................................................................................................................................ 38 Vaje ................................................................................................................................................................... 40 Kochova rta ................................................................................................................................................. 40 Razred Toka in Kochova rta ...................................................................................................................... 40 Ulomek .......................................................................................................................................................... 40 Razred Majica ............................................................................................................................................... 40 Razred Zajec ................................................................................................................................................. 41 Razred Kolega ............................................................................................................................................... 41 Uporaba razreda Kolega ................................................................................................................................ 41 Uporaba razreda Zajec .................................................................................................................................. 42 Datum............................................................................................................................................................ 42 Zajci z datumom............................................................................................................................................ 42 Uporaba razreda Zajec z datumom ................................................................................................................ 42 Nadgradimo datum ........................................................................................................................................ 42 Dostop do stanj objekta..................................................................................................................................... 42 Dostopi do stanj ............................................................................................................................................ 43 Zgledi ............................................................................................................................................................ 48 Programiranje 1 VS Informatika

C# . NET

Dostop do stanj/lastnosti ............................................................................................................................... 48 Nastavitve podatkov (stanj)........................................................................................................................... 49 Dostop do stanj.............................................................................................................................................. 51 Ostale metode................................................................................................................................................ 52 Metoda ToString ........................................................................................................................................... 52 Celotni razred Zajec ...................................................................................................................................... 54 Gradnja razredov - zgled .................................................................................................................................. 58 Ustvarjanje objektov ..................................................................................................................................... 58 Problem Banke Butale .................................................................................................................................. 58 Okostje razreda ............................................................................................................................................. 59 Razred Kovanec ............................................................................................................................................ 59 Uporaba razreda Kovanec ............................................................................................................................. 61 Zgled - razred Kvader ................................................................................................................................... 62 Ustvarjanje razredov in objektov: povzetek .................................................................................................. 66 Zgledi ................................................................................................................................................................ 67 Vaje ................................................................................................................................................................... 72 Razred Kolega ............................................................................................................................................... 74 Datum............................................................................................................................................................ 76 Oseba............................................................................................................................................................. 76 Majica ........................................................................................................................................................... 77 Kandidat za direktorja banke ........................................................................................................................ 77 Denarnica ...................................................................................................................................................... 79 Podatkovni nosilec ........................................................................................................................................ 80 Razred Zajec ................................................................................................................................................. 80 Statino in objektno ........................................................................................................................................... 87 Statine komponente ..................................................................................................................................... 87 Statine spremenljivke .................................................................................................................................. 87 Uporaba statinih spremenljivk ..................................................................................................................... 88 Statine komponente dostop ...................................................................................................................... 88 Statine komponente naslavljanje .............................................................................................................. 88 Zajec.............................................................................................................................................................. 88 Statine metode ............................................................................................................................................. 95 Statine metode ............................................................................................................................................. 96 Privatne metode............................................................................................................................................. 97 Dedovanje ......................................................................................................................................................... 97 Pogosto uporabljani postopki I...................................................................................................................... 97 Dedovanje ..................................................................................................................................................... 98 Razred BoljsiUlomek .................................................................................................................................... 98 Uporaba Boljega ulomka ............................................................................................................................. 98 Pogosto uporabljani postopki ........................................................................................................................ 99 Dedovanje ..................................................................................................................................................... 99 Dedovanje ................................................................................................................................................... 100 Iz muhe slon ................................................................................................................................................ 106 Osnova: razred ZajecNov ............................................................................................................................ 106 Prekrite metode ........................................................................................................................................... 106 "Umazane" podrobnosti .............................................................................................................................. 106 Uporaba ....................................................................................................................................................... 106 Zgledi .............................................................................................................................................................. 107 Vaje ................................................................................................................................................................. 107 Zival ............................................................................................................................................................ 107 Razred Pes ................................................................................................................................................... 109 Razred Dalmatinec ...................................................................................................................................... 109 Naloge brez raunalnika .............................................................................................................................. 110 Razred Pes II ............................................................................................................................................... 111 Zajec iz ivali .............................................................................................................................................. 113 Programiranje 1 VS Informatika

C# . NET

Embi d.o.o ................................................................................................................................................... 113 Vaje "pe" ................................................................................................................................................... 114 Halo Kitajc .................................................................................................................................................. 118 Trojiko ....................................................................................................................................................... 119 Redki vektorji.............................................................................................................................................. 119 Plavalec ....................................................................................................................................................... 120 Plavalec II ................................................................................................................................................... 121 Razredi in objekti (osnove) ............................................................................................................................... 121 Razred - class .................................................................................................................................................. 122 Enkapsulacija .............................................................................................................................................. 122 Konstruktor ................................................................................................................................................. 127 Preobloeni (overloaded) konstruktorji ....................................................................................................... 129 Kopirni (copy) konstruktorji ....................................................................................................................... 130 Statini (static) konstruktorji ....................................................................................................................... 130 Polja tipa readonly ...................................................................................................................................... 131 Destruktorji ................................................................................................................................................. 131 Lastnost (Property) ...................................................................................................................................... 134 Statine metode ........................................................................................................................................... 137 Statina polja ............................................................................................................................................... 137 Dedovanje (Inheritance) izpeljani razredi ................................................................................................... 139 Kaj je to dedovanje ..................................................................................................................................... 139 Bazini razredi in izpeljani razredi.............................................................................................................. 139 Klic konstruktorja bazinega razreda .......................................................................................................... 140 Doloanje oz. prirejanje razredov ............................................................................................................... 140 Nove metode ............................................................................................................................................... 141 Virtualne metode ......................................................................................................................................... 143 Prekrivne (Override) metode ...................................................................................................................... 143 Polimorfizem - mnogolinost .......................................................................................................................... 146 Uporaba oznaevalca protected ..................................................................................................................... 148 Prosojnice M. Lokar 2009 ................................................................................................................................ 149 Razred Avto ....................................................................................................................................................... 149 Testiranje razreda ........................................................................................................................................... 221 OOP v C++ (avtor dr. M. Krana)................................................................................................................... 221

Programiranje 1 VS Informatika

C# . NET

Objektno programiranje
Motivacija Pri programiranju se je izkazalo, da je zelo koristno, e podatke in postopke nad njimi zdruujemo v celote, ki jih imenujemo objekte. Programiranje je potem sestavljeno iz tega, da objekte ustvarimo in jim naroamo, da izvedejo doloene postopke. Veina sodobnih programskih jezikov je objektno ali kot tudi reemo predmetno usmerjenih. Pri uporabi tovrstnih jezikov hitro naletimo naletimo na pojme kot so zdruevanje (enkapsulacija), velinost (polimorfizem), dedovanje (inheritenca), ki so vsaj na prvi pogled zelo zapleteni, Nas ne bodo zanimali, kot tudi ne tevilne druge podrobnosti. Objektno usmerjeno programiranje nam omogoa, da na problem gledamo kot na mnoico objektov, ki med seboj sodelujejo in vplivajo drug na drugega. Na ta nain laje piemo sodobne programe, kjer se nenehno odvija veliko tevilo dogodkov kot so premikanje mike, zapiranje oken, klikanje na gumbe, potrditev doloenih izbir, ki se med sabo prepletajo, vplivajo drug na drugega in kar bi le s teavo sprogramirali na klasien nain z nizanjem zaporedja stavkov in ukazov. tevilni jeziki (JavaScript, Visual Basic for Applications, Java, C#, Python, ) nudijo okolja v katerih so e doloeni objekti, nad katerimi lahko izvajamo doloene metode, funkcije. Tako "iz ni" dobimo grafini objekt g, na katerim potem z doloeno metodo nariemo krog. Ko program zaenemo, ta samodejno ustvari okno z doloenim imenom in gumbom za zapiranje Veina jezikov omogoa, da program zlahka dopolnimo z gumbi, potrditvenimi stikali in podobnimi elementi. Vse to so objekti, ki imajo lastnosti in metode, s katerimi na te objekte vplivamo. Na primer v jeziku JavaScript. Zanima nas le oznaeni del
var i = 0; function animacija() { i = i + 1; if (i == 6) i = 1; document.menjajocaSlika.src = "album" + i + ".jpg"; setTimeout("animacija()", 1000) }

JavaScript spletno stran, na kateri se nahaja, imenuje kot objekt z imenom document. Na tem objektu imamo tudi druge objekte, v naem konkretnem primeru sliko (vstavljeno v jeziku HTML z znako IMG), poimenovano kot menjajocaSlika:
<img name=" menjajocaSlika " src="album1.jpg">

S pomojo stavkov v jeziku JavaScript vplivamo na ta objekt (document.menjajocaSlika) tako, da mu spremenimo lastnost src, kjer je zapisana datoteka, ki naj jo ta objekt prikazuje
document.menjajocaSlika.src = "album" + i + ".jpg";

Podobno z metodo writeln vstavimo v samo dototeko ustrezno kodo v jeziku html. e v kodi spletne strani pie
<script type="text/javascript"> document.writeln("<p>To naj se pojavi na spletni strani!</p>"); </script>

pomeni, da naj se objekt document (kar pomeni kar ta spletna stran) spremeni tako, da vsebuje tekst, zapisan med narekovaji. Dejansko je torej uinek isti, kot e bi na spletni strani napisali kar
<p>To naj se pojavi na spletni strani!</p>

Seveda pa smo se doslej nauili e dovolj, da vemo, kakne vse monosti s tem imamo verjetno bomo JavaScript uporabili, da bomo napisali na spletno stran kaj bolj zapletenega, na primer besedilo, ki ga bomo prej s pomojo ustreznega postopka obdelali. Tako smo na primer pri esti nalogi hitrega testa v uvodu uporabili monost pisanja na spletno stran zato, da smo na enostaven nain poenotili vse naslove na spletni strani. Programiranje 1 VS Informatika

C# . NET

10

Ko torej piemo programe, imamo s samim izvajalnim okoljem ponavadi na voljo bogato zbirko razlinih objektov (natanneje nartov za to, kakni so objekti doloene vrste). Ni nam potrebno pisati na stotine vrstic kode le za to, da bi dosegli, da na program uporabniku omogoa vnos datuma preko posebnega okna z e izpisanim koledarjem. Vedeti je potrebno le, da imamo v izvajalnem okolju e na voljo (nart za) tovrstni objekt. Ostane nam le e, da tak objekt ustvarimo in s pripravljenimi metodami nanj vplivamo. Tako s spodnjim zgledom v programskem jeziku Java ustvarimo okno z vnosno povrino, po kateri lahko piemo.

e ne bi imeli na voljo e ustreznih objektov, bi na program sestavljalo na desetine ali celo stotine ustreznih ukazov. Tako pa le uporabimo dana narta za objekta JFrame in JTextArea, z ukazom new ustvarimo objekta ustrezne vrste in z metodami, kot so setSize, show in drugimi vplivamo nanju.
import javax.swing.*; import java.awt.*; public class JFrameTest { public static void main(String[] args) { JFrame okno = new JFrame("Moje okno"); okno.setSize(250, 250); okno.setLocation(300,200); okno.getContentPane().add(BorderLayout.CENTER, new JTextArea(10, 40)); okno.show(); } }

In seveda imamo na voljo take objekte tudi v standardnih knjinicah jezika C#. Objektno usmerjeno programiranje nam omogoa, da na problem gledamo kot na mnoico objektov, ki med seboj sodelujejo in vplivajo drug na drugega. Za nas je pomembno to, da veina sodobnih jezikov prinaa v svojem izvajalnem okolje celo vrsto e pripravljenih objektov in metod za delo z njimi. Ti objekti so na primer spletna stran, slika na spletni strani, izbire v menuju programov v okolju Microsoft Office, grafino okno, tiskalnik, . S pripravljenimi metodami potem vplivamo na te objekte na primer zamenjamo sliko na spletni strani, spremenimo privzeto delovanje ukaza Print v izbiri File, na grafino povrino nariemo krog, Objektno usmerjeno programiranje kaj je to Pri objektno (ali kot tudi reemo predmetno) usmerjenem programiranju se ukvarjamo z objekti seveda. Objekt je nekakna rna katla, ki dobiva in poilja sporoila. V tej rni katli (objektu) se skriva tako koda (torej zaporedje programskih stavkov), kot tudi podatki (informacije nad katerimi se izvaja koda). Pri klasinem programiranju imamo kodo in podatke loene. Tudi mi smo do sedaj programirali ve ali manj na klasien nain. Pisali smo metode, ki smo jim podatke posredovali preko parametrov. Parametri in metode niso bile prav ni tesno povezane. e smo npr. napisali metodo, ki je na primer poiskala najveji element v tabeli tevil, tabela in metoda nista bili zdrueni tabela ni ni vedela o tem, da naj bi kdo npr. po njej iskal najveja tevila. V objektno usmerjenem (vasih boste sreali tudi kratico OO ali O-O, kar izvira iz object oriented) programiranju pa sta koda in podatki zdueni v nedeljivo celoto objekt. To prinaa doloene prednosti. Ko uporabljamo objekte nam nikoli ni potrebno pogledati v sam objekt. To je dejansko prvo pravilo OO programiranja uporabniku ni nikoli potrebno vedeti, kaj se dogaja znotraj objekta.

Programiranje 1 VS Informatika

C# . NET

11

Objekt Zakaj ni potrebno vedeti tega? Vsi objekti med samo komunicirajo preko sporoil. Za vsak objekt se tono ve, kakna sporoila lahko sprejme in kakna lahko polje. Vse, kar objekt zna narediti, je doloeno z vmesnikom objekta. Se vam zdi to zapleteno? No, pa povejmo malo bolj "po domae". Gre dejansko zato, da nad objektom izvajamo razline metode. In za vsak objekt se tono ve, katere metode zanj obstajajo in kakne rezultate vraajo. Recimo, da imamo doloen objekt z imenom obj, ki predstavlja doloeno osebo in vemo, da ta objekt lahko povpraamo (mu poljemo sporoilo) o tem, koliko je njegov IQ. To storimo tako, da nad njem izvedemo metodo

obj.KolikoJeIQ()
Objekt odgovori s sporoilom (metoda vrne rezultat), ki je neko celo tevilo. Koliko je tvoj IQ ?

92

Tisto, kar je pomembno, je to, da nam, kot uporabnikom objekta, ni potrebno vedeti, kako objekt izrauna IQ (je to podatek, ki je zapisan nekje v objektu, je to rezultat nekega preraunavanja ). Kot uporabnikom nam je vano le, da se z objektom lahko pogovarjamo o njegovem IQ. Vse "umazane podrobnosti" o tem, kaj je znotraj katle, je prepueno tistim, ki napiejo kodo s pomojo katere se ustvari objekt in (e je zadeva seveda sprogramirana prav) uporabnik (programer, ki pie drug program, ki te objekte uporablja) se vanje ne more vtikati. Seveda se lahko zgodi, da se kasneje ugotovi, da je potrebno "preurediti notranjost objekta". In tu se izkae prednost OO koncepta. Ker v programih, kjer objekte uporabljamo, ni ne vemo o tem, kaj je znotraj katle, kaj se na primer dogaja, ko objekt povpraamo po IQ, bodo programi navkljub spremembam znotraj katle e vedno delovali. e torej na objekte gledamo kot na rne katle (zakaj rne zato, da se ne vidi, kaj je znotraj!) in z njimi ravnamo le preko sporoil (preko klicev metod), nai programi delujejo ne glede na morebitne spremembe v samih objektih. Omogoanje dostopa do objekta samo preko sporoil in onemogoanje uporabnikom, da vidijo (in brskajo) po podrobnostih, se imenuje skrivanje informacij (information hidding) ali e bolj ueno enkapsulacija (encapuslation). In zakaj je to pomembno? Velja namre, da se programi ves as spreminjajo. Velika veina programov se dandanes ne napie na novo, ampak se spremeni obstoje program. In veina napak izhaja iz tega, da nekdo spremeni doloen delek kode, ta pa potem povzroi, da drug del programa ne deluje ve. e pa so tisti delki varno zapakirani v kapsule, se spremembe znotraj kapsule ostalega sistema prav ni ne tiejo. Objekti Objekt je skupek podatkov, s katerim elimo upravljati kot s celoto. Ima: Podatke: kaj o objektu vemo, kakne podatke o objektu hranimo Metode: Kaj objekt zna Kakne metode lahko izvajamo nad njem Vsak objekt pripada nekemu razredu. e pripada objekt x razredu R, potem pravimo tudi da je x objekt tipa R.

Programiranje 1 VS Informatika

C# . NET

12

Pravzaprav smo se e ves as ukvarjali z objekti, saj smo v naih programih uporabljali razline objekte, ki so e pripravljeni v standardnih knjinicah jezika C#. Oglejmo si nekaj primerov objektov iz standardne knjinice jezika: Objekt tipa StreamReader predstavlja vhodni kanal. Kadar elimo brati s tipkovnice ali z datoteke, naredimo tak objekt in kliemo njegovo metodo readLine za branje ene vrstice. Objekt System.Console predstavlja standardni izhod. Kadar elimo kaj izpisati na zaslon, pokliemo metodo Write na objektu System.Console. Objekt tipa Random predstavlja generator nakljunih tevil. Metoda Next(a, b), ki jo izvedemo nad objektom tega tipa pa nam vrne neko nakljuno celo tevilo med a in b.

StreamWriter pisanje = new StreamWriter(datoteka); //kreiranje objekta StreamWriter pisanje.Flush(); //uporaba metode objekta new Random().Next(1,100); //uporaba metode na objektu iz razreda Random Console.WriteLine(); //uporaba metode WriteLine na objektu Console

Nauili smo se torej uporabnosti objektnega programiranja, nismo pa se e nauili izdelave svojih razredov. In e se vrnemo na razlago v uvodu kot uporabniki isto ni ne vemo (in nas pravzaprav ne zanima), kako metoda Next doloi nakljuno tevilo. In tudi, e se bo kasneje "katla" Random spremenila in bo metoda Next delovala na drug nain, to ne bo "prizadelo" programov, kjer smo objekte razreda Random uporabljali. Seveda, e bo sporoilni sistem ostal enak. V omenjenem primeru to pomeni, da se bo metoda e vedno imenovala Next, da bo imela dva parametra, ki bosta doloala meje za nakljuna tevila in da bo odgovor (povratno sporoilo) neko nakljuno tevilo z elenega intervala. Seveda pa nismo omenjeni le na to, da bi le uporabljali te "rne katle", kot jih pripravi kdo drug (npr. jih dobimo v standardni knjinici jezika). Objekti so uporabni predvsem zato, ker lahko programer definira nove razrede in objekte, torej sam ustvarja te nove rne katle, ki jih potem on sam in drugi uporablja. Oglejmo si primer programa v C#, ki uporablja objekte, ki jih napiemo sami.

PRVI
1: 2: 3: 4: 5: 6: 7: 8: 9: 10: 11: 12: 13: 14: 15: 16: 17: 18: 19: 20:

OBJEKTNI PROGRAM

using System; public class MojR { private string mojNiz; public MojR(string nekNiz) { mojNiz = nekNiz; } public void Izpisi() { Console.WriteLine(mojNiz); } } public class Pozdrav { public static void Main(string[] arg) { MojR prvi = new MojR("Pozdravljen, moj prvi objekt v C#!"); prvi.Izpisi(); } }

Programiranje 1 VS Informatika

C# . NET

13

Program napiimo kar na obiajni nain v okolju SharpDevelop torej New Solution/Windows Applications/Console Application. Vnesene vrstice kar vse pobriimo in napiimo zgornjo kodo. Ko program prevedemo in poenemo, dobimo

Na kratko razloimo, "kaj smo se li". V vrsticah 3 13 smo definirali nov razred z imenom MojR. Ta je tak, da o vsakem objektu te vrste poznamo nek niz, ki ga hranimo v njem (vrstica 4). Vse znanje, ki ga objekti tega razreda imajo, je, da se znajo odzvati ne metodo Izpis(), ko izpiejo svojo vsebino (torej niz, ki ga hranimo v njem). V vrsicah 15 20 je na "pravi program", torej tisti del reitve, ki opravi dejansko neko delo. V vrstici 17 naredimo primerek objekta iz razreda MojR in vanj shranimo niz "Pozdravljen, moj prvi objekt v C#!". V vrstici 18 pa temu objektu naroimo, naj izpie svojo vsebino.

Objekti o stanja: Programiranje 1 VS Informatika

C# . NET

14

o o

Lastnosti, podatki, komponente znanje Odzivanje na dogodke Zdrueno v celoto Podatki in metode, ki opisujejo neko stvar/objekt oga: Podatki: velikost, barva, poloaj v prostoru, Metode: sprememba velikosti, sprememba poloaja, Ulomek: Podatki: tevec, imenovalec Metode: spremeni tevec, spremeni imenovalec, setej, obratna vrednost, lepo izpii, ... Razlika med ogo kot idejo oge in mojo ogo (konkretni primerek realizacija ideje oge) oziroma med ulomkom kar tako in ulomkom .

Programiranje v C# Sestavljanje razredov: Opis lastnosti objektov Opis metod (znanja objektov): Ustvarjanje objektov in njihova uporaba "Ukazovanje" objektom, kaj naj ponejo Objekt za izpolnitev doloene naloge potrebuje druge objekte in njihove metode Zaetek: Glavni razred (ki ima metodo Main) Izvajanje metode Main ustvarjanje objektov, proenje dogodkov, odzivanje na dogodke,

Razred je abstraktna definicija objekta in e elimo nek razred uporabiti, mora obiajno obstajati vsaj en primerek razreda. Primerek nekega razreda imenujemo objekt. Ustvarimo ga s kljuno besedo new. ImeRazreda primerek = new ImeRazreda(); Objekt je raunalniki model predmeta ali stvari iz vsakdanjega ivljenja (avto, oseba, datum). Za reitev problema uvedemo mnoico objektov, ki si medsebojno poiljajo sporoila. Lastnosti objektov so zapisane v razredih (class), ki vsebujejo:

podatke in , metode oz. odzive objektov na sporoila.

Stanje objekta opiemo s spremenljivkami, njihovo obnaanje oz. odzive pa z metodami. Objekti Objekt je kakrenkoli skupek podatkov, s katerimi elimo upravljati. Osnovni pristop objektnega programiranja: objekt = podatki + metode za delo s podatki. Ko elimo kak podatek (objekt) obdelati, objektu (podatku) signaliziramo, kaj naj se zgodi: Pokliemo ustrezno metodo v objektu. Objekt je "rna katla, ki sprejema in poilja sporoila. Jedro objekta sestavljajo njegove spremenljivke, okrog katerih se nahajajo njegove metode. Klasino/objektno programiranje Klasino programiranje: program = metode Ko elimo kak podatek obdelati v klasinem programiranju: pokliemo ustrezno metodo z argumenti argumenti: podatki, ki naj jih obdela. e elimo izvesti metodo f na podatku x: o Klasino: Programiranje 1 VS Informatika

C# . NET

15

izvedi statino metodo f na podatku x f(x); Objektno: podatku/objektu x signaliziraj, da naj izvede metodo f x.f();

Od kje razredi? Veliko razredov je e vgrajenih (so v standardnih knjinicah) v C# in njegovo oklolje. Taki razredi so na primer Math, System, StreamReader, o .NET Framework o C# je .NET jezik ima dostop do vseh razredov, definiranih v knjinicah (zbirkah razredov) okolja .NET Glej npr. http://msdn2.microsoft.com/sl-si/library/ms229335(en-us).aspx

Razporejeni v imenske prostore System, System.IO

Razrede lahko dobimo tudi iz drugih virov: o Nai stari razredi o Drugi programerji

Potrebujemo dostop do ustrezne datoteke (dll, exe) Objekt in ime spremenljivke

NekiObjekt a;
a je naslov, kjer bo objekt (referenca na objekt) V pomnilniku se je naredil objekt tipa NekiObjekt() / po pravilih, ki so doloena z opisom razreda NekiObjekt V pomnilniku se je naredil objekt tipa NekiObjekt() in a kae na ta novo ustvarjeni objekt

new NekiObjekt(); a = new NekiObjekt();


Ustvarjanje objektov Razred je ablona, ki definira spremenljivke in metode skupne vsem objektom iste vrste. class: Nart objekta, ablona Primerek razreda (instanca) konkretni objekt: Ustvarimo ga z new Brez tega objekta NE MOREMO uporabiti NekiObjekt a; Objekt NE obstaja a je IME objekta natanneje a je ime spremenljivke, kjer hranimo NASLOV objekta vrste NekiObjekt C# in objekti Razred (class) je opis vrste objekta (nart, kako naj bo objekt videti) opis ideje objekta. Primerek razreda (instanca) konkretni objekt.

Programiranje 1 VS Informatika

C# . NET

16

Ustvarjanje objektov

Ulomek ime = new Ulomek(3, 4);


Reemo: V objektu ime je shranjen ulomek ; Toneje: v spremenljivki ime je naslov nekega objekta tipa Ulomek, ki predstavlja ulomek . Spremenljivka ime kae na objekt tipa Ulomek, ki Prvi ukaz je dejansko spoj dveh stavkov: deklaracija in prireditev

Ulomek ime; ime = new Ulomek(3, 4);


ime: _2h11b11__ 2h11b11: Brez new objekta e NI vasih skrito Nizi string a = "bla"; string a = new string("bla"); Tabele int[] tabela = {1, 2, 3}; int[] tabela = new int[3]; tabela[0] = 1;

o o

Zgled Poglejmo si e en zgled. Denimo, da bi radi napisali program, ki bo prebral nek ulomek in mu pritel 1/2. "Klasino" se bomo tega lotili takole (seveda pisec ni pozabil, kako se setevajo ulomki, a takojle, po Janezkovo, si je laje zapomniti ;-) )

POVEAJMO
1: 2: 3: 4: 5: 6:

ULOMEK KLASINO

using System; namespace UlomkiKlasika { class Program { public static void Main(string[] args) {
Programiranje 1 VS Informatika

C# . NET

17

7: 8: 9: 10: 11: 12: 13: 14: 15: 16: 17: 18: 19: 20: 21: 22: 23:

// vnos podatkov Console.Write("tevec ulomka: "); string beri = Console.ReadLine(); int stevec = int.Parse(beri); Console.Write("Imenovalec ulomka: "); beri = Console.ReadLine(); int imenovalec = int.Parse(beri); // "delo" stevec = stevec + 1; imenovalec = imenovalec + 2; // izpis Console.WriteLine("Nov ulomek je: " + stevec imenovalec); Console.Write("Press any key to continue . . . "); Console.ReadKey(true); } } }

"

"

Sedaj pa to naredimo e "objektno". Oitno bomo potrebovali razred Ulomek. Objekt tipa Ulomek hrani podatke o svojem tevcu in imenovalcu. Njegovo znanje je, da "se zna" poveati za drug ulomek. To pomeni, da vsebuje metodo, ki ta ulomek povea za drug ulomek. Shematsko bo program (kjer so doloeni deli skriti) videti kot

Cel program pa bo:

POVEAJMO

ULOMEK

OBJEKTNO

24: using System; 25: namespace UlomkiObjektno 26: { 27: class Ulomek { 28: public int stevec; 29: public int imenovalec; 30:
Programiranje 1 VS Informatika

C# . NET

18

31: public Ulomek(int st, int im) { 32: this.stevec = st; 33: this.imenovalec = im; 34: } 35: 36: public void Pristej(Ulomek a) { 37: this.stevec = this.stevec + a.stevec; 38: this.imenovalec = this.imenovalec + a.imenovalec; 39: } 40: } 41: class Program 42: { 43: public static void Main(string[] args) 44: { 45: // vnos podatkov 46: Console.Write("tevec ulomka: "); 47: string beri = Console.ReadLine(); 48: int stevec = int.Parse(beri); 49: Console.Write("Imenovalec ulomka: "); 50: beri = Console.ReadLine(); 51: int imenovalec = int.Parse(beri); 52: Ulomek moj = new Ulomek(stevec, imenovalec); 53: // "delo" 54: Ulomek polovica = new Ulomek(1, 2); 55: moj.pristej(polovica); 56: // izpis 57: Console.WriteLine("Nov ulomek je: " + moj.stevec + " / " + 58: moj.imenovalec); 59: } 60: } 61: }
e posebej oznaimo kljune toke (poleg definicije razreda Ulomek v vrsticah 4 17):

Objektno programiranje Imamo nek problem. Kako se torej lotiti nartovanja reitve s pomojo objektnega programiranja? Programiranje 1 VS Informatika

C# . NET

19

Z analizo ugotovimo, kakne objekte potrebujemo za reevanje Pregledamo, ali e imamo na voljo ustrezne razrede Standardna knjinica Druge knjinice Nai stari razredi Sestavimo ustrezne manjkajoe razrede Sestavimo glavni program, kjer s pomojo objektov reimo problem

Objekti, razredi, ...


Zdruevanje podatkov Denimo, da piemo program, ki bo pomagal upravljati farmo zajcev. Za vsakega zajca poznamo: serijsko tevilko spol teo Kako dosei, da se podatki drijo skupaj: Tabela ni ustrezna Tabela je zbirka istovrstnih podatkov Pri tabelah smo omenili, da so sestavljen podatkovni tip. Vsebujejo elemente istega tipa. Velikokrat pa elimo ustvariti tip, ki je prav tako sestavljen, a iz razlinih podatkovnih tipov. V ta namen imamo v jeziku C# tako imenovane strukture. A ker gre v bistvu le za posebni primer objektov, jih bomo kar preskoili in si raji kar neposredno ogledali objekte. Da pa boste vedeli zakaj gre, e boste v kaknem programu naleteli na kljuno besedo struct, si zapomnimo le, da gre za nekakne "poenostavljene" objekte. Sestavimo razred Zajec Opis podatkov, ki sestavljajo poljubnega zajca

V zgledih do sem smo razrede pisali le za "lokalno uporabo", znotraj doloenega programa. Sedaj se nauimo e, kako na najlaji nain gradimo svojo knjinico razredov, ki jih bomo uporabljali v razlinih programih. Na ta nain bomo tudi bolj loili tisti del programiranja, ko gradimo razrede in tisti del, ko uporabljamo objekte doloenega razreda. V okolju SharpDevelop tokrat ne izberemo Windows Applications/Console Application, ampak C# / Class Library

Programiranje 1 VS Informatika

C# . NET

20

Kot ime bomo napisali MojiRazredi. V ta projekt bomo dodajali vse tiste razrede, ki jih bomo ustvarjali, vkljuno z naim razredom Zajec.

Vidimo, da je SharpDevelop pripravil okolje in naredil tako imenovam imenski prostor MojiRazredi. Znotraj tega imenskega prostora bomo zlagali nae razrede. Ker nam ime MyClass ni ve, bomo to spremenili v Zajec. Omenimo e komentarje, ki se zano z ///. To so tako imenovani dokumentacijski komentarji. Ti sluijo za to, da pripravimo dokumentacijo o razredu. Ta je zelo pomembna, saj nosi tisto informacijo, ki jo kasneje potrebujemo, e elimo razred uporabljati. Zanekrat si zapomnimo le, da na ustrezno mesto napiemo kratek povzetek o tem, emu je razred namenjen. Ve o tem si lahko preberete: http://www.softsteel.co.uk/tutorials/cSharp/lesson19.html http://www.winnershtriangle.com/w/Articles.XMLCommentsInCSharp.asp http://www.csharphelp.com/archives3/archive598.html ...

RAZRED ZAJEC
21: public class Zajec { 22: public string serijska; 23: public bool spol; 24: public double masa; 25: }

Programiranje 1 VS Informatika

C# . NET

21

S tem imamo napisan opis, kako je doloen poljuben zajec: Nart, kakni so zajci Ni to konkreten zajec Ni metode Main, dejansko se NI ne izvede, ... Ni namenjeno poganjanju kot program. Zato bo stvar potrebno prevesti drugae. V Build izberemo Build Moji Razredi (oziroma pritisnemo na F9). S tem smo ustvarili ustrezno prevedeno obliko in sicer MojiRazredi.dll. TA vsebuje med drugim tudi definicijo razreda Zajec. Uporaba razreda Zajec Denimo, da sedaj piemo nek program, kjer bomo potrebovali Zajce. V ta namen sedaj sestavimo program v C#. Obnaamo se tako kot smo pisali programe do sedaj. v SharpDevelop: File/New Solution/Winows applications/Console Application Sedaj moramo dodati e t.i. referenco, da bo na program prepoznal na razred. Project / Add reference

Programiranje 1 VS Informatika

C# . NET

22

V oknu, ki se odpre, izberemo .Net Assembly Browser. Poiemo imenik MojiRazredi/bin/Debug in v njem datoteko MojiRazredi.dll.

Da bomo kraje pisali, dodamo sedaj imenski prostor MojiRazredi (ker vsebuje definicijo razreda Zajec)

using MojiRazredi;
e sedaj v programu potrebujemo konkretnega zajca, ga ustvarimo z new: new Zajec() Ustvaril se je konkreten zajec po navodilih za razred Zajec (ta zajec ima torej tri podatke / lastnosti / komponente) Metoda je vrnila naslov, kje ta konkretni zajec je Zajec rjavko = new Zajec(); V spremenljivki rjavko je naslov, kje je novo ustvarjeni zajec (objekt) Dostop do podatkov v objektu rjavko.spol = true; rjavko.serijska = BRGH_17_A; rjavko.masa = 3.2;

UPORABA

RAZREDA

ZAJEC

26: using System; 27: using MojiRazredi; 62:


Programiranje 1 VS Informatika

C# . NET

23

63: namespace TestZajec 64: { 65: class Program 66: { 67: public static void Main(string[] args) 68: { 69: Zajec z1 = new Zajec(); 70: z1.serijska = "1238-12-0"; 71: z1.spol = false; 72: z1.masa = 0.12; 73: z1.masa = z1.masa + 0.3; 74: Console.WriteLine("Zajec ima ser. t.:" + z1.serijska); 75: 76: Console.Write("Press any key to continue . . . "); 77: Console.ReadKey(true); 78: } 79: } 80: }

FARMAZAJCEV
28: public class FarmaZajcev { 29: public static void Main(atring[] ar) { 30: Zajec[] zajci = new Zajec[10]; // na farmi imamo do 10 zajcev 31: int i = 0; 32: while (i < 10) { 33: zajci[i] = new Zajec(); // rodil se je nov zajec 34: zajci[i].serijska = "1238-12- + i; 35: zajci[i].spol = false; 36: zajci[i].masa = 0.12; 37: i++; 38: } 39: ... 40: } 41: }

Programiranje 1 VS Informatika

C# . NET

24

Programiranje 1 VS Informatika

C# . NET

25

e en primer - Ulomek Denimo, da bi potrebovali e podatkovni tip Ulomek. Na projekt MojiRazredi (seveda bi lahko naredili novo knjinico razredov) dopolnimo z
RAZRED

ULOMEK

81: public class Ulomek { 82: public int stevec; 83: public int imenovalec; 84: }
Potem, ko z Build/Build MojiRazredi prevedemo stvar na novo, je knjinica z novim razredom Ulomek pripravljena za uporabo. To pomeni, da novi razred (e elite novi podatkovni tip) lahko uporabljamo v drugih programih, kot tudi pri sestavljanju drugih razredov. Ne pozabimo e elimo narediti objekt vrste (tipa) Ulomek, napiemo

Ulomek x = new Ulomek();


Kako napolniti stevec in imenovalec? x.stevec : spremenljivka tipa int! x.imenovalec : enako

x.stevec = 1; x.imenovalec = x.stevec + 1;


Programiranje 1 VS Informatika

C# . NET

26

No, ne pozabimo, da e doloen razred potrebujemo le v sklopu reitev enega primera, ga lahko ustvarimo tudi "lokalno", znotraj tistega programa.

PRIMER
42: 43: 44: 45: 46: 47: 48: 49: 50: 51: 52: 53: 54: 55: 56: 57: 58: 59: 60: 61:

IZDELAVE IN UPORABE RAZREDA

using System; public class Vozilo { public int letnik; public string proizvajalec; public int prevozeniKilometri; } class Program { public static void Main() { Vozilo mojAvto = new Vozilo();//kreiramo primerek mojAvto.proizvajalec = "Citron"; mojAvto.letnik = 2000; mojAvto.prevozeniKilometri = 90000; Console.WriteLine("Proizvajalec: " + mojAvto.proizvajalec); Console.WriteLine("Letnik: " + mojAvto.letnik); Console.WriteLine("Kilometri: " + mojAvto.prevozeniKilometri); } }

Razlaga. Najprej ustvarimo razred z imenom vozilo (vrstice 2-7). V glavnem programu kreiramo nov primerek (objekt) z imenom mojAvto razreda Vozilo (vrstica 12). Objektu doloimo vrednosti (vrstice 13-15) in izpiemo vrednosti (vrstice 16-18).

Povzetek Najenostavneji razred kreiramo tako, da doloimo spremenljivke, ki doloajo objekte tega razreda. Te so lahko razlinih podatkovnih tipov. Sintaksa najenostavneje definicije razreda je naslednja: public class ImeRazreda { public podatkovni tip element1; public podatkovni tip element2; public podatkovni tip elementn; } e elimo tak razred uporabljati v nekem programu, moramo v programu dodati referenco na ustrezno prevedeno obliko (dll) tega razreda. Objekt tega razreda ustvarimo z new ImeRazreda(); S tem dobimo naslov, kje ta objekt je in ga shranimo v spremenljivko tipa ImeRazreda: ImeRazreda imeObjekta = new ImeRazreda(); Do posameznih spremenljivk (reemo jim tudi komponente ali pa lastnosti), dostopamo z imeObjekta.imeKomponente Konstruktorji Ob tvorbi objekta bi radi nastavili zaetno stanje spremenljivk (in morda opravili e kaj a o tem kasneje). Programiranje 1 VS Informatika

C# . NET

27

V ta namen imamo v C# posebne metode, ki jih imenujemo konstruktorji. Konstruktor je metoda, ki jo pokliemo ob tvorbi objekta z new. Je brez tipa rezultata. To ne smemo zamenjati z metodami, ki rezuultata ne vraajo so tipa void). Konstruktor tipa rezultata sploh nima, tudi void ne. Prav tako smo omenjeni pri izbirri imena te metode. Konstruktor mora imenti ime nujno tako. kot je ime razreda. Najveja omejitev, ki loi konstruktorje od drugih metod pa je ta, da konstruktor ne moremo klicati na poljubnem mestu (kot lahko ostale metode). Kliemo ga izkljuno skupaj z new: Klic: new Zajec(); Razred Zajec

RAZRED ZAJEC

S KONSTRUKTORJEM

85: public class Zajec { 86: public string serijska; 87: public bool spol; 88: public double masa; 89: 90: // konstruktor 91: public Zajec() { 92: this.spol = true; // vsem zajcem na zaetku doloimo m. spol 93: this.masa = 1.0; // in tehtajo 1kg 94: this.serijska = NEDOLOENO; 95: } 96: }
this V zgornjem primeru smo v konstruktorju uporabili prijem, ki ga doselj e nismo sreali. Napisali smo this. Kaj to pomeni? this oznauje objekt, ki ga "obdelujemo". V konstruktorju je to objekt, ki ga ustvarjamo. this.spol se torej nanaa na lastnost/komponento spol objekta, ki se ustvarja (ki ga je ravno naredil new). Denimo, da v nekem programu napiemo

Zajec rjavko = new Zajec(); Zajec belko= new Zajec(); Pri prvem klicu se ob uporabi konstruktorja Zajec() this nanaal na rjavko, pri drugem na belko. Na ta nain (z this) se lahko sklicujemo na objekt vedno, kadar piemo metodo, ki jo izvajamo nad nekim
objektom. Denimo, da smo napisali

Random ng = new Random(); Random g2 = new Random(); Console.WriteLine(ng.Next(1,10)); Kako so programerji, ki so sestavljali knjinico in v njej razred Random lahko napisali kodo metode, da se je vedelo, da pri metodi Next mislimo na uporabo generatorja ng in ne na g2? Denimo, da imamo razred MojRazred (v njem pa komponento starost) in v njem metodo MetodaNeka. V programu, kjer razred MojRazred uporabljamo, ustvarimo dva objekta tipa MojRazred. Naj bosta to objA in objC. Kako se znotraj metode MetodaNeka sklicati na ta objekt (objekt, nad katerim je izvajana metoda)? e torej metodo MetodaNeka kliemo nad obema objektoma z objA.MetodaNeka() oziroma z
objC.MetodaNeka(), kako v postopku za metodaNeka povedati, da gre: Prvi za objekt z imenom objA drugi za objekt z imenom objC e se moramo v kodi metode metodaNeka sklicati recimo na komponento starost (jo recimo izpisati na zaslon), kako povedati, da naj se ob klicu objA.MetodaNeka() uporabi starost objekta objA, ob klicu objC.MetodaNeka() pa starost objekta objC?

Console.WriteLine("Starost je: " + ?????.starost);


Ob prvem klicu so ???? objA, ob drugem pa objC. To "zamenjavo" doseemo z this. Napiemo

Console.WriteLine("Starost je: " + this.starost);


Programiranje 1 VS Informatika

C# . NET

28

Ob prvem klicu this pomeni objA, ob drugem pa objC. Torej v metodi na tistem mestu, kjer potrebujemo konkretni objekt, nad katerim metodo izvajamo, napiemo this. Uporaba razreda: Kot smo povedali e vekrat, je razred le nart, kako so videti objkekti doloenega razreda. e potrebujemo konkreten primer, v naem primeru Zajca, ga ustvarimo z new:

new Zajec()
S tem se je ustvaril konkreten zajec (torej tak, ki ima tri spremenjlivke za hranjenje podatkov), nad katerim smo takoj potem izvdeli doloeno akcijo po navodilih iz konstruktorja Zajec(). Kombinacija new Zajec()je torej poskrbela, da ima objekt tipa Zajec tri podatke z vrednostmi, kot je predpisano v konstruktorju. Privzeti konstruktor e konstruktorja ne napiemo (kot ga nismo prej), ga naredi prevajalnik sam (a metoda ne naredi ni). Dokler je bil na razred zajec

RAZRED ZAJEC
1: 2: 3: 4: 5: public class Zajec { public string serijska; public bool spol; public double masa; }

je prevajalnik sam dodal privzeti kostruklor.

PRIVZETI

KONSTRUKTOR RAZREDA

ZAJEC

97: public Zajec() { 98: }


Kakor hitro pa smo konstruktor Zajec() napisali sami, se seveda prevajalnik ni ve "vmeaval": Ko smo napisali
RAZRED

ULOMEK

99: public class Ulomek { 100: public int stevec; 101: public int imenovalec; 102: }
je torej to enako, kot e bi napisali
RAZRED

ULOMEK

S PRIVZETIM KONSTRUKTORJEM

103: public class Ulomek { 104: public int stevec; 105: public int imenovalec; 106: 107: public Ulomek() { 108: } 109: }
Konstruktorjev ne moremo klicati posebej (kot ostale metode), ampak le, ko tvorimo objekt z new. Konstruktorje uporabljamo za vzpostavitev zaetnega stanja objekta. Ne pozabimo, da imajo enako ime kot razred. Nimajo tipa rezultata (tudi void ne!). Prat tako ne vsebujejo stavka return.

Programiranje 1 VS Informatika

C# . NET

29

Ve konstruktorjev Uporabniki bi poleg privzetega zajca, radi e monost, da bi takoj, ko zajca naredijo, temu doloili e serijsko tevilko. Radi bi torej konstruktor

public Zajec(string serijskaSt)


Poleg tega pa vasih na farmo dobijo tudi poiljko samic. Torej potrebujejo e konstruktor

public Zajec(bool spol)


Vasih pa so zajci "nestandardni"

public Zajec(string serijskaSt, bool spol, double teza)


Potrebovali bi torej, da ima razred ve konstruktorjev. A ker morajo imeti vsi konstruktorji ime tono tako, kot je ime razreda, to pomeni, da mora biti metoda

public Zajec(string serijskaStev, bool spol, double masa)


Ker pa imamo e od prej metodo

public Zajec()
to pomeni, da bi imeli ve metod z enakim imenom. Je to sploh mono? Jezik C# podpria tako imenovano preobteevanje (overloading) metod. Tako imamo lahko znotraj istega programa ve metod z enakim imenom. To ne velja le za konstruktorje, ampak tudi v splonem. Metode se morajo razlikovati ne v imenu, ampak podpisu. Podpis metode je sestavljen iz imena metode in tipov vseh parametrov. Konstruktor

Zajec()
ima torej podpis enostavno Zajec, konstruktor

public Zajec(string serijskaStev, bool spol, double masa)


pa podpis Zajec_string_bool_double Preobteene metode Kot smo omenili, so lahko preobteene tudi navadne metode (ne le konstruktorji). Prav tako enako velja e enkrat preobteenost oznauje monost, da imamo ve enako poimenovanih metod, ki pa sprejemajo parametre razlinega tipa. Zakaj je to uporabno? Denimo, da imamo metodo Ploscina, ki kot parameter dobi objekt iz razreda Kvadrat, Krog ali Pravokotnik. Kako jo zaeti?

public static double Ploscina(X lik)


Ker ne vemo, kaj bi napisali za tip parametra, smo napisali kar X. e preobteevanje ne bi bilo mono, bi morali napisati metodo, ki bi sprejela parameter tipa X, kjer je X bodisi Kvadrat, Krog ali Pravokotnik. Seveda to ne gre, saj prevajalnik nima naina, da bi zagotovil, da je X oznaka bodisi za tip Kvadrat, tip Krog ali pa tip Pravokotnik. Pa tudi e bi lo kako bi nadaljevali? V kodi bi morali rei ... e je lik tipa kvadrat, uporabi to formulo, e je lik tipa Krog spet drugo ... S preobteevanjem pa problem reimo enostavno. Napiemo tri metode

public static double Ploscina(Kvadrat lik) { public static double Ploscina(Krog lik) { public static double Ploscina(Pravokotnik lik) {
Ker za vsak lik znotraj ustrezne tono vemo, kaken je, tudi ni teav z uporabo pravilne forumule. Imamo torej tri metode, z enakim imenom, a razlinimi podpisi. Seveda bi lahko problem reili brez preobteevanja, recimo takole:

public static double PloscinaKvadrata(Kvadrat lik) { public static double PloscinaKroga(Krog lik) { public static double PloscinaPravokotnika(Pravokotnik lik) {
A s stalia uportabnika metod je uporaba preobteenih metod enostavneja. e ima nik lik bla, ki je bodisi tipa Kvadrat, tipa Krog ali pa tipa Pravokotnik, metodo poklie z Ploscina(bla), ne da bi mu bilo potrebno razmiljati, kakno je pravilno ime ustrezne metode ravno za ta lik. Prav tako je enostavneje, e dobimo e

Programiranje 1 VS Informatika

C# . NET

30

etrti tip objekta v glavno kodo ni potrebno posegati naredimo le novo metodo z istim imenom (Ploscina) in s parametrom katerega tip je novi objekt. Klic pa je e vedno Ploscina(bla)! Podpisi metod Podpis metode: Podpis: ime + tevilo in tipi parametrov! Tip rezultata (return tip) NI del podpisa!

public static int NekaMetoda(double x)


Podpis metode: public static int NekaMetoda(double x) Podpis: NekaMetoda_double interno ime Kaj je lahko soasno: public static int NekaMetoda() public static int NekaMetoda(double y) public static int NekaMetoda(double x) public static double NekaMetoda(double x) public static int nekaDrugaMetoda(double y) Konstruktorji razreda Zajec navzkrino sklicevanje Poglejmo, kako bi kostruktorje razreda Zajec napisali "zares".

KONSTRUKTORJI
62: 63: 64: 65: 66: 67: 68: 69: 70:

RAZREDA

ZAJEC

public Zajec() { this.spol = true; // vsem zajcem na zaetku doloimo m. spol this.masa = 1.0; // in tehtajo 1kg this.serijska = NEDOLOENO; } public Zajec(string serijskaStev) : this() { this.serijska = serijskaStev; }

71: public Zajec(string serijskaStev, 72: bool spol, double masa) : this(serijskaStev) { 73: this.masa = masa; // popravimo maso 74: this.spol = spol; // popravimo spol 75: }
Kljuna beseda this v zgornjem zgledu nastopa v dveh vlogah. Enkrat je uporabljena za ime objekta, kar e poznamo (this.spol, this.serijska ), novo pa je uporaba this( takoj za seznamom parametrov nekega konstruktorja. e malo o this o this( Za klic drugega konstruktorja pred vsemi ostalimi stavki drugega konstruktorja this() this(<parametri>) o this. Za dostop do lastnosti this.serijska e ni monosti zamenjave, lahko izpustimo Programiranje 1 VS Informatika

C# . NET

31

serijska this.spol = spol; Obstajalo je e DRUGO ime spol Loiti med spremenljivko spol, ki je parameter in lastnostjo objekta z imenom spol "Prednost" ima bolj "lokalna" stvar torej parameter spol = spol; Zgled Oglejmo si e en primer sestavljanja razredov. Denimo, da bi radi napisali program, ki vodi evidenco o lanih portnega kluba. Podatki o lanu obsegajo ime, priimek, letnico vpisa v klub in vpisno tevilke (seveda je to poenostavljen primer). Torej objekt, ki predstavlja lana kluba, vsebuje tiri podatke:

RAZRED CLAN
76: public class Clan { 77: public string ime; 78: public string priimek; 79: public int leto_vpisa; 80: public string vpisna_st; 81: }
S tem smo povedali, da je vsak objekt tipa Clan sestavljen iz tirih komponente: ime, priimek, leto_vpisa, vpisna_st. e je a objekt tipa Clan, potem lahko dostopamo do njegove komponente ime tako, da napiemo a.ime. Nov objekt naredimo z ukazom new, kot to kae naslednji primer:

TESTKLUB
82: public class TestKlub { 83: public static void Main(string[] args) { 84: 85: Clan a = new Clan(); 86: a.ime = "Janez"; 87: a.priimek = "Starina"; 88: a.leto_vpisa = 2000; 89: a.vpisna_st = "2304"; 90: 91: Clan b = new Clan(); 92: b.ime = "Mojca"; 93: b.priimek = "Mavko"; 94: b.leto_vpisa = 2001; 95: b.vpisna_st = "4377"; 96: 97: Clan c = b; 98: c.ime = "Andreja"; 99: 100: Console.WriteLine("Clan a:\n" + a.ime + " " 101: " " + a.leto_vpisa + " (" 102: 103: Console.WriteLine("Clan b:\n" + b.ime + " " 104: " " + b.leto_vpisa + " (" 105: 106: Console.WriteLine("Clan c:\n" + c.ime + " " 107: " " + c.leto_vpisa + " (" 108: Console.ReadLine(); 109: } 110: }
Programiranje 1 VS Informatika

+ a.priimek + + a.vpisna_st + ")\n"); + b.priimek + + b.vpisna_st + ")\n"); + c.priimek + + c.vpisna_st + ")\n");

C# . NET

32

Hm, kako to, da sta dva zadnja izpisa enaka? V programu smo naredili dva nova objekta razreda Clan, ki sta shranjena v spremenljivkah a in b. Kot vedno, se nove objekte naredi z ukazom new. Spremenljivka c pa je isti objekt kot b, se pravi, da se v 16. vrstici ni naredila nova kopija objekta b, ampak se spremenljivki b in c sklicujeta na isti objekt. In zato smo z vrstico 23 vplivali tudi na ime objekta b! V vrsticah 48 smo naredili objekt a in nastavili vrednosti njegovih komponent. Takole nastavljanje je v praksi dokaj neprimerno, ker se zlahka zgodi, da kako komponento pozabimo nastaviti. Zato C# omogoa, da delamo nove objekte na bolj praktien nain s pomojo konstruktorjev. Konstruktor je posebna metoda, ki ima enako ime kot je ime razreda. Konstruktor uporabimo v ukazu new. C# najprej naredi nov objekt, nato pa poklie konstruktor. Znotraj konstruktorja se pravkar narejeni objekt imenuje this. Primer:

111: public class Clan { 112: public string ime; 113: public string priimek; 114: public int leto_vpisa; 115: public string vpisna_st; 116: 117: public Clan(string i, string p, int l, string v) { 118: this.ime = i; 119: this.priimek = p; 120: this.leto_vpisa = l; 121: this.vpisna_st = v; 122: } 123: }
Poskusimo ali nae "pacanje" po razredu kaj vpliva na testni program. Ko poskusimo prevesti program, prevajalnik "protestira". Kako, kaj pa tisto govorjenje o tem, da spremembe razreda ne vplivajo na programe, ki razred le uporabljajo. Se je kje spremenilo kaj na nivoju sporoil? Saj jih v prvotnem programu sploh nimamo. Torej se ne bi smelo ni pokvariti! Razlog je v tem, da uporabimo privzeti konstruktor (Clan()), ki ga pa v razredu Clan nismo napisali. Ampak, saj ga prej tudi ni bilo? Kako je pa prej delovalo? Kot smo rekli e prej, e konstruktorja ne napiemo, C# sam doda konstruktor Clan(). Zato je prej zadeva delovala. Kakor hitro pa napiemo poljubni konstruktor, se C# ne vmeava ve. Zato sedaj ni sam dodal konstruktor Clan(), in testni program ne dela ve prav. V ta namen si je dobro zapomniti, da v razredih vedno napiemo tudi konstruktor Clan().

RAZRED CLAN 110: public class Clan { 111: public string ime; 112: public string priimek; 113: public int leto_vpisa; 114: public string vpisna_st; 115: 116: public Clan() {
Programiranje 1 VS Informatika

C# . NET

33

117: 118: 119: 120: 121: 122: 123: 124: 125: 126: 127: 128: 129: }

this.ime = "Ne vem"; this.priimek = "Ne vem"; this.leto_vpisa = 0; this.vpisna_st = "Ne vem"; } public Clan(string i, string p, int l, string v) { this.ime = i; this.priimek = p; this.leto_vpisa = l; this.vpisna_st = v; }

Ko sedaj poskusimo izvesti na testni program, teav ni ve in dobimo isti rezultat. A emu smo potem pisali e drugi konstruktor in zakaj smo se sploh ubadali z njimi, e pa je stvar enaka kot prej. Poglejmo ta testni program

TESTCLAN
130: public class TestClan{ 131: public static void Main(string[] args) { 132: Clan a = new Clan("Janez", "Starina", 2000, "2304"); 133: Clan b = new Clan("Mojca", "Mavko", 2001, "4377"); 134: Clan c = b; 135: c.ime = "Katarina"; 136: 137: Console.WriteLine("Clan a:\n" + a.ime + " " + a.priimek + 138: " " + a.leto_vpisa + " (" + a.vpisna_st + ")\n"); 139: 140: Console.WriteLine("Clan b:\n" + b.ime + " " + b.priimek + 141: " " + b.leto_vpisa + " (" + b.vpisna_st + ")\n"); 142: 143: Console.WriteLine("Clan c:\n" + c.ime + " " + c.priimek + 144: " " + c.leto_vpisa + " (" + c.vpisna_st + ")\n"); 145: } 146: }
Zgornji program deluje povsem enako kot prejnji testni program, je pa vsekakor bolj pregleden. Namen konstruktorja je, da nastavi vrednosti komponent objekta. Ker konstruktorji (pa tudi druge metode znotraj razreda) zelo pogosto dostopajo do komponent, nam C# omogoa, da namesto this.komponenta piemo kar komponenta:

RAZRED CLAN (BREZ THIS) 124: public class Clan { 125: public string ime; 126: public string priimek; 127: public int leto_vpisa; 128: public string vpisna_st; 129: 130: public Clan() { 131: ime = "Ne vem"; 132: priimek = "Ne vem"; 133: leto_vpisa = 0;
Programiranje 1 VS Informatika

C# . NET

34

134: 135: 147: 136: 137: 138: 139: 140: 141: 142: }

vpisna_st = "Ne vem"; } public Clan(string i, string p, int l, string v) { ime = i; priimek = p; leto_vpisa = l; vpisna_st = v; }

Objektne metode Svoj pravi pomen dobi sestavljanje razredov takrat, ko objektu pridruimo e metode, torej znanje nekega objekta. Kot e vemo iz uporabe vgrajenih razredov, metode nad nekim objektom kliemo tako, da navedemo ime objekta, piko in ime metode. Tako e elimo izvesti metodo WriteLine nad objektom System.Console napiemo

System.Console.WriteLine("To naj se izpie");


e elimo izvesti metodo Equals nad nizom besedilo, napiemo

besedilo.Equals(primerjava)
in tako dalje. Denimo, da potrebujemo metodo, ki vrne inicialke nekega lana. To bomo napisali takole:

METODA V RAZREDU CLAN 148: public string Inicialke() { 149: return this.ime[0] + "." + this.priimek[1] + "."; 150: }
Oglejmo si e uporabo te metode v nekem testnem programu:

TESTCLAN
151: public class TestClan{ 152: public static void Main(string[] args) { 153: Clan a = new Clan("Janez", "Starina", 2000, "2304"); 154: string inicialnkeClanaA = a.Inicialke(); 155: Console.Write("Clan a:\n" + a.ime + " " + a.priimek + 156: " " + a.leto_vpisa + " (" + a.vpisna_st + ") "); 157: Console.WriteLine("ima inicialke: " + inicialnkeClanaA); 158: } 159: }
Denimo, da smo kasneje ugotovili, da bi bili uporabniki razreda Clan veliko bolj zadovoljni, e bi metoda Inicialke vrnila niz brez pik, le s presledkom med zaetnico imena in priimka. Kaj storiti? Potrebno je popraviti le razred Clan, kjer spremnimo metodo

METODA V RAZREDU CLAN 160: public string Inicialke() { 161: return this.ime[0] + " " + this.priimek[0]; 162: }
Ko razred ponovno prevedemo, imamo e vse pripravljeno za "pravilno" izvajanje vseh tistih programov, ki uporabljajo ta razred. Brez kakrnekoli spremembe v uporabnikem programu (in tudi brez ponovnega prevajanja tega programa), metoda sedaj deluje v skladu z v razredu narejenimi spremembami. e torej opazimo, da je potrebno v razredu narediti kaken popravek, le vsem naim uporabnikom poljemo novo razliico prevedenega razreda (ali knjinice, ki vsebuje ta razred). Brez kakrnihkoli sprememb na strani uporabnika njihovi programi delujejo "popravljeno". Programiranje 1 VS Informatika

C# . NET

35

Vemo, da z

a = b;
kjer sta a in b obe spremenljivki tipa Clan, v a ne shranimo kopije objekta b, ampak sedaj a in b oznaujeta isti objekt. Zato napiimo metodo, ki naredi kopijo objekta. a = b.Kopija(); V a je nov objekt, ki pa ima iste podatke kot b.

KOPIJA

OBJEKTA

163: public Clan Kopija() { 164: Clan nov = new Clan(); 165: nov.ime = this.ime; 166: nov.priimek = this.priimek; 167: nov.leto_vpisa = this.leto_vpisa; 168: nov.vpisna_stevilka = 169: this.vpisna_stevilka; 170: }
Uporabna je tudi metoda, ki izpie objekt

IZPIS

OBJEKTA

171: public void Izpis() { 172: Console.WriteLine("Clan:\n" + this.ime + " " + 173: this.priimek + " " + this.leto_vpisa + 174: " (" + this.vpisna_st + ")\n"); 175: }
ali pa e

OPIS

OBJEKTA

176: public string Opis() { 177: return this.ime + " " + this.priimek + " " + 178: this.leto_vpisa + 179: " (" + this.vpisna_st + "); 180: }
e sedaj navedemo celotni razred

RAZRED CLAN
181: public class Clan { 182: public string ime; 183: public string priimek; 184: public int leto_vpisa; 185: public string vpisna_st; 186: 187: public Clan() { 188: ime = "Ne vem"; 189: priimek = "Ne vem"; 190: leto_vpisa = 0; 191: vpisna_st = "Ne vem"; 192: } 193: 194: public Clan(string i, string p, int l, string v) : this() { 195: ime = i; 196: priimek = p; 197: leto_vpisa = l;
Programiranje 1 VS Informatika

C# . NET

36

198: 199: 200: 201: 202: 203: 204: 205: 206: 207: 208: 209: 210: 211: 212: 213: 214: 215: 216: 217: 218: 219: 220: 221: 222: 223: 224: }

vpisna_st = v; } public string Inicialke() { return this.ime[0] + "." + this.priimek[0] + "."; } public Clan Kopija() { Clan nov = new Clan(); nov.ime = this.ime; nov.priimek = this.priimek; nov.leto_vpisa = this.leto_vpisa; nov.vpisna_stevilka = this.vpisna_stevilka; return nov; } public void Izpis() { Console.WriteLine("Clan:\n" + this.ime + " " + this.priimek + " " + this.leto_vpisa + " (" + this.vpisna_st + ")\n"); } public string Opis() { return this.ime + " " + this.priimek + " " + this.leto_vpisa + " (" + this.vpisna_st + "); }

In e zgled uporabe tega razreda

UPORABA RAZREDA CLAN


225: public class TestKlub { 226: public static void Main(string[] args) { 227: 228: Clan a = new Clan("Janez", "Starina", 2000, "2304"); 229: Clan b = new Clan("Mojca", "Mavko", 2001, "4377"); 230: Clan c = b; 231: c.ime = "Andreja"; 232: Clan d = b.Kopija(); 233: 234: Console.WriteLine("Clan a"); a.Izpis(); 235: Console.WriteLine("Clan b:\n" + b.Opis()); 236: Console.WriteLine("Clan c:\n" + c.Opis()); 237: Console.WriteLine("Clan d"); d.Izpis(); 238: Console.ReadLine(); 239: } 240: }

Programiranje 1 VS Informatika

C# . NET

37

Zgledi
Datum Denimo, da v naih programih pogosto delamo z datumi. Zato bomo sestavili ustrezni razred. Najprej moramo pripraviti nart razreda. Odloiti se moramo torej, kako bi hranili podatke o datumu. Podatki, ki sestavljajo datum, so: o dan (tevilo) o mesec (izbira: tevilo ali pa niz) o Leto (tevilo) Denimo, da se odloimo, da bomo dan in leto hranili kot tevilo, mesec pa kot niz (torej kot januar, februar, ...). Sedaj se moramo odloiti, katere metode bo poleg konstruktorjev poznal na razred. Nekaj idej: o Lepo izpii o Poveaj za 1 dan o Je datum smiselen o Je leto prestopno o Nov datum za toliko in toliko dni pred/za danim datumom o Dan v tednu o ... Potem, ko smo si pripravili nart, se lotimo sestavljanja razreda

RAZRED DATUM
241: public class Datum { 242: public int dan; 243: public string mesec; 244: public int leto; 245: public Datum() { 246: dan = 1; 247: mesec = "januar" 248: leto = 2000; 249: } // privzeti datum je torej 1.1.2000
Dodajmo e dva konstruktorja

250: 251: 252: 253: 254: 255: 256: 257:

public Datum(int leto) : this() { this.leto = leto; // this je nujen } // datum je torej 1.1.leto public Datum(int d, string m, int l) : this(l) { // leto smo e nastavili this.mesec = m; // this ni nujen this.dan = d; } // datum je torej d.m.l

Sedaj se lahko lotimo metod. Kot prvno, nas zanima, ali je leto prestopno

258: public bool JePrestopno() { 259: int leto = this.leto; 260: if (leto % 4 != 0) return false; 261: if (leto % 400 == 0) return true; 262: if (leto % 100 == 0) return false; 263: return true; 264: }
Vejih teav ni bilo. No, verjetno bolj uporabna pa bop metoda, ki bo dani datum poveala za en dan. To pomeni, da bomo objektu, nad katerim bomo metodo izvedli, poveali dan za 1. Potem pa se lahko zaplete, saj s tem lahko naredimo neobstoje datum, recimo 32. Januar. Sveda ne smemo pozabiti na prestopna leta. Lotimo se metode

Programiranje 1 VS Informatika

C# . NET

38

265: public void PovecajZaEnDan() { 266: dan = dan + 1; 267: if (dan < 29) return; 268: if (dan == 29 && mesec != "februar") return; 269: if (dan == 29 && mesec == "februar" && this.JePrestopno()) return; 270: // lahko nehamo, mesec in leto sta ok 271: string[] meseciPo30 = {"april","junij","september", "november"}; 272: if (dan == 31) { 273: if (meseciPo30.IndexOf(mesec) > 0){ 274: mesec = mesec + 1; 275: if (mesec == 13) { 276: mesec = 1; 277: leto++; 278: } 279: return; 280: } 281: // e je 32 dni, je zagotovo
Ko privandramo do sem, pa ugotovimo da imamo teave. Vrstica 34 je pa napana (sintaktino sicer pravilna, a pomensko povsem zgreena). Ker v spremenljivki mesec hranimo niz, bi morali namesto poveanja za 1 vzeti naslednje ime meseca. Tudi vrstica 35 je narobe .... Ko e enkrat premislimo, vidimo, da bi lo z manj truda, e bi si tudi za mesec namesto imena meseca raje zapomnili kar tevilko. e elimo datum videti z imeni mesecev pa za to lahko poskrbimo denimo ob izpisu. Zato se spodobi lotiti stestavljanja razreda datum znova. Vendar to, kot tudi preostale metode z naega spiska, prepustimo bralcu v izziv. Denimo, da smo razred Datum uspeno naredili. Sedaj pa ga e koristno uporabimo. Denimo, da elimo ugotoviti, e je letonje leto prestopno. Dovolj bo, e le naredimo objekt, v katerega shranimo katerikoli letonji datum in pokliemo pripravljeno metodo JePrestopno().

JE

LETONJE LETO PRESTOPNO

282: using MojiRazredi; 283: public class JeLetosPrestopnoLeto { 284: Datum danes = new Datum(22, 1, 2008); 285: if (danes.jePrestopno()) { 286: Console.WriteLine("Je prestopno leto"); 287: } else { 288: Console.WriteLine("Ni prestopno leto"); 289: } 290: }
Fibonaccijevo zaporedje V naravi vekrat opazimo zanimive vzorce. Tako e gremo teti koliko je zrn v posamezni spirali sonninega cveta pa tudi npr v tevilu lusk ananasa, brovega stora, semen na jagodi ... dobimo zanimivo zaporedje, ki ga imenujemo Fibonnaccijevo zaporedje. Fibonaccijeva tevila definiramo z zaetnima pogojema (prvo in drugo tevilo sta enaka 1) ter z rekurzivno formulo (n-to Fibonaccijevo tevilo je vsota prejnjih dveh) . S temi podatki lahko izraunamo vsa ostala tevila. Fibonaccijevo zaporedje je torej 1, 1, 2, 3, 5, 8, 13, 21, 34, 55, 89, ... e zaetna pogoja spremenimo (rekurzivno pravilo pa ostane isto), dobimo posploena Fibonaccijeva tevila. e si npr. za prvo tevilo izberemo 3 in za drugo -1 dobimo zaporedje tevil 3, -1, 2, 1, 3, 4, 7, 11... Sestavimo razred PosploseniFibonacci, ki bo vseboval metodo public int VrniNto(int n), ki bo izraunal n-to posploeno Fibonaccijevo tevilo. Razred naj vsebuje dva konstruktorja: publicPosploseniFibonacci() - ta naj za zaetni pogoj postavi pogoj za obiajna Fibonaccijeva tevila.

Programiranje 1 VS Informatika

C# . NET

39

public PosploseniFibonacci(int prvo, int drugo) - temu podamo vrednosti prvega in drugega posploenega Fibonaccijevega tevila. e torej ustvarimo objekta PosploseniFibonacci fibo = new PosploseniFibonacci() in PosploseniFibonacci splosni = new PosploseniFibonacci(3, -1) nam klica metod fibo.VrniNto(4) in splosni.VrniNto(4) vrneta 3 oz. 1. Hraniti bo potrebno zaetna lena

RAZRED POSPLOENIFIBONACCI
291: public class PosploseniFibonacci { 292: public int prvo; 293: public int drugo; 294: 295: public PosploseniFibonacci() { 296: this.prvo = 1; 297: this.drugo = 1; 298: } 299: 300: public PosploseniFibonacci(int p, int d) { 301: this.prvo = p; 302: this.drugo = d; 303: }
Metoda bo enostaven primer uporabe rekurzije

304: public int VrniNto(int n) { 305: if (n == 1) return this.prvo; 306: if (n == 2) return this.drugo; 307: return this.VrniNto(n 2) + 308: this.VrniNto(n 1); 309: }
Tako, konali smo. A ni nam preve ue hitrost tega naega razreda. Bi lo hitreje? Zelo pogosto potrebujemo prvih 20 lenov Fibonnacijevega zaporedja, ostala pa bolj redko. Kaj storiti, da izboljamo odzivnost? Naj objekt hrani tabelo prvih 20 lenov, e potem uporabimo VrniNto(i) in je i <= 20, le pogledamo v tabelo. Le v tistih izjemni primerih, ko potrebujemo kasneje lene pa uporabimo rekurzijo. Kje narediti tabelo? Seveda v konstruktorju, saj mora ta poskrbeti za zaetne nastavitve!

IZBOLJANI RAZRED POSPLOENIFIBONACCI


310: public class PosploseniFibonacci { 311: public int[] tabela = new int[20] 312: public PosploseniFibonacci() { 313: tabela[0] = tabela[1] = 1; 314: for (int i = 2; i < 20; i++) { 315: tabela[i] = tabela[i 2] + tabela[i - 1]; 316: } 317: } 318: public PosploseniFibonacci(int p, int d) { 319: tabela[0] = p; 320: tabela[1] = d; 321: for (int i = 2; i < 20; i++) { 322: tabela[i] = tabela[i 2] + tabela[i - 1]; 323: } 324: } 325: public int VrniNto(int n) { 326: if (n < 20) return this.tabela[n 1]; // e imamo e naraunanao 327: return this.VrniNto(n 2) + // sicer uporabi rekurzijo 328: this.VrniNto(n 1);
Programiranje 1 VS Informatika

C# . NET

40

329: } 330: }

Vaje
Kochova rta

Sestavi metodo, ki s pomojo rekurzije izrauna dolino vodoravne Kochove rte stopnje N, ki jo nariemo od koordinate x1 do koordinate x2. Na osnovi prejnje metode sestavi metodo, ki izrauna dolino Kochove rte, ki gre od toke T1 s koordinatami (x1,y1) do toke T2 s koordinatami (x2, y2). Namig: sestavi metodo, ki ima 5 parametrov: n, x1, x2, y1 in y2.
Razred Toka in Kochova rta

Pri prvi podtoki naloge 1 se koordinati x in y nista "drali" skupaj. Zato sestavi razred, ki vsebuje koordinato x in y in metodo iz naloge 1 prepii tako, da bo imela tri parametre: n (stopnjo rte), T1 in T2 (ki sta tipa Tocka, ki si ga ravno sestavil).
Ulomek

Sestavite razred Ulomek in napiite metodo, ki ustvari tabelo nakljunih ulomkov s tevci med 1 in 10 ter imenovalci med 1 in 10. Velikost tabele naj bo parameter metode. Nato napiite e eno metodo, ki v tabeli ulomkov poie najveji ulomek. e tretja metoda pa naj zna izpisati ulomek. Vse skupaj pa zloite v program, ki v tabeli nakljunih ulomkov velikosti 20 izpie vse ulomke, ki so (matematino) enaki najvejemu ulomku. e je npr. najveji ulomek 2/4, naj program izpie (seveda, e so v tabeli) tudi vse pojavitve ulomkov 1/2, 3/6, 5/10 in 4/8.
Razred Majica

Sestavite razred Majica, ki hrani osnovne podatke o majici:


o o o

velikost: tevilo med 1 in 5, barvo: poljuben niz in ali ima majica kratke ali dolge rokave.

Razred mora tudi poznati metode za nastavljanje in branje teh vrednosti. Podpisi teh metod naj bodo: public int VrniVelikost() ter public void SpremeniVelikost(int velikost) o public string VrniBarvo() ter public void SpremeniBarvo(string barva) o public boolean ImaKratkeRokave() ter public void NastaviKratkeRokave(boolean imaKratkeRokave)
o

Napii testni program, ki naredi tabelo 100 razlinih majic. Potem prepii to tabelo v datoteko tako, da podatke o vsaki majici zapie v svojo vrstico.
Programiranje 1 VS Informatika

C# . NET

41

Nato razred Majica dopolni s konstruktorjem, ki kot parameter dobi niz v takni obliki, kot si podatke zapisal na datoteko in v skladu s podatki v tem nizu nastavi ustrezne podatke o majici. Testni program potem dopolni tako, da potem, ko si podatke o majicah zapisal na datoteko, naredi novo tabelo 100 majic, ki pa podatke o teh majicah prebere s pravkar ustvarjene datoteke. Celotni program zakljui s tem, da napie e metodo, ki preveri, e sta obe tabeli enaki!
Razred Zajec

Denimo, da piemo program, ki bo pomagal upravljati farmo zajcev. Za vsakega zajca poznamo serijsko tevilko, spol in maso. Sestavi razred Zajec, ki vsebuje komponente:

//vrednost true, e je zajec mokega spola in false, e enskega (kaj hoete, moki ovinisti ...) masa //masa zajca v kilogramih (tip double) serijska //serijska tevilka zajca (tip String)
spol

Sestavi program, ki naredi tri zajce s teami, ki so nakljuna tevila med 1.2 in 5.5. Izpii vse tri tee zajcev. Enemu poveaj njegovo teo za 2kg. Izpii serijsko tevilko najlajega zajca.
Razred Kolega

Sestavi razred Kolega, ki ima tri komponente:


ime priimek telefonska tevilka

Vse tri komponente naj bodo tipa String in javno dostopne. Napii konstruktor:

ki vse tri komponente nastavi na "NI PODATKOV".

Sestavi testni program, v katerem ustvari dva objekta tipa Kolega. Oba objekta tudi izpii na zaslon.
Uporaba razreda Kolega

Napii program, ki sestavi tabelo 10ih objektov tipa Kolega, prebere telefonsko tevilko in izpie tiste objekte iz tabele, ki imajo tako telefonsko tevilko. e takega objekta v tabeli ni, naj se izpie: "Noben moj kolega nima take telefonske tevilke."
Programiranje 1 VS Informatika

C# . NET

42

Uporaba razreda Zajec

Sestavi program, ki ustvari farmo zajcev (tabelo n zajcev) in med njimi izpie: 1. 2. 3. 4.
Datum

najtejega najcenejega vse zajklje najtejega samca

Denimo, da v naih programih pogosto delamo z datumi. Zato bomo sestavili ustrezni razred. Vsebuje naj le dva konstruktorja.
Zajci z datumom

Razred Zajec nadgradi tako, da bo za vsakega zajca tudi hranil datum, klo se je skotil in datum, ko je bil zadnji pregledan.
Uporaba razreda Zajec z datumom Ustvari farmo zajcev in na njej poii vse tiste zajce, ki v tem koledarskem letu e niso bili pregledani. Nato pa izpii e tiste zajklje, ki so bile se skotile v obdobju enega leta (torej med 23. 1. 2007 in 22. 1. 2008. Nadgradimo datum

Razred Datum nadgradimo tako, da naj poleg kostruktorjev pozna naslednje metode Lepo izpii Poveaj za 1 dan Je datum smiselen Je leto prestopno Vrni nov datum za toliko in toliko dni pred danim datumom Vrni nov datum za toliko in toliko dni za danim datumom Vrni dan v tednu ...

Dostop do stanj objekta


Monost, da neposredno dostopamo do stanj/lastnosti objekta ni najbolji! Glavni problem je v tem, da na ta nain ne moremo izvajati nobene kontrole nad pravilnostjo podatkov o objektu! Tako lahko za naega zajca rjavka v programu mirno napiemo rjavko.masa = -3.2; Ker ne moremo vedeti, ali so podatki pravilni, so vsi postopki (metode) po nepotrebnem bolj zapleteni, oziroma so nai programi bolj podvreni napakam. Ideja je v tem, da naj objekt sam poskrbi, da bo v pravilnem stanju. Seveda potem moramo tak neposreden dostop do spremenljivk, ki opisujejo objekt, prepreiti. Dodatna teava pri neposrednem dostopu do spremenljivk, ki opisujejo lastnosti objekta se pojavi , e moramo kasneje spremeniti nain predstavitve podatkov o objektu. S tem bi "podrli" pravilno delovanje vseh starih programov, ki bi temeljili na prejnji predstavitvi.

Programiranje 1 VS Informatika

C# . NET

43

Torej bomo, kot smo omenjali e v uvodu, objekt res imeli za "rno katlo", torej njegove notranje zgradbe ne bomo "pokazali javnosti". Zakaj je to dobro? e malo pomilsimo, uporabnika razreda pravzaprav ne zanima, kako so podatki predstavljeni. e podamo analogijo z realnim svetom: Ko med vonjo avtomobila prestavimo iz tretje v etrto prestavo, nas ne zanima, kako so prestave realizirane. Zanima nas le to, da se stanje avtomobila (prestava) spremeni. Ko kupimo nov avto nam je naeloma vseeno, e ima ta drugano vrsto menjalnika, z drugano tehnologijo. Pomembno nam je le, da se nain prestavljanja ni spremenil, da e vedno v takih in takoh okoliinah prestavimo iz tretje v etrto prestavo. S "skrivanjem podrobnosti" omogoimo, da e pride do spremembe tehnologije se za uporabnika se stvar ne spremeni. V naem primeru programiranja v C# bo to pomenilo, da e spremenimo razred (popravimo knjinico), se za uporabnike razreda ne bo ni spremenilo. Denimo, da so v C# 3.0 spremenili nain hranjenja podatkov za doloanje nakljunih tevi v objektih razreda Random. Ker dejansko nimamo vpogleda (neposrednega dostopa) v te spremenljivke, nas kot uporabnike razreda Random ta sprememba ni ne prizadane. Programe e vedno piemo na enak nain, kliemo iste metode. Skratka - ni potrebno spreminjati programov, ki razred Random uporabljajo.e posebej je pomembno, da programi, ki so delovali prej, e vedno delujejo (morda malo bolje, hitreje, a bistveno je, da delujejo enako). In e enkrat .- s tem ko "ne dovolimo" vpogleda v zgradbo objekta, lahko poskrbimo za zaito pred nedovoljenimi stanji. Do sedaj smo spremenljivke, ki opisujejo objekt, kazali navzven (imele so doloilo public). To pomeni, da uporabnik lahko neposredno dostopa do teh spremenljivk in morebiti objekt spravi v nemogoe stanje: mojAvto.prestava = -10; Dostopi do stanj Do sedaj smo pisali programe tako, da smo naredili objekt. Ko smo eleli v objekt zapisati kak podatek, smo uporabili zapis

ime_objekta.stanje = <izraz>;

DOSTOP

DO PODATKOV

331: public class TestClan{ 332: public static void Main(string[] args) { 333: Clan novClan = new Clan(); 334: novClan.ime = "Katarina"; 335: novClan.leto_vpisa = 208; 336: } 337: }
Problem s takim pristopom nam kae ravno vrstica 5. Ker smo se zatipkali in vnesli nemogo podatek, objekt novClan sedaj hrani napaen podatek. Radi pa bi, da take tipkarske napake "polovimo". Seveda bi lahko rekli v redu, napisali bomo metodo, s katero bomo nastavljali leto vpisa in v metodi preverili, e je podatek smiselen. Takega pristopa smo se do sedaj e vekrat posluili v zgledih in vajah. e sedaj ponovno napiemo razred Clan, le da dodamo metodo za nastavljanjen leta vpisa

RAZRED CLAN

Z METODOZA DOLOANJE LETA VPISA

338: public class Clan { 339: public string ime; 340: public string priimek; 341: public int leto_vpisa; 342: public string vpisna_st; 343: 344: // konstruktorji in metode kot prej! 345: public bool SpremeniLetoVpisa(int leto) { 346: if ((2000 <= leto) && (leto <= 2020)) { 347: this.leto_vpisa = leto; 348: return true; //leto je smiselno, popravimo stanje objekta in vrnemo
true Programiranje 1 VS Informatika

C# . NET

44

349: 350: 351:

} return false; // leto ni smiselno, ne spremenimo ni in vrnemo false }

352: } In e zgled uporabe tega razreda

SPREMINJANJE

Z METODO

353: public class TestKlub { 354: public static void Main(string[] args) { 355: 356: Clan novClan = new Clan(); 357: novClan.ime = "Katarina"; 358: novClan.leto_vpisa = 2007; 359: novClan.SpremeniLetoVpisa(208); 360: novClan.SpremeniLetoVpisa(2008);

Sedaj v 7. vrstici ne bomo podatka popravili na napanega, ker letnica ni ustrezna, v 8. vrstici pa je bila sprmememba uspena. e bi eleli, bi to, ali je sprememba uspela, lahko tudi preverili tako, da bi pogledali, kakno vrednost je vrnila metoda. Po drugi strani pa e iz vrstice 6 vidimo, da je naa "zaita" zelo pomanjkliva. e bi napisali e

361:

novClan.leto_vpisa = 20008;

bi se vrstica veselo izvedla in spet bi imeli v objektu napaen podatek. e bi torej prepreili uporabo

ime_objekta.stanje = <izraz>;
in bi se stanje spremenljivk, ki opisujejo objekt lahko spreminjalo le preko metod, bi lahko poskrbeli, da bi pred spremembo podatka izvedli ustrezne kontrole in v primeru poskusa nastavljanja napanih podatkov ustrezno reagirali. Po drugi strani pa tudi ni dobro, da se ime_objekta.stanje pojavi kjerkoli. Denimo, da imamo v nekem programu napisano

if (enClan.leto_vpisa > drugClan.leto_vpisa) {


Kasneje pa ugotovimo da moramo razred Clan spremeniti in namesto leta_vpisa hraniti kompleten datum vpisa. Ni problema, sprememba par vrstic kode knjinice MojiRazredi v razredu Clan in e je tukaj nov razred Clan

RAZRED CLAN

Z DATUMOM

362: public class Clan { 363: public string ime; 364: public string priimek; 365: public Datum datum_vpisa; 366: public string vpisna_st; 367: 368: public Clan() { 369: ime = "Ne vem"; 370: priimek = "Ne vem"; 371: datum_vpisa = new Datum(); 372: vpisna_st = "Ne vem"; 373: } 374: 375: public Clan(string i, string p, Datum d, string v) : this() { 376: ime = i; 377: priimek = p;
Programiranje 1 VS Informatika

C# . NET

45

378: datum_vpisa = d; 379: vpisna_st = v; 380: } 381: 382: public string Inicialke() { 383: return this.ime[0] + "." + this.priimek[0] + "."; 384: } 385: 386: public Clan Kopija() { 387: Clan nov = new Clan(); 388: nov.ime = this.ime; 389: nov.priimek = this.priimek; 390: nov.datum_vpisa = this.datum_vpisa.Kopija(); 391: nov.vpisna_stevilka = this.vpisna_stevilka; 392: Return nov; 393: } 394: 395: public void Izpis() { 396: Console.WriteLine("Clan:\n" + this.ime + " " + 397: this.priimek + " " + this.Datum_vpisa.OpisDat() + 398: " (" + this.vpisna_st + ")\n"); 399: } 400: 401: public string Opis() { 402: return this.ime + " " + this.priimek + " " + 403: this.datum_vpisa.OpisDat() + " (" + this.vpisna_st + "); 404: } 405: public bool SpremeniLetoVpisa(int l) { 406: if ((2000 <= leto) && (leto <= 2020)) { 407: this.datum_vpisa.leto = l; 408: return true; //leto je smsielno, popravimo stanje onbjekta in vrnemo
true 409: 410: 411: } return false; // leto ni smsielno, ne spremnimo in in vrnemo false }

412: }
Preden nadaljujemo, opozorimo na vrstico 29. e bi tam napisali

nov.datum_vpisa = this.datum_vpisa;
bi bilo to narobe. V novem objektu bio namre ne hranili novega datuma, ampak bi le kazali na isti datum, kot ga vsebuje obstojei objekt. In e bi potem kasneje spremnili datum v kateremoli od teh objektov, bi se spremil za oba objekta, saj gre za isti datum. Zato smo v 29. vrstici naredili tudi kopijo datuma! Dodatno razlago morda zahtevata e zapisa

this.datum_vpisa.Kopija();
in

this.Datum_vpisa.OpisDat()
Pa ni ni udnega. this pa oznauje objekt, nad katerim bomo izvajali metodo. Ta objekt ima polje datum_vpisa. This.datum_vpisa je torej objekt tipa Datum. V tem razredu imamo metodi Kopija() in OpisDat(), ki ju izvedemo nad tem objektom. Pri vrstici 45

this.datum_vpisa.leto = l;
je podobno. this.datum_vpisa je objekt tipa Datum, torej ima polje leto. Programiranje 1 VS Informatika

C# . NET

46

Vrnimo se k razlagi, zakaj ni dobro, da je uporabnik razreda Clan v svojem programu napisal npr.

if (enClan.leto_vpisa > drugClan.leto_vpisa) {


e bi ta uporabnikov program sedaj poskusili uporabiti z naim razredom, pa seveda ne bi lo, saj polja leto_vpisa sploh ni ve! Zaradi spremembe tehnologije (spremembe razreda Clan) torej stari programi (ki uporabljajo razred Clan) ne delujejo ve. Kako pa bi morali potem pisati? e prej bi morali v razredu Clan ponuditi metodo, ki vrne leto vpisa.

RAZRED CLAN

Z METODAMA ZA DOLOANJE/VRAANJE LETA VPISA

413: public class Clan { 414: public string ime; 415: public string priimek; 416: public int leto_vpisa; 417: public string vpisna_st; 418: 419: public bool SpremeniLetoVpisa(int leto) { 420: if ((2000 <= leto) && (leto <= 2020)) { 421: this.leto_vpisa = leto; 422: return true; //leto je smsielno, popravimo stanje onbjekta in vrnemo
true 423: 424: 425: } return false; // leto ni smsielno, ne spremnimo in in vrnemo false }

426:
427: 428:

public int VrniLetoVpisa() {


return this.leto_vpisa; }

429: }
"Pametni" uporabniki naega razreda bi potem seveda programirali z

if (enClan.VrniLetoVpisa() > drugClan.VrniLetoVpisa()) {


e bi potem prilo do omenjene zamenjave tehnologije (leto nadomeeno z datumom), bi seveda lahko poskrbeli, da bi prav delovali tudi pametno napisani programi. V razredu Clan bi seveda imeli nekaj dela, da bi ustrezno popravili vse metode, a temu se ob "sprmemebi tehnologije" seveda ne da izogniti saj ravno to hoemo!

METODA VRNILETOVPISA
430:
431: 432: }

V RAZREDU

CLAN

Z DATUMOM

public int VrniLetoVpisa() {


return this.datum_vpisa.leto;

Ker je metoda VrniLetoVpisa "na zunaj" (torej za uporabnike) enaka kot prej, programi, kli so jo uporabljali, delujejo pravilno. Problem pa je v besedi "pametni uporabnik". Namre pri tako sestavljenem razredu nihe ne prepreuje uporabniku, da ne bi napisal kar

if (enClan.datum_vpisa.letoa > drugClan.datum_vpisa.leto) {


in morebiti kasneje spret povzroil, da ob e eni spremebi razreda Clan spet stvari ne bi delovale. e torej povzamemo. Uporabniki razredov konstrukta

ime_objekta.stanje
naj sploh ne bi nikoli uporabljali. Zakaj je to lahko problem? zunanji uporabnik nastavi napano vrednost: z1.masa = -100.10; Uporabnik pozna predstavitev: Kasneje je ni mogoe spremeniti No na sreo pa imamo monost, da dostop do spremenljivk lahko nadziramo. V C# poznamo 4 naine dostopa:

public private
Programiranje 1 VS Informatika

C# . NET

47

protected internal
Zadnjih dveh mi ne bomo uporabljali, zato si njihov pomen in uporabo oglejte kar sami. Dostop public smo e ves as uporabljali, saj smo pisali na primer: o o public string serijska; public double masa;

Besedi public pomenita, da do teh dveh spremenljivk dostop ni omejen (je javen public). e tega ne elimo , public zamenjamo s private o private string serijska; o private int[] tab; o private Datum datumRojstva; Vasih besedo, ki oznauje nain dostopa (javen ali privaten) spustimo in napiemo le o bool spol; Kaken dostop velja takrat, je odvisno od okoliin. Obiajno bo to kar public, ne pa vedno. Zato se opuanju navedbe dostopa izogibajmo in ga piimo vedno. Zakaj bi zgubljali as s premiljevanjem o tem, v kaknih okoliinah je ta spremenjlivka in kaken bo potem dostop do nje. Oglejmo si sedaj razliko med public in private. Zavedati pa se moramo, da znotraj razreda (torej ko sestavljamo razred in piemo njegove metode) ni omejitev, vedno (ne glede na nain dostopa) je moen dostop do komponent. Omejitve pri nainu dostopa veljajo le, ko objekte doloenega razreda uporabljamo torej v drugih programih in razredih! public e je nain dostopa nastavljen na public, to pomeni, da do lastnosti (komponent, spremnljivk, polj ...) lahko dostopajo vsi, od kjerkoli (iz katerihkoli datotek (razredov)) in sicer z

ime_objekta.lastnost
Denimo, da smo v razredu MojObjekt napisali public int javnaLastnost; Kdorkoli naredi objekt vrste MojObjekt: MojObjekt x = new MojObjekt(); lahko dostopa do javnaLastnost: x.javnaLastnost Ta nain smo uporabljali do sedaj. private Dostop private pomeni, da do lastnosti ne more dostopati nihe, razen metod znotraj razreda. Ko piemo nart razreda, sevedda lahko napiemo this.lastnost lastnost Denimo, da smo v razredu MojObjekt napisali private int privatnaLastnost; e kdo naredi objekt vrste MojObjekt: MojObjekt x = new MojObjekt();

Programiranje 1 VS Informatika

C# . NET

48

bo ob poskusu dostopa do privatnaLastnost: x.privatnaLastnost prevajalnik javil napako. Zgledi

RAZRED ZAJEC
143: 144: 145: 146: 147: 148: 149: 150: 151: 152: 153: 154: 155: 156: 157: 158: public class Zajec { public string serijska; // serijska stevilka zajca public bool spol; // true = moski, false = zenska private double masa; // masa zajca ob zadnjem pregledu } public class Zajnik { public static void Main(String[] ar) { Zajec z1 = new Zajec(); z1.serijska = "1238-12-0; z1.spol = false; z1.masa = 0.12; z1.masa = z1.masa + 0.3; System.Console.WriteLine(Zajec ima ser. t.: + z1.serijska); } }

RAZRED ZAJEC2
159: public class Zajec2 { 160: public string serijska; // serijska stevilka zajca 161: public bool spol; // true = moski, false = zenska 162: private double masa; // masa zajca ob zadnjem pregledu 163: 164: public SpremeniTezo(double x) { 165: this.masa = x; 166: } 167: 168: }

UPORABA RAZRED ZAJEC2


169: public class Zajnik { 170: public static void Main(string[] ar) { 171: Zajec z1 = new Zajec2(); 172: z1.serijska = "1238-12-0; 173: z1.spol = false; 174: z1.SpremeniTezo(0.11); 175: z1.masa = 0.12; 176: z1.masa = z1.masa + 0.3; 177: System.Console.WriteLine(Zajec ima ser. t.: + z1.serijska); 178: } 179: }
Dostop do stanj/lastnosti Odloili smo se torej, da bomo iz objektov naredili rne katle. Uporabnikom bomo s private prepreili, da bodo "kukali" v zgradbo objektov doloenih razredov. e bodo eleli dostopati do lastnosti (podatkov) objekta (zvedeti, kakne podatke v objektu hranimo) ali pa te podatke spremeniti, bodo morali uporabljati metode. In v teh metodah bo sestavljalec razreda lahko poskrbel, da se s podatki "ne bo kaj udnega poelo". Programiranje 1 VS Informatika

C# . NET

49

Potrebujemo torej: Metode za dostop do stanj (za dostop do podatkov v objektu) Metode za nastavljanje stanj (za spreminjanje podatkov o objektu) Prvim pogosto reemo tudi "get" metode (ker se v razredih, ki jih sestavljajo angleko usmerjeni pisci, te 1 metode pogosto prino z Get (Daj) ). Druge pa so t.i. "set" metode (set / nastavi) . Ponovimo e enkrat, zakaj je pristop z get in set metodami bolji od uporabe javnih spremenljivk. Spotoma pa bomo navedli e kak razlog in (upamo) prepriali e zadnje dvomljvce, ki se tako teko poslovijo od javnih spremenljivk. Razlogi, zakaj je dostop do podatkov v objektu preko metod bolji kot neposredni dostop (preko javnih spremenljivk) so med drugim: Monost kontrole pravilnosti! Monost kasneje spremembe naina predstavitve (hranjenja podatkov). Monost oblikovanja pogleda na podatke: Podatke uporabniku posredujemo drugae, kot jih hranimo. Tako denimo v razredu Datum mesec hranimo kot tevilo, proti uporabniku pa je zadeva videti, kot bi uporabljali besedni opis meseca. Dostop do doloenih lastnosti lahko omejimo: Npr. spol lahko nastavimo le, ko naredimo objekt (kasneje pa uporabnik spola sploh ne more spremeniti, saj se ne spreminja ... e odmislimo kakne operacije, doloene vrste ivali ... seveda) Hranimo lahko tudi doloene podatke, ki jih uporabnik sploh ne potrebuje .. Nastavitve podatkov (stanj) Potrebujemo torej metode, ki bodo nadomestile prireditveni stavek. Za tiste podatke, za katere elimo, da jih uporabnik spreminja, napiemo ustrezno set metodo. Na primer: zajcek.SpremeniTezo(2.5); V bistvu smo s tem dosegli isto kot prej s prireditvenim stavkom zajcek.masa = 2.5; A metoda spremeniTezo lahko PREVERI, e je taka sprememba tee smiselna! Tako je zapis zajcek.SpremeniTezo(-12.5); naeloma nadomestek stavka zajcek.masa = -12.5; Vendar gre tu za bistveno razliko. Prireditveni stavek se bo zagotovo izvedel (in bo s tem zajec nevarno shujal). Pri spreminjanju tee zajca z metodo, pa lahko prepreimo postavitev lastnosti objekta v napano stanje! V metodi SpremeniTezo lahko izvedemo ustrezne kontrole in e sprememba ni smislena, je sploh ne izvedemo.

RAZRED ZAJEC SPREMENITEZO


433: public void SpremeniTezo(double novaTeza) { 434: // smiselna nova teza je le med 0 in 10 kg 435: if ((0 < novaTeza) && (novaTeza <= 10)) 436: this.masa = novaTeza; 437: // v nasprotnem primeru NE spremenimo tee 438: } 439: 440: public bool SpremeniTezo(double novaTeza) { 441: // smislena nova teza je le med 0 in 10 kg 442: if ((0 < novaTeza) && (novaTeza <= 10)){ 443: this.masa = novaTeza; 444: return true; // sprememba uspela 445: } 446: // v nasprotnem primeru NE spremenimo tee
1

Mimogrede, e bi li v podrobnosti jezika C#, bi videli, da lahko doloene komponente proglasimo za lastnosti (Property), ki zahtevajo, da jim napiemo metodi z imenom get in set in potem lahko uporabljamo notacijo imeObjekta.imeLastnosti. Na zunaj je videti, kot bi imeli javne spremenljivke. V resnici pa je to le "zamaskiran" klic get oziroma set metode. Mi bomo lastnosti spustili in bomo pisali "svoje" get in set metode. Programiranje 1 VS Informatika

C# . NET

50

447: 448: 449: }

// in javimo, da spremembe nismo naredili return false;

Ali imamo lahko obe metodi? al ne, saj imata obe enak podpis. Spomnimo se, da podpis sestavljajo ime metode in tipi parametrov. Tip rezultata pa ni del podpisa! Pri sestavljanju razreda se bomo torej odloili za eno teh dveh metod (odvisno od ocenjenih potreb). Metoda je seveda lahko bolj kompleksna. Denimo da vemo, da se tea zajca med dvema tehtanjima ne more spremeniti bolj kot za 15%. Zato lahko z metodo "polovimo" morda napane poskuse sprememb.

R A Z R E D Z A J E C S P R E M E N I T E Z O VM E J A H
450: public bool SpremeniTezoVmejah(double novaTeza) { 451: // smislena nova teza je le med 0 in 10 kg 452: // in e ni ve kot 15% spremembe od zadnji 453: int sprememba = (int)(0.5 + (100 * 454: Math.Abs(this.masa novaTeza) / this.masa); 455: 456: if ((0 < novaTeza) && (novaTeza <= 10) && (sprememba <= 15) ){ 457: masa = novaTeza; // this.masa ... Lahko pa this spustimo! 458: return true; // sprememba uspela 459: } 460: // v nasprotnem primeru NE spremenimo tee 461: // in javimo, da spremembe nismo naredili 462: return false; 463: }
Kaj pa metodi za spreminjanje serijske tevilke in spola? Na zadnjo lahko mirno pozabimo. Zajec naj ima ves as tak spol, kot mu ga doloimo pri "stvarjenju" (torej v konstruktorju). Zato set metode za spremninjanje spola sploh ne bomo napisali. In ker je spremenljivka spol zaitena s private, je uporabnik ne bo mogel spremeniti. Seveda, e bomo na razred Zajec potrebovali za kaken genetski laboratorij, kjer se gredo udne stvari, pa bo morda metoda SpremeniSpol potrebna. Tudi serijske tevilke verjetno ne bomo spreminjali. No, e malo bolje premislimo, pa nam konstruktor brez parametrov ustvari zajca, ki ima za vrednost serijske tevilke niz "NEDOLOENO". Takim zajcem bomo verjetno eleli spremniti serijsko tevilko. Zato naj metoda SpremeniSerijsko pusti spreminjati le nedoloene serijske tevilke!

RAZRED ZAJEC SPREMENISERIJSKO


public bool SpremeniSerijsko(string seStev) { // sprememba dopustna le, e serijske tev. ni if (this.serijska.Equals("NEDLOENO")) { this.serijska = seStev; return true; } return false; // ne smemo spremniti e obstojee! }
Tudi tu lahko npr. poskrbimo, da je metoda SpremeniSerijsko bolj kompleksna. Na primer lahko zahtevamo, da se vse serijske tevilke zano s predpono SN, ki ji potem zraven pripnemo poljuben niz. In ker so uporabniki pozabljivi in bodo nekateri e sami zaeli niz s SN, mi pa noemo imeti serijskih tevilk oblike SNSN..., bo metoda poskrbekla tudi za to. Lahko bi tudi vzdrevali seznam vseh podeljenih serijskih tevilk in bi metoda poskrbela, da imajo vsi zajci razline serisske tevilke. Lahko bi ...

RAZRED ZAJEC SPREMENISERIJSKO

S PREDPONO

public bool SpremeniSerijsko(string seStev) { // sprememba dopustna le, e serijske tev. ni if (this.serijska.Equals("NEDLOENO")) {
Programiranje 1 VS Informatika

C# . NET

51

if ((seStev.Length > 1) && (seStev[0] == 'S') && (seStev[1] == 'N')) this.serijska = seStev; // e ima predpono else this.serijska = "SN" + seStev; // nima predpone return true; return false; // ne smemo spremniti e obstojee! }
Opozorimo e na stvar, ki jo pri sestavljanju razreda pogosto pozabimo. Glavni razlog, da smo napisali te set metode, je, da bi zagotovili, da so podatki pravilni. Zato je smiselno, da zagotovimo, da je tea ustrezna e ves as! A zaenkrat smo na nekaj pozabili! Kaj pa zaetno stanje, ki ga nastavimo v konstruktorju! Tudi v konstruktorju preverimo, e se uporabnik "obnaa lepo". Pogosto na to pozabimo in uporabnik lahko napie npr.

Zajec neki = new Zajec("X532", true, 105);


105 kilogramskega zajca verjetno ni, a uporabnik je pozabil na decimalno piko v 1.05. Zato je kontrola smiselnosti podatkov potrebna tudi v konstruktorjih! Dostop do stanj Pogosto nem je vseeno, e uporabnik "vidi", kako hranimo podatke v objektu. A zardi zagortavljanja pravilnosti in monosti kontrole sprememb podatkov, smo dostop nastavili na private. S tem smo seveda onemogoili tudi enosatven nain poizvedbe po vrednosti podatka v obliki rjavk.masae bomo torej potrebovali teo zajca, bo potrebno pripraviti ustrezno metodo. e bomo torej potrebovali teo zajca zajcek, bomo napisali zajcek.PovejTezo() Veina tovrstnih get metdo je enostavnih in v telesu metode vsebujejo le ukaz return.

RAZRED ZAJEC POVEJTEZO


180: public double PovejTezo() { 181: return this.masa; // ali return masa 182: }
A ni nujno, da so metode get tako enostavne. Lahko pogled na podatke "oblikujemo". Recimo, da bomo uporabniku vedno povedali le teo na pol kilograma, mi pa bomo interno teo zajca vodili na gram (ali e bolj) natanno. e torej teo povemo na 0.5 kg natanno 2.721 2.5, 2.905 3, 2.502 2.5, ... Ustrezen podstopek bo: Vzamemo teo v celih kg in pogledamo prvo decimalko decimalnega dela e je med 3 in 7, pritejemo k celim kg 0.5 e je ve kot 7, pritejemo k celim kg 1.0

RAZRED ZAJEC POVEJTEZO

NA

0.5 K G

NATANNO

464: public double PovejTezo() { 465: // teo bomo povedali le na 0.5 kg natanno 466: int tezaKg = (int)this.masa; 467: int decim = (int)((this.masa tezaKg) * 10); 468: if (decim < 3) return tezaKg + 0.0; 469: if (decim < 8) return tezaKg + 0.5; 470: return tezaKg + 1.0; 471: }

Programiranje 1 VS Informatika

C# . NET

52

Zgled razred Datum Kot primer oblikovanja pogleda na podatke si oglejmo e razred Datum. Prej (glej stran 37) smo ugotovili, da ni smiselno, da podatke o mesecu hranimo kot niz. A uporabniku bi jih e vedno raje "servirali" kot februar in ne kot 2. Zato bi metoda KateriMesec() bila lahko taka

RAZRED DATUM KATERIMESEC


1: 2: 3: 4: 5: 6: public string KateriMesec() { string[] imenaMesecev = {"januar", "februar", "marec", "maj", "junij", "julij", "avgust", "september", "oktober", "november", "december"}; return imenaMesecev[this.mesec]; } "april",

Seveda so potrebne e spremembe v drugim metodah. Npr. uporabnik bo verjetno elel imeti metodi NastaviMesec, ki bosta sprejeli bodisi tevilni ali pa opisni podatek. Ostale metode Poleg get/set metod in konstruktorjev v razredu napiemo tudi druge metode, saj objektov ne potrebujemo samo kot "hranilnikov" podatkov. S temi metodami doloimo odzive objektov "znanje objektov" e se na primer spomnimo na objekte tipa string: Znajo povedati, kje se v njih zane nek podniz:

"niz".IndexOf("i") nekNiz.toLower() mojPriimek.Equals("Lokar")

Znajo vrniti spremiti rke v male in vrniti nov niz:

o o

Znajo povedati, e so enaki nekemu drugemu nizu:

Zato bomo tudi v "naih" razredih sprogramirali znanje objektov doloenega razreda s tem, da bomo napisali ustrezne metode. Katere bodo te metode je pa odvisno od nartovane uporabe naih razredov. Kot enostaven zgled recimo, da bo zajec znal povedati svojo vrednost, e mu povemo ceno za kg ive tee. "Komercialno" zanimiva bi bila e metoda, ki bi vrnila true, e je smiselno zajca tik pred tehtanjem (in prodajo) poteno napojiti.Spomnimo se namre, da teo zajcev uporabnikom povemo na pol kg natanno, eoprav jo interno hranimo tono.

RAZRED ZAJEC
183: 184: 185: 186: 187: 188: 189: 190: 191: 192: 193: 194:

DODATNE METODE

public double Vrednost(double cenaZaKg) { // pove vrednost zajca // zajce tehtamo na dogovorjeno natannost return cenaZaKg * this.PovejTezo(); } public bool MeNapojiti() { // ugotovimo, e ga je smiselno // napojiti, da bomo "ujeli" naslednjih pol kg // dejanska tea je veja od "izmerjene" return (this.masa this.povejTezo() > 0); }

Metoda ToString Poglejmo si naslednji program:

Programiranje 1 VS Informatika

C# . NET

53

IZPIS

OBJEKTA

using System; using MojaKniznica; namespace Izpis { class Program { public static void Main(string[] args) { Zajec zeko = new Zajec(); Console.WriteLine("To je zajec: " + zeko); Console.Write("Press any key to continue . . . "); Console.ReadKey(true); } } }
e ga izvedemo, na zaslon dobimo

Od kod, zakaj? Oitno objekte lahko tudi izpiemo. In e napiemo string niz = "Zajec " + zeko + "!"; prevajalnik tudi ni ne protestira. Torej se tudi objekti "obnaajo" tako kot int, double ... in se torej po potrebi pretvorijo v niz. Obnaanje, ki smo ga opazili (da se tevila, objekti ...) pretvorijo v niz, omogoa metoda ToString. Metoda je nekaj posebnega, saj se lahko "poklie kar sama". Namre, e na doloenem mestu potrebujemo niz, a naletimo na objekt, se metoda poklie avtomatino. Torej

string niz = "Zajec " + zeko + "!";


dejansko pomeni

string niz = "Zajec " + zeko.ToString() + "!";


Od kje pride ta metoda, saj je v razredu Zajec nismo napisali. Gre spet za eno od tistih "arovnij", ki jo pone prevajalnik, kot na primer pri konstruktorjih? Zadeva je malek drugana in jo bomo pojasnili v nadaljevanju. Zaenkrat bodi dovolj kle to, da ta metoda vedno obstaja, tudi e je ne napiemo in omogoa pretvorbo poljubnega tipa v niz. A s pretvorbo nismo ravno zadovoljni. Radi bi kakne bolj smiselne informacije. To storimo tako, da v razredu, ki ga definiramo (recimo Zajec), sami napiemo metodo ToString. e to storimo, in zaenemo isti program:

V razred Zajec smo napisali

METODA TOSTRING
public override string ToString() { return "Zajec: " + this.PovejSerijsko(); }
Programiranje 1 VS Informatika

C# . NET

54

Opazimo novo neznano besedo override. Uporabiti jo moramo zaradi "dedovanja". Ve o tem, kaj dedovanje je, kasneje, a povejmo, da smo z dedovanjem avtomatino pridobili metodo ToString. To je razlog, da je ta metoda vedno na voljo v vsakem razredu, tudi e je ne napiemo. e elimo napisati svojo metodo, ki se imenuje enako kot podedovana metoda, moramo napisati besedico override. S tem "povozimo " podedovano metodo. Seveda bi lahko napisali tudi neko drugo metodo, na primer Opis, ki bi prav tako vrnila niz s smiselnim opisom objekta. Razlika med

METODA TOSTRING
public override string ToString() { return "Zajec: " + this.PovejSerijsko() ; }
in

METODA OPIS
public string Opis() { return "Zajec: " + this.PovejSerijsko() ; }
je v tem, da moramo metodo Opis poklicati sami, metoda ToString pa se klie avtomatsko (e je potrebno). e torej napiemo

string niz1 = "Zajec " + zeko.ToString() + "!"; string niz2 = "Zajec " + zeko + "!"; string niz3 = "Zajec " + zeko.Opis() + "!";
so vsi trije dobljeni niz enaki! Zapomnimo si torej, da metoda ToString obstaja tudi, e jo ne napiemo. A verjetno z vrnjenim nizom nismo najbolj zadovoljni, zato jo praktino vedno napiemo sami. Celotni razred Zajec Oglejmo si sedaj celotno kodo razreda Zajec s spremembami, ki smo jih naredili. Spomnimo se, kaj vse smo opravili: Pripravili smo nekaj konstruktorjev Zaitili smo dostop do podatkov (private) Napisali smo ustrezne metode za spreminjanje podatkov o objektu Napisali smo metode za poizvedovanje po vrednosti podatkov Napisali smo metodo ToString, ki vrne opis objekta Napisali smo dve metodi, ki pomenita "znanje" objektov
RAZRED

CELOTNI

ZAJEC

472: public class Zajec { 473: private string serijska; 474: private bool spol; 475: private double masa; 476: // konstruktor 477: public Zajec() { 478: this.spol = true; // vsem zajcem na zaetku doloimo m. spol 479: this.masa = 1.0; // in tehtajo 1kg
Programiranje 1 VS Informatika

C# . NET

55

480: 481: 482: 483: 484: 485: 486: 487: 488: 489: 490: 491: 492: 493: 494: 495: 496: 497: 498: 499: 500: 501: 502: 503: 504: 505: 506: 507: 508: 509: 510: 511: 512: 513: 514: 515: 516: 517: 518: 519: 520: 521: 522: 523: 524: 525: 526: 527: 528: 529: 530: 531: 532: 533:

this.serijska = "NEDOLOENO"; } public Zajec (string serijskaStev) { this(); // poklicali smo konstruktor Zajec() this.serijska = serijskaStev; } public Zajec(string serijskaStev, bool spol, double masa) { this(); // poklicali smo konstruktor Zajec() this.serijska = serijskaStev; this.SpremeniTezo(masa); // uporabimo metodo za sprem. this.spol = spol; } public double PovejTezo() { // teo bomo povedali le na 0.5 kg natanno int tezaKg = (int)this.masa; int decim = (int)((this.masa tezaKg) * 10); if (decim < 3) return tezaKg + 0.0; if (decim < 8) return tezaKg + 0.5; return tezaKg + 1.0; } public bool SpremeniTezo(double novaTeza) { // smislena nova teza je le med 0 in 10 kg if ((0 < novaTeza) && (novaTeza <= 10)){ masa = novaTeza; return true; // sprememba uspela } // v nasprotnem primeru NE spremenimo tee // in javimo, da spremembe nismo naredili return false; } public string PovejSerijsko() { return this.serijska; } public bool SpremeniSerijsko(string seStev) { // sprememba dopustna le, e serijske tev. ni if (this.serijska.Equals("NEDLOENO")) { this.serijska = seStev; return true; } return false; // ne smemo spremniti e obstojee! } public bool JeSamec() { return this.spol; } // ker se spol naknadno NE spremeni, metode za // spreminjanje spola sploh ne ponudimo uporabniku! public double Vrednost(double cenaZaKg) {
Programiranje 1 VS Informatika

C# . NET

56

534: 535: 536: 537: 538: 539: 540: 541: 542: 543: 544: 545: 546: 547: 548: 549: 550: 551:

// pove vrednost zajca // zajce tehtamo na dogovorjeno natannost return cenaZaKg * this.PovejTezo(); } public bool MeNapojiti() { // ugotovimo, e ga je smiselno // napojiti, da bomo "ujeli" naslednjih pol kg // dejanska tea je veja od "izmerjene" return (this.masa this.povejTezo() > 0); } public override string ToString() { return "Zajec: " + this.PovejSerijsko(); } } // Zajec

Uporaba razreda Zajec Poglejmo si, kako opravljene spremembe vplivale na uporabo rezreda Zajec v uporabnikih programih. Prej so bili ti takni:

UPORABA

STAREGA RAZREDA

ZAJEC

195: public class Zajnik { 196: public static void Main(string[] ar) { 197: Zajec z1 = new Zajec(); 198: z1.serijska = "1238-12-0; 199: z1.spol = false; 200: z1.masa = 0.12; 201: z1.masa = z1.masa + 0.3; 202: System.Console.WriteLine("Zajec ima ser. t.:" + z1.serijska); 203: } 204: }
Z novim razredom Zajec seveda se nain uporabe povsem spremeni, saj ne moremo priakovati, da bodo tako drastine spremembe, ki smo jih naredile, pustile uporabnike programe nespremenjene. e enkrat povejmo, da razreda Zajec ne bi nikoli "zares" napisali tako, kot smo ga po starem (z javnimi spremenljivkami).

UPORABA

NOVEGA RAZREDA

ZAJEC

205: public class ZajnikNov { 206: public static void Main(string[] ar) { 207: Zajec z1 = new Zajec("1238-12-0", false, 0.12); 208: if (z1.SpremeniTezo(z1.PovejTezo() + 0.3)) 209: System.Console.WriteLine("Tea je spremenjena na " 210: + z1.PovejTezo()); 211: else System.Console.WriteLine("Tea je nespremenjena!" 212: + " Prirastek je prevelik! Preveri!"); 213: System.Console.WriteLine("Zajec ima ser. t.:" z1.PovejSerijsko()); 214: } 215: }

Ko sestavljamo razred, kot objektne spremenljivke lahko uporabimo tudi spremenljivke istega razreda
Programiranje 1 VS Informatika

C# . NET

57

Npr.: starsi Zajca Razred Clan public class Clan { private string ime; private Clan gaJePriporocil; ... elimo hraniti tudi stare zajca public class Zajec { private double masa; private string serijska; private bool spol; private Zajec oce; private zajec mati; e konstruktor Sestavimo privzeti konstruktor public Zajec() { this.spol = true; this.masa = 1.0; this.serijska = "NEDEOLOENO"; this.oce = new Zajec(); this.mama = new Zajec(); } Ko stvar prevedemo, je vse v redu. A ob poskusu Zajec rjavko = new Zajec();

Rekurzija brez ustavitve Tudi konstruktor je metoda Ustavitveni pogoj A pri konstruktorju brez parametrov ni parametrov, ki bi lahko doloili ustavitveni pogoj "Privzeti" zajec ne pozna starev oce = null; mama = null; e malo pomislimo ko zajca "naredimo", morata stara e obstajati Ju nima smisla ustvarjati na novo

Programiranje 1 VS Informatika

C# . NET

58

Gradnja razredov - zgled


Ustvarjanje objektov Razred je ablona, ki definira spremenljivke in metode skupne vsem objektom iste vrste. Ko torej napiemo

class
gre za to, da zaeno pisati nart objekta, ablono po kateri bomo ustvarjali objekte. Z ustvarjanjem razredov si pripravljamo sestavne dele, s pomojo katerih bomo reevali nek problem. Ko pa sestavljamo program, ki predstavlja algoritem, s katerim reujemo problem, pa na podlagi teh pripravljenih nartov (razredov) ustvarimo primerek razreda konkretni objekt. Pogosto bomo prebrali, da je objekt instanca nekega razreda, a to je nepotrebno "paenje" slovenskega jezika. Za besedo instanca obstaja isto lep slovenski izraz primerek. Primerek razreda (konkretni objekt) ustvarimo ga z new. Dokler new ne uporabimo, objekta ni in ga seveda ne moremo uporabiti. e torej napiemo

NekiObjekt a;
Ne pozabimo, da objekt s tem e ne obstaja. Spremenljivka a je samo ime objekta, oziroma natanneje , a je ime spremenljivke, kjer bomo hranili naslov objekta vrste NekiObjekt. ele new bo naredil objekt in vrnil naslov, kje ta objekt je. In ta naslov bomo shranili v a. Problem Banke Butale Banka Butale se intenzivno pripravlja na prihod nove valute arve. Med drugim bo potrebno nakovati nove kovance. Za ustrezno informacijsko podporo kovanici najamejo tebe. Po nekajmesenih pogovorih ugotovi, da bomo v programih potrebovali objekte vrste Kovanec. Potrebujemo torej razred Kovanec. Kaj pa sedaj? Kako do svojega razreda Najlaje je, e ustrezen razred e obstaja v standardnih knjinicah jezika C#. e ga tam ni, se splaa pogledati okoli. Morda je kdo drug pripravil knjinico, v kateri je iskani razred. Kaj pa, e na triu ni niti priblino ustreznega razreda. Takrat moramo narediti razred sami. Kako se tega lotimo? Skica postopka z opombami bi bila: o Analiza: Pa ne matematini predmet Katera so stanja/lastnosti: Kaj hoemo o objektih te vrste vedeti Kakne lastnosti imajo Katere so metode: Kakno je znanje objektov Na katere ukaze se odzovejo o Predstavitev razreda (priprava class) Nain predstavitve lastnosti objekta (podatke o objektu) skrijemo: private enkapsulacija Odloitev o nainu predstavitve Pisanje metod o Preverjanje delovanja posameznih metod Pisanje testnih programov, s katerimi preverimo, ali se posamezna metoda obnaa na predpisan nain o S pomojo ustreznih orodij izdelamo dokumentacijo (na podlagi dokumentacijskih komentarjev) Najprej torej poteno prouimo na problem in analiziramo zahteve, ki jih mora izpolnjevati razred Kovanec. Prvenstveno moramo ugotoviti, kaj hoemo o objektih vrste Kovanec vedeti torej kakne podatke bomo o posameznem kovancu hranili. Potem ugotovimo, kaj bi z objekti vrste Kovanec radi poeli torej kakne metode naj bi lahko izvajali nad objekti te vrste. Seveda premislek o monih metodah lahko vpliva tudi na to, katere podatke bomo o kovancih hranili.

Programiranje 1 VS Informatika

C# . NET

59

Ko smo z analizo konali, se lotimo pisanja razreda. Pa tudi tu e ne pride takoj na vrsto kodiranje. Anjprej se moramo odloiti, kako bomo eljene podatke hranili. Kakne bodo spremenljivke (kaknega tipa), koliko jih bo ... Praviloma vse spremenljivke, v akterih hranimo podatke o objektu, "skrijemo". Za zunanje uporabnike jih napravimo nevidne z doloilom private. Ko smo se odloili o nainu predstavitve lastnosti, se lotimo pisanja ustreznih metod. Ko smo konali, dobro preverimo delovanje vseh metod. Na koncu, a kot zelo pomembno zadevo, pa pripravimo e dokumentacijo o razredu, kjer tono opiemo parametre vseh metod, tip rezultata ter namen posamezne metode. Pri pisanju komentrajev soi pomagamo z orodji, ki to dokumentacijo avtomatino ustvarijo na podlagi dokumentacijskih komentarjev. Okostje razreda Oglejmo si, kako bo videti tipini razred, ki ga bomo sestavljali. Vrstni red sicer ni pomemben, a se najvekrat drimo prav takega. Pohosto sicer vidimo, da je v razredu tudi metoda Main, ki jo uporabljamo za preverjanje delovanja razreda. A naeloma to ni najbolje, kar "zamegljuje" sliko. Razred naj bo pa nart za objekte nekega tipa. V drugem programu (ki pa je tudi razred, a brez komponent, objektnih metod ...) pa pa objekte pripravljenih razredov uporabljamo. public class Razred { // deklaracija lastnosti - komponent - polj - ... // konstruktorji // metode // ToString } Razred Kovanec Sestavimo sedaj razred Kovanec, s katerim predstavimo kovance v obliki, kot jih bomo potrebovali za butalsko banko.. Naredimo analizo: Ugotovimo, da so kovanci okrogli, z danim polmerom in viino. Poleg konstruktorjev in standardnih metod, ki nastavijo in vrnejo vrednosti lastnosti in za pretvorbo v niz, naj razred pozna e metodi, ki vrneta povrino in volumen kovanca. Sedaj se moramo odloiti o nainu predstavitve podatkov. Torej vedeti moramo kje in kako bomo podatke (polmer, viina) hranili. Denimo, da vemo, da so to vedno cele vrednosti, zato se odloimo kar za dve celotevilski spremenljivki. To seveda ni edina mona odloitev. Ker se mere kovancev lahko spreminjajo in ker je smiselno, da uporabnik mere lahko zve, bomo pripravili tudi dve set in dve get metodi. Pripravimo skico razreda, kjer bomo vsebino metod izpustili.

KOVANEC -

SKICA

216: public class Kovanec { 217: 218: private int polmer; 219: private int visina; 220: 221: // konstruktorji 222: public Kovanec() {} 223: public Kovanec(int r, int v) {} 224: 225: // "SET" metode 226: public void NastaviPolmer(int r) { } 227: public void NastaviVisino(int visina) { } 228: 229: // "GET" metode
Programiranje 1 VS Informatika

C# . NET

60

230: 231: 232: 233: 234: niz 235: 236: 237: 238: 239: 240: }

public int PovejPolmer() { } public int PovejVisino() { } // tostring overide public string ToString() { } // kako je objekt videti kot // "znanje" public double Volumen() { } public double Povrsina() { }

Lotimo se pisanja metod. Denimo, da napiemo nekaj takega:

KOVANEC

DEL METOD

241: public class Kovanec { 242: private int polmer; 243: private int visina; 244: 245: // konstruktorji 246: public Kovanec() {} 247: public Kovanec(int r, int v) {} 248: 249: // "SET" metode 250: public void NastaviPolmer(int r) { 251: polmer = r; 252: } 253: 254: public void NastaviVisino(int visina) { 255: // smiselna visina je le med 1 in 100 256: // drugace jo pustimo pri miru 257: if ((1 <= visina) && (visina <= 100)) 258: this.visina = visina; 259: } 260: 261: // "GET" metode 262: public int PovejPolmer() { 263: return polmer; 264: } 265: 266: public int PovejVisino() { 267: return visina; 268: } 269: 270: override public string ToString() { 271: return r = + this.PovejPolmer() + \nvisina = 272: + this.PovejVisino(); 273: } 274: }
Primerjajmo metodi NastaviPolmer in NastaviVisino. Pri slednji smo preverili, ali je uporabnik te metode navedel smiselne parameter. Iz analize problema vemo, da je smiselna viina kovancev med 1 in 100. Zato metoda to preveri. e parameter ni v teh mejah, potem metoda ne spremeni stanja objekta.

Programiranje 1 VS Informatika

C# . NET

61

Pri metodi NastaviPolmer pa zgolj vrednost parametra zapiemo v spremenljivko in s tem spremenimo lastnost objekta. Torej neprevidni programer lahko "naredi kovanec" z negativnim polmerom. Vsekakor pri "pravem 2 programiranju" metode ne bomo napisali na ta nain. Pri metodi za opis objektov vrste kovanec smo se odloili, da je smielen opis objekta dvovrstini. V prvi vrstici pie r xx, v drugi pa visina xxx, kjer je namesto xx seveda ustrezna vrednost.Opazimo tudi, da do vrednosti polmera dostopamo preko metod. To sicer ni potrebno in bi metodo lahko napisali tudi kot

METODA TOSTRING
1: 2: 3: 4:

Z NEPOSREDNIM DOSTOPOM

override public string ToString() { return r = + this.polmer + \nvisina = + this.visina; }

Torej z neposrednim dostopom do spremenljivk. To lahko naredimo, saj smo znotraj razreda. A je vseeno bolje, e metodo napiemo na prej predstavljeni nain. Vemo, da se Butalci pogosto radi malo postavijo nasproti Verejcem. In ker se Verejci hvalijo, da so njihovi kovanci precej veji, jim Butalci ne bodo ostali dolni. Po e-poti dobi zahtevo, da "popravi" razred Kovanec tako, da bo javljal 2x veji polmer (podatek o polmeru naj bo v objektu za vsak primer zapisan kar pravi, le navzven naj se "pretvarja" da je dvakrat veji) . In e smo dostop do lastnosti polmer povsod izvajali preko metode PovejPolmer() ustrezno spremembo napravimo le na enem mestu. Uporaba razreda Kovanec Prvi problem, ki ga mora reiti za butalsko banko, je problem njihove dravne kovnice. Dravna kovnica eli, da napie program, ki rei naslednji problem. Kovino za izdelovanje kovancev imajo v kovnici obliki enega samega velikega kvadra z merami 20 x 12 x 30 (za ve ni prostora, saj je arhitekt, ko (ki je povsem sluajno isti kot arhitekt neke fakultete) je risal narte za kovnico pozabil na skladie. Ko Banka Butale potrebuje nekaj kovancev, jih zanima, e bodo iz tega kvadra res lahko izdelali eljeno tevilo kovancev. Zato bi radi imeli program,m ki pove, ali lahko naredimo n "obiajnih" kovancev (torej takih, kot jih naredi konstruktor Kovanec()). Problem sploh ni lahek. A e ga "razumemo prav" in upotevamo da lahko kvader potem tudi malo preoblikujemo, odpadke spet zlijemo skupaj in ponovno kujemo, ... Poleg tega moram,o odgovore programa (DA/NE) pravilno tolmaiti. ne: nikakor to ne gre da: mogoe, ni pa nujno Program bo enostaven. Z new Kovanec() ustvarimo nov, obiajni kovanec. Povpraajmo ga, koliko je njegov volumen. e n kratnik volumna presega volumen kvadra, vemo, da s kovanjem taknega tevila kovancev ne bo ni in dogovorimo NE. V nasprotnem pa ostaja upanje, da bodo vrli butalski kovai e nekako nakovali n kovancev in odgovorimo DA.

UPORABA

RAZREDA

KOVANEC

275: public static Drzava { 276: public static void Main(string[] a) { 277: int kvader_x = 20; 278: int kvader_y = 12; 279: int kvader_z = 30; 280: int volumenKvadra = kvader_x * kvader_y * kvader_z; 281: Console.Write("koliko kovancev potrebujemo: "); 282: int n = int.Parse(Console.ReadLine()); 283: Kovanec en = new Kovanec(); 284: int volKovanca = en.Volumen(); 285: if (volumenKvadra > n * volKovanca) 286: System.Console.WriteLine("DA"); 287: else 288: System.Console.WriteLine("NE");
2

Lahko pa in si s tem zagotovimo monost nadaljnih "izboljav" (in novih zaslukov) Programiranje 1 VS Informatika

C# . NET

62

289: 290: }

Program je napisan, v Butalah so nad njim navduzeni. A ne mine leto, ko dravni zakladnik spremeni dimenzije "obiajnih" kovancev. Je potrebno spremeniti program? Kje so potrebne spremembe? Spremembe v programu niso potrebne. Popraviti je potrebno seveda razred Kovanec, kjer spremenimo delovanje konstruktorja brez parametrov. A to je vse. V uporabnike programe, torej tiste, ki razred Kovanec uporabljajo, se ni potrebno vtikati! Razrede sestavljamo tako, da uporabniki tega razreda niso prizadeti ob morebitnih spremembah razredov Glave metod pustimo enake (podpis + tip rezultata + nain dostopa) Uporabniki programi ostanejo enaki Potrebujejo le nove dll datoteke razreda Za uporabnika se s tem ne spremeni ni! Zgled - razred Kvader Naa naslednja naloga je sestaviti razred, ki bo opisoval kvadre. Najprej nas spet aka analiza problema. Odloiti se moramo, kaj za nas kvader sploh pomeni. Denimo, da ga potrebujemo zgolj kot geometrijsko telo. Zato bomo o njem hranili le njegove mere. Potem moramo pripraviti ustrezne metode za ravnanje s podatki ter predvideti "znanje " objektov. Skica naega razmiljanja bo torej: o Geometrijsko telo o Podatki Komponente opisujejo stanje objekta o Metode Konstruktorji (posebne metode) Kaj se zgodi ob new znanje objektov tega razreda volumen, povrina, ... Metode za ravnanje s podatki Nastavi podatek Vrni podatek ToString Kvader podatki Kvader kot geometrijsko telo je podan z dolinami vseh treh stranci. Odloiti se moramo torej kako bo imel objekt predstavljene stranice. Ena od monosti je, da uporabimo 3 spremenljivke tipa int. Druga monost bi bila, da vzamemo tabelo s tremi polji. Spet tretja, da podatke predstavimo kot niz oblike "a x b x c". Spet etrta monost ... V naem zgledu se bomo odloili kar za prvo monost. Uporabili bomo torej

private int a; // stranica a private int b; // stranica b private int c; // stranica c


Vendar bomo razred sestavljali tako, da uporabniki programi pri mrebitni kasneji spremembi naina predstavitve podatko v ne bodo prizadeti. Se e spomnimo, zakaj se s private "gremo" kapsuliranje (enkapsulacijo).? Nain predstavitve uporabnika NE zanima s private mu prepreimo dostop. Kako pa potem pridemo do podatkov? S tem, da pripravimo ustrezne metode. V njih bomo lahko tudi preverjali smiselnost podatkov. Z enkapsulacijo tem smo si omogoili tudi morebitno naknadno spreminjanje razreda, ne da bi s tem "trpeli" obstojei programi, ki ta razred uporavljajo. e se pri spremembi razreda podpisi metod ne spreminjajo ni teav s spreminjanjem razreda: Vsi programi, ki uporabljajo objekte doloenega razreda, si podatke izmenjujejo le preko metod e se klic ne bo spremenil, je vseeno, kako je spremenjen razred!

Programiranje 1 VS Informatika

C# . NET

63

Kvader metode za delo s podatki Za podatke, za katere je smiselno, da jih uporabnik vidi, napiemo metode, ki povejo vrednost podatka. Pri tem lahko prikaz podatkov oblikujemo (npr. vrnemo podatek le na eno decimalno mesto, kot niz, ...). Vasih doloenih podatkov sploh ne bomo "pokazali" upotrabniku. V tem primeru pa ne napiemo nobene get metode, ki bi vrnila ta podatek. V naem razredu bomo napisali metode oblike

PovejA(),
Za podatke, za katere je smiselno, da jih uporabnik spremeni, pa pripravimo metode, ki spremenijo vrednost podatka. Ob tem obiajno preverimo, e je podatek smiselen. Kaj pa naredimo, e podatek ni smsielene, je odvisno od namena, za katerega sestavljamo razred. Tako se na primer lahko odloimo, da podatka enostavno ne spremenimo in morda to javimo, preko izhodnega rezultata tipa int ali bool. Lahko v primeru napanih podatkov privzamemo, da potem podatek objekta spremenimo na neko vnaprej doloeno vrdnost ... Vse te odloitve (kaj storimo ob napanih podatkih) pa dobro dokumentiramo v dokumentaciji. Tako bodo uporabniki tega razreda vedeli, kaj lahko priakujejo. . V naem razredu bomo napisali metode oblike

StranicaA(),
Kvader konstruktorji K metodam, ki spreminjajo podatke, na doloen nain spadajo tudi konstruktorji. Z njimi najpogosteje nastavimo zaetne vrednosti podatkov v objektu. Pri tem ne smemo pozabiti, da mora tudi konstruktor poskrbeti, da bodo shranjeni podatki smiselni. e posebej pa moramo biti pazljivi na to, da objekt ob klicu 3 konstruktorja e nima nastavljenih smiselnih podatkov . Zato si obiajno ne privoimo tega, da bi v primeru napanih poarametrov v konstruktorju ne naredili ni, amapak zamenjamo napane vrednosti parametrov z nekeimi, vnaprej dogopvorjenimi (in v dokumentaciji dobro opisanimi) vrednostmi. e pri razlagi uporabe konstruktorjev smo omenili, da skoraj vedno pripravimo konstruktor brez parametrov. Tak konstruktor naredi privzeti objekt. Denimo, da je na privzeti objekt kvader s stranicami: 1 x 1 x 1. Ustrezni konstruktor bo

KONSTRUKTOR
public Kvader(){ a = 1; b = 1; c = 1; }

BREZ PARAMETROV

Naeloma ta konstruktor zadostuje. e elimo narediti drugaen kvader, pa naredimo osnovni kvader in mu z ustreznimi metodami spremenimo stranice. Kaj pa, e bi uporabniku radi ponudili ve monosti zaetnega kvadra? Denimo Konstruktor, ki naredi kocko Konstruktor, kjer podamo stranice Konstruktor, ki naredi kopijo objekta

Navedimo sedaj kar celoten razred. V njem smo napisali cel kup komentarjec, doloene zadeve smo po nepotrebnem pisali drugae, le zato, da smo lahko pripraili ustrezne komentarje. Sem in tja bomo kodo prekinili z razlago. Opazili boste, da smo namenoma malo premeali vrstni red. Na ta nain elimo opozoriti, da je vrstni red metod v razredu povsem poljuben.
RAZRED

KVADER
doloceni konstrukcijski prijemi

291: public class Kvader { 292: // z /* ... */ so oznaceni komentarji za razlago zakaj 293: // v "pravem" razredu jih ne bi bilo! 294:
3

Rsnici na ljubo imajo vse komponente, ki opisujejo objekt, takoj nastavljene privzete vrednosti. A do sedaj smo se e nauili, da se zanaanje na to, da bo za nekaj poskrbel prevajalnik, obiajno ne kona najbolje. Spomnimo se le teav, ki smo jih imeli, ker je prevajalnik sam namesto nas pripravil konstruktor brez parametrov.Tudi tu je vpraanje, le privzete vrednosti opisujejo "legalno" stanje objekta. Programiranje 1 VS Informatika

C# . NET

64

295: 296: 297: 298: 299: 300: 301: 302: 303:

private int a; /* uporabnika ne zanima, kako imamo shranjene podatke */ private int b; private int c; // minimalna dolzina stranice public const int MIN_DOL_STR = 1; // maksimalna dolzina stranice public const int MAX_DOL_STR = 100;

e pred spremenljivko ob deklaraciji napiemo const, s tem povemo, da gre za konstanto. To pomeni, da vrednosti, ki jo priredimo ob deklaraciji, potem ne moremo ve spreminjati. Tudi konstante so lahko javne ali privatne. Lahko jih piemo lokalno (znotraj metod), lahko pa reemo, da so to lastnost razreda (in jih napiemo izven vseh metod, tja kot objektne spremenljivke. Navada je, da jih poimenujemo z imenom, ki vsebuje same velike rke. Pogosto jim doloimo javni dostop, saj jih uporabnik tako ali tako ne more spreminjati, saj so konstante. Seveda pa, e bi jih uporabniku radi predstavili drugae (prego get metod) ali jih pred njim skrili, lahko uporabimo private. Gre za tako imenovane razredne (statine) podatke . To pomeni, da obstajajo neodvisno od obstioja kaknega primerka in da do njih dostopamo (e so public) z

ImeRazreda.IME_KONSTANTE
Ve o tem v razdelku, ko bomo na dolgo govorili o statinih (razrednih) podatkih.

304: 305: 306: 307: 308: 309: 310: 311: 312: 313: 314: 315: 316: 317: 318: 319: 320: 321: 322: 323: 324: 325: 326: 327: 328: 329: 330:

/* Ker menimo, da je smiselno, da uporabnik neposredno vidi ti dve kolicini - dostop public. Spreminjati ju ne more zaradi const. Dostop: Kvader.MIN_DOL_STR Gre za razredno spremenljivko - 1 kopija za vse objekte, ne gre za lastnost posameznega razreda - ve kasneje */ // vrni podatek public int PovejA() { /* omogocimo uporabniku dostop do vrednosti zanj zanimivih podatkov */ return a; } public int PovejB() { return b; } public int PovejC() { return c; } private bool Kontrola(int x){ /* pomozna metoda, zato private */ // preverimo, ce velja MIN_DOL_STR <= x <= MAX_DOL_STR return ((MIN_DOL_STR <= x) && (x <= MAX_DOL_STR)); }

Tu smo napisali pomono metodo, ki preveri, e je podatek v mejah, kot jih doloata konstanti. Ker smo ocenili, da metoda za uporabnika ni uporabna, smo jo s private pred njim skrili. Tako je ne more uporavljati in je na voljo izkljuno znotraj tega razreda.

331: 332:

// nastavi podatek

Programiranje 1 VS Informatika

C# . NET

65

333: 334: 335: 336: 337: 338: 339: 340: 341: 342: 343: 344: 345: 346: 347: 348: 349: 350: 351: 352: 353: 354: 355: 356: 357: 358: 359: 360: 361: 362: 363: 364: 365: 366: 367: 368: 369: 370:

public void StranicaA(int a) { /* omogocimo uporabniku spreminjanje podatkov */ // Ce je podatek v mejah med MIN_DOL_STR in MAX_DOL_STR, // ga spremenimo, drugace pustimo // taksnega, kot je if (Kontrola(a)) this.a = a; /* this je potreben, da locimo med imenom podatka objekta in parametrom a */ /* verjetno bi bilo bolj smiselno namesto a parameter poimenovati s ali kako drugae */ } public void StranicaB(int a) { // Ce je podatek v mejah med MIN_DOL_STR in MAX_DOL_STR, //ga spremenimo, drugace pustimo // taksnega, kot je if (Kontrola(a)) this.b = a; /* this v nasprotju s prejsnjo metodo tu ni potreben. se vedno pa velja, da bi bilo boljse, da bi parameter a poimenovali drugace - npr. s */ } public void StranicaC(int s) { // Ce je podatek v mejah med 1 in 100, ga spremenimo, //drugace pustimo // taksnega, kot je if (Kontrola(s)) /* na ta nacin bi verjetno "zares" sprogramirali tudi zgornji metodi */ c = s; } //........................................... // konstruktorji public Kvader() { a = b = c = 1; }

Tu smo spet enkrat za spremembo uporabili kombinacijo prireditvenega stavka in prireditvenega izraza. e se spomnimo iz poglavja o datotekah, kjer smo tudi naleteli na prireditveni izraz, je to izraz, ki ima poleg tega, da vrne vrednost, e stranski uinek. Ta je, da spremenjlivko nastavi na to vrednost, ki jo sicer vrne kot vrednost izraza. Konkretno vrstica 79 vse tri stranice nastavi na 1.

371: 372: 373: 374: 375: 376:

public Kvader(int s) { // kocka s stranico s. e podatek ni // v redu - kocka z robom 1 if (!Kontrola(s)) s = 1; // ce podatek ni v mejah, //ga postavimo na 1 a = b = c = s; }

Tu vidimo, da smo namesto napane vrednosti kar sami doloili ustrezni podatek (1). Neklaj takega moramo storiti, saj konstruktor mora nastaviti podatke o objektu na neke smiselne vrednosti (in jih ne moremo kar pustiti nenastavljen oziroma upati, da so privzete vrednosti v jeziku C# ustrezne za na razred).

377:

public Kvader(int s1, int s2, int s3) { // kvader s1 x s2 x s3


Programiranje 1 VS Informatika

C# . NET

66

378: 379: 380: 381: 382: 383: 384: 385: 386: 387: 388: 389: 390: 391: 392: 393: 394: 395: 396: 397: 398: 399: 400: 401:

// Ce kak podatek ni v redu - ga postavimo na 1 if (!Kontrola(s1)) s1 = 1; // ce podatek ni v mejah, // ga postavimo na 1 a = s1; if (!Kontrola(s2)) s2 = 1; // ce podatek ni v mejah, // ga postavimo na 1 b = s2; if (!Kontrola(s3)) s3 = 1; // ce podatek ni v mejah, // ga postavimo na 1 c = s3; } public Kvader(Kvader sk) { // Novi objekt je kopija // obstojecega objekta sk this.a = sk.a; /* this ni potreben */ StranicaB(sk.b); /* tudi znotraj razreda se splaca uporabljati metode za delo s podatki */ StranicaC(sk.c); /* ceprav imamo neposreden dostop do spremenljivk, saj nam ob morebitni spremembi predstavitve ni potrebno toliko popravljati! */ }

Morda se spraujete, kje je tukaj new. Ko smo v enem od prejnjih zgledov sestavljali metodo, ki vrne kopijo objekta, smo e posebej poudarili, da ne smemo pozabiti na new znotraj metode. A ne pozabimo, da smo v konstruktorju. Torej se je objekt ravnokar naredi (prav z new) in mi le nastavljamo njegove podatke.

402: 403: // 404: // --------------- to string 405: // 406: override public String ToString(){ /* prekrivanje metode iz razreda 407: Object */ 408: // Metoda vrne podatek v obliki Kvader: a x b x c 409: return "Kvader: " + PovejA() + " x " + PovejB() + " x " 410: + PovejC(); 411: /* tudi znotraj razreda se splaca uporabljati metode za 412: delo s podatki 413: ceprav imamo neposreden dostop do spremenljivk, saj 414: nam ob morebitni 415: spremembi predstavitve ni potrebno toliko popravljati! */ 416: } 417: } // class Kvader
Ustvarjanje razredov in objektov: povzetek Nredimo sedaj povzetek vsega povedanega. Konkretni objekt je primerek nekega razreda . Nastane z new. Izjema so na prvi pogled objekti razreda string. A dejansko ne gre za izjemo, gre le drugaen zapis, ki "skrije" uporabo operatiorja new! Podobno je pri tabelah ko uporabimo inicializacijo zaetnih vrednosti, naptetih v zavitih oklepajih. Posaminim lastnostim objekta vedno doloimo privatni nain dostopa (da so torej dostopni le metodam znotraj razreda). To povemo tako, da ob deklaraciji napiemo private. Razlog za to je v tem, da uporabnika ne zanima nain hranjenja lastnosti objekta, ampak le smiselna uporaba objektov. S tem tudi omogoimo tudi bolj kontrolirano delo s podatki v objektu. V ta namen pripravimo metode za delo s podatki/lastnosti kot so :

VrniPodatek, NastaviPodatek
Programiranje 1 VS Informatika

C# . NET

67

V razredu moramo obvezno imet tudi konstruktorje. To so metode, ki povedo, kaj se zgodi ob kreaciji novega objekta. Prvenstveno podskrbijo, da so vsi podatki o objektu takoj nastavljeni na smislene vrednosti. Ko piemo metode, s katerimi nastavljamo vrednost (set), ne smemo pozabiti na preverjanje pravilnosti parametrov, Stanje objekta mora biti ves as pravilno. Ne smemo pozabiti na ustreno preverjanje parametrov e pri pisanju konstruktorjev. Kot smo omenili, morajo tudi ti poskrbeti, da je novoustvarjeni objek v "smiselenem stanju") Pri metodah, s katerimi vraamo vrednost (t.i. get metode, vejih zapletov ne gre priakovati. Seveda pa lahko metode izkoristimo, da podatke, ki jih v objektu hranimo na en nain, vrnemo na drug nain,. Vsak na razred naj bi imel tudi metodo ToString. Ta poskrbi, da se bodisi ob klicu, bodisi avtomatino (e se na tistem mestu namesto objekta priakuje niz) objekt pretvori v niz. Uporabljamo jo za predstavitev objekta. Ker zaradi mehanizma dedovanja ta metoda avtomatino obstaja v vsakem razredu, moramo na zaetek dodati e besedo override, Poleg metod za nastavljanje/vraanje podatkov in metode ToString imamo v razredu obiajno e ve drugih metod. Tiste, katerih uporaba je namenjena uporabnikom, se zano z doloilom public, interne (pomone) metode pa s private. Predvsem ori konstruktorjih smo uporabili tehniko preobteevanja (overloading). Gre za to, da imamo lahko ve metod, ki se imenujeo enako, razlikjejo pa se v seznamu parametrov.

Zgledi
Ogledali si bomo nekaj postopkov pri katerih uporabimo objektno programiranje. Avto Izdelujemo spletno anketo o priljubljenosti razlinih avtomobilov. V ta namen bomo sestavili razred Avto, ki naj hrani tri osnovne podatke o velikosti (dolini), barvi in o tipu (limuzina ali kupe): velikost (dolino): decimalno tevilo med 4.0 in 5.0, barvo: poljuben niz in ali je avto tip limuzine ali kupeja. Vse spremenljivke razreda morajo biti privatne, razred pa mora tudi poznati metode za nastavljanje in branje teh vrednosti. Metoda za nastavljanje velikosti avta naj poskrbi tudi za to, da bo velikost vedno ostala znotraj sprejemljivih meja! e uporabnik poskusi doloiti napano velikost, naj se obdri prejnja vrednost. Mona reitev:

RAZRED AVTO
public class Avto { private double velikost; private string barva; private bool tip; // true pomeni, da gre za limuzino, // false, da je kupe // konstruktor public Avto() { this.tip = true; // vsem privzetim avtom na zaetku // doloim tip limuzine this.velikost = 4.0; // in so 4 m veliki this.barva = "nedoloena"; } public Avto(string barvaKatera, bool tip, double velikost) { this.barva = barvaKatera; this.tip = tip;
Programiranje 1 VS Informatika

C# . NET

68

if (!this.SpremeniVelikost(velikost)) //e metoda spremeni velikost ni uspela //moramo "rono" nastaviti velikost this.velikost = 4.0; } public double PovejVelikost () { // velikost bomo povedali le na 0.5 metra natanno int velikostMetri = (int) this.velikost; int decim = (int) ((this.velikost - velikostMetri)*10); if (decim < 4) return velikostMetri + 0.0; if (decim < 5) return velikostMetri + 0.5; return velikostMetri + 4.0; } public bool SpremeniVelikost (double novaVelikost) { //smiselna nova velikost je le med 4 in 5 metri if ((4 < novaVelikost) && (novaVelikost <= 5)) { this.velikost = novaVelikost; return true; // sprememba je uspela } // v nasprotnem primeru ne spremenimo velikosti in // javimo, da spremembe nismo naredili return false; } public string PovejBarvo () { return this.barva; } public void SpremeniBarvo (string b) { this.barva = b; } public bool JeLimuzina () { return this.tip; } public string KaksenTip () { if (this.JeLimuzina()) return "limuzina"; return "kupe"; } // ker se tip avta naknadno ne spremeni, // metode za spreminjanje tipa sploh ne ponudimo uporabniku! // metoda ToString
Programiranje 1 VS Informatika

C# . NET

69

override public string ToString () { return ("Podatki o avtu so naslednji: Velikost je " + this.PovejVelikost() + "m, barva: " + this.PovejBarvo() + " in je tipa: " this.JeLimuzina() + "."); } } } //class Avto Uporaba razreda: Spodaj je naveden program, ki ustvari en avto in mu naknadno podalja dolino za 30cm. Program tudi izpie, kakne barve je avtomobil. public static void Main(string[] args) { Avto a1 = new Avto(); a1.barva = "rdea"; a1.tip = false; a1.velikost = a1.velikost + 0.3; Console.WriteLine("Avto je barve: " + a1.barva); }
Kaj je narobe s tem programom? V programu se obnaamo, kot bi bile spremenljivke, ki opisujejo objekte tipa Avto javne (public). Ker pa niso (so privatne (private)), je v vsaki od vrstic od 4 do 7 kakna napaka. Do ustreznih podatkov moramo dostopati preko metod. Popravimo program. S etrto vrstico ne bo teav a1.SpremeniBarvo("rdea"); Kaj pa 5 vrstica? Ustrezne metode za spreminjanje tipa ni. Tip avtomobilu lahko nastavimo le, ko ustvarimo nov objekt. Zato bodo potrebne malo veje spremembe. Pobrisali bomo tudi 3. vrstico in 3. 5. vrstico zamenjali z Avto a1 = new Avto("rdea", false, 4.0); S tem smo ustvarili enak avto, kot so jih prej vrstice 3. 5. Sedaj lahko spremenimo velikost. Vrstica 6 postane

a1.SpremeniVelikost(a1.PovejVelikost() + 0.3);
vrstica 7 pa

Console.WriteLine("Avto je barve: " + a1.PovejBarvo());


Dodajmo e vrstico, ki izpie novo velikost avtomobila

Console.WriteLine("Avto je dolg: " + a1.PovejVelikost());


Ko pa program poenemo, smo presenei, saj se izpie

Avto je dolg: 4.5m


Od kje pa to ali ne znamo ve raunati? 4m + 0.3m je vendar 4.3m in ne 4.5m. Z naim znanjem raunstva ni ni narobe. Le pozabiti ne smemo, da smo rekli, da bomo uporabnikom velikost avtomobila sporoali na pol metra natanno. In ker je torej za poizvedovanje po velikosti na voljo le ta metoda, ima to lahko zanimive posledice. Tako e na avto poskuamo poveati za 0.3m to sploh ni nujno mono. Na avto je sedaj dejansko dolg (vsaj podatek je tak) 4.5m. In e sedaj avto podaljamo e za 0.3m z

a1.SpremeniVelikost(a1.PovejVelikost() + 0.3);
bo njegova dejanska velikost 4.8m, eprav bo metoda PovejVelikost() sporoala, da je dolg 5m. Denarnica

Sestavi razred Denarnica, ki vsebuje tri komponente:


celotevilsko spremenljivko, ki predstavlja koliino evrov v njej celotevilsko spremenljivko, ki predstavlja koliino centov v njej spremenljivko tipa String, ki vsebuje ime lastnika denarnice.
Programiranje 1 VS Informatika

C# . NET

70

Napii vsaj dva konstruktorja:


prazen konstruktor, ki koliino evrov in centov v denarnici postavi na 0 in ime lastnika na "NEZNANO" konstruktor, ki sprejme koliko evrov in centov naj bo v denarnici in ime lastnika

Napii metode get in set. V set metodi za evre in cente preveri smiselnost podatka - e je koliina denarja, ki naj bo v denarnici, manja od 0, naj se vrednost komponente ne spremeni. Napii tudi metodo ToString, ki vrne niz V denarnici, katere lastnik je #ime_lastnika je #st_evrov evrov in #st_centov centov.
Napii program, ki ustvari tabelo desetih denarnic z nakljuno mnogo denarja. S pomojo metode izpii to tabelo. Reitev:

public class Denarnica { //komponente private int evri; private int centi; private string lastnik; //konstruktorji public Denarnica() {//prazen konstruktor, ki ustvari prazno denarnico brez lastnika this.evri = 0; this.centi = 0; this.lastnik = "NEZNANO"; } public Denarnica(int e, int c, string l) { //konstruktor, ki ustvari denarnico z e evri, c centi in lastnikom l this(); // naredimo prazno denarnico in jo // potem poskusimo napolniti this.NastaviEvre(e);//pogledamo e so podani podatki smiselni this.NastaviCente(c); this.NastaviLastnika(l); } //set, get metode public bool NastaviEvre(int e) {//set metoda, ki sprejme koliino evrov v denarnici if (e >= 0) {//koliina evrov mora biti pozitivno tevilo this.evri = e; return true; } return false;//e smo vnesli negativno vrednost, //ostane tevilo evrov enako kot prej, metoda nam vrne false }

Programiranje 1 VS Informatika

C# . NET

71

public bool NastaviCente(int c) {//set metoda, ki sprejme koliino centov v denarnici if (c >= 0) {//koliina centov mora biti pozitivno tevilo this.centi = c; return true; } return false; } public bool NastaviLastnika(string l) {//set metoda, ki sprejme ime lastnika if(l.Equals(""))//e smo vnesli prazen niz, // nam metoda ne nastavi lastnika, vrne nam false return false; else { this.lastnik = l;//e niz l ni prazen, shranimo niz l // v ime lastnika denarnice ter vrnemo true return true; } } public int VrniEvre() {//get metoda, ki vrne koliko evrov je v denarnici return this.evri; } public int VrniCente() { return this.centi; } public string VrniLastnika() {//get metoda, ki pove ime lastnika denarnice return this.lastnik; } //metoda ToString override public string ToString() {//metoda, ki izpie podatke o denarnici return "V denarnici, katere lastnik je " + this.VrniLastnika() + ", je " + this.VrniEvre() + " evrov in " + this.VrniCenti() + " centov."; } }
e program

public class TestDenarnica { public static void Main(string[] args) { Denarnica[] d = new Denarnica[10]; //ustvarimo tabelo desetih denarnic string[] lastniki = {"Ana", "Ema", "Sara", "Andreja", "Mojca", "Samo", "Ane", "Bor", "Ale", "Jure"}; //tabela lastnikov, iz katere bomo jemali lastnike denarnic
Programiranje 1 VS Informatika

C# . NET

72

Random random = new Random(); int i = 0; while (i < 10){//ustvarimo i-to denarnico z lastnikom iz tabele lastniki in s poljubno mnogo denarja med 0 in 10 evri in 0 in 150 centi d[i] = new Denarnica( (int)(random.Next(0,10)), (int)(random.Next(0,150)), lastniki[i]); i++; } // izpis IzpiTabeleDenarnic(d); } public static void IzpisTabeleDenarnic(Denarnica[] t) { int i = 0; while (i < t.Length) { Console.WriteLine(d[i].toString());//izpiemo lastnosti denarnice i = i + 1; } } }

Vaje
Zival

V ogrodju se nahaja razred Zival, ki vsebuje spremenljivke


private int steviloNog; private string vrsta; private string ime;

in metode za nastavljanje in spreminjanje le-teh. Vsebuje tudi konstruktor brez parametrov, ki postavi spremenljivke na smiselno zaetno vrednost. OGRODJE
RAZREDA

ZIVAL:

public class Zival { /*Razred predstavlja objekte tipa Zival. Vsebuje osnovne podatke o zivali, kot so vrsta, stevilo nog in ime zivali. */ //objektne spremenljivke private int steviloNog; private string vrsta; private string ime; /* Edini razredni konstruktor. Ustvari objekt Zival s stirimi nogami vrste pes in imenom Pika.
Programiranje 1 VS Informatika

C# . NET

73

*/ public Zival() { steviloNog = 4; vrsta = "pes"; ime = "Pika"; } // Vrne ime zivali. public string VrniIme() { return this.ime; } // Vrne vrsto zivali. public string VrniVrsto() { return this.vrsta; } /* Vrne stevilo nog zivali. Zagotovljeno je, da bo stevilo nog vedno vecje od 0. */ public int VrniSteviloNog() { return this.steviloNog; } /*Nastavi ime zivali.*/ public void NastaviIme(string vrednost) { if(vrednost != null) { this.ime = vrednost; } } /*Nastavi vrsto zivali.*/ public void NastaviVrsto(string vrednost) { if(vrednost != null) { this.vrsta = vrednost; } } /*Nastavi stevilo nog zivali.*/ public void NastaviSteviloNog(int vrednost) { if(vrednost > 0) { this.steviloNog = vrednost; } } }

Naloga: Dopolnite razred z metodo override public String ToString(), ki naj izpie podatke o objektih v obliki: #Ime: je vrste #vrsta in ima #steviloNog nog. Pri tem seveda zamenjajte #vrsta in #steviloNog z vrednostmi v istoimenskih spremenljivkah. Nato napiite testni program, kjer ustvarite 5 ivali in jim nastavite smiselno vrsto in imena ter tevilo nog. Izpiite jih!

Programiranje 1 VS Informatika

C# . NET

74

Razred Kolega Sestavi razred Kolega, ki ima tri komponente: ime priimek telefonska tevilka Vse tri komponente naj bodo tipa string in javno dostopne. Napii vsaj dva konstruktorja: prazen konstruktor, ki vse tri komponente nastavi na "NI PODATKOV". konstruktor, ki sprejme vse tri podatke in ustrezno nast avi komponente Napii tudi metodo public string ToString(), ki vrne niz s smiselnim izpisom podatkov o objektu tipa Kolega (ime, priimek in telefonska tevilka). Preizkus razreda Kolega Sestavi testni program, v katerem ustvari dva objekta tipa Kolega. En objekt ustvari s praznim konstruktorjem, drugega s konstruktorjem, ki sprejme tri parametre. Oba objekta tudi izpii na zaslon. Uporaba razreda Kolega Napii program, ki sestavi tabelo 10ih objektov tipa Kolega, prebere telefonsko tevilko in izpie tiste objekte iz tabele, ki imajo tako telefonsko tevilko. e takega objekta v tabeli ni, naj se izpie: "Noben moj kolega nima take telefonske tevilke." Naloge brez raunalnika Sledee naloge reuj brez uporabe raunalnika! 1. V spodnji kodi je napaka. Poii jo in jo odpravi.
Z NAPAKO

KODA

552: public class X { 553: public int a = 0; 554: public int b = 2; 555: 556: override public ToString() { 557: return "a = " + a + " b = " + b; 558: } 559: }
2. Dana je koda:

560: public class Y { 561: private int x; 562: private int y; 563: 564: public Y(int row, int col) { 565: x = row; 566: y = col; 567: } 568: }
Kateri izmed spodnjih konstruktorjev je pravilen: a. y1 = new Y(2,3); Programiranje 1 VS Informatika

C# . NET

75

b. c. d. e. f. 3.

y2 y3 y4 y5 y6

= = = = =

new new new new new

Y(2); Y; Y(); Y(10.0, 3); Y[5];

Razredu Y dodamo e konstruktor

public Y(int row) { x = row; y = 80; }


Kateri izmed konstruktorjev pa so sedaj pravilni? a. y1 = new Y(2,3); b. y2 = new Y(2); c. y3 = new Y; d. y4 = new Y(); e. y5 = new Y(10.0, 3); f. y6 = new Y[5]; 4. Dana je koda

569: public class Z { 570: private int a = 0; 571: private int b =0; 572: 573: public Z(int aa, int bb) { 574: a = aa; 575: b = bb; 576: } 577: }
Ustvarimo dva objekta tipa Z, in sicer z1 = new Z(5, 4) ter z2 = new Z(5, 4). Kakno vrednost nam vrne test z1 == z2 ? Trditev obrazloi. Kako pravilno preveriti, e sta dva objekta enaka ? Namig: metoda equals. Ali lahko metodo equals takoj uporabi v zgornji kodi, ali mora razred kaj spremeniti? 5. Dana je koda razreda Povecaj:

578: public class PovecajR { 579: public void Povecaj(int a) { 580: a++; 581: } 582: 583: public void Povecaj(int[] a) { 584: for(int i =0; i < a.Length; i++) 585: a[i] = a[i] + 2; 586: } 587: }
Ali je v kodi kakna napaka? e je, jo odpravi! Kaj izpie sledea koda?

588: 589:

PovecajR inc = new PovecajR();


Programiranje 1 VS Informatika

C# . NET

76

590: 591: 592: 593: 594: 595: 596: 597:


Datum

int a = 5; int[] b = {5}; inc.Povecaj (a); inc.Povecaj (b); Console.WriteLine("a = " + a); Console.WriteLine("b = " + b[0]);

Sestavi razred Datum, ki predstavlja datum (dan, mesec in leto). Definiraj ustrezne komponente in konstruktorje. Definiraj metodo override public string ToString(), ki vrne datum predstavljen z nizom znakov. Definiraj metodo public bool Equals(Datum d), ki vrne True, e je datum this enak datumu d. Datum 2 Razredu Datum dodaj metodo public ter vrne celo tevilo: < 0, e je this pred d 0, e je this enak d > 0, e je this za d Oseba Oseba 1 Sestavi razred Oseba, ki vsebuje podatke o osebi, in sicer: ime priimek datum rojstva Za predstavitev datuma uporabi razred Datum iz prejnje naloge. Definiraj ustrezne konstruktorje in metodo public string nizom znakov. Razred preizkusi tako, da naredi osebo, ki predstavlja tebe. Oseba 2 Razredu Oseba dodaj metodo public pravi ime in priimek, loena s presledkom.

int CompareTo(Datum d), ki primerja this in d

ToString(), ki predstavi osebo z

String Polno_ime(), ki vrne polno ime osebe, se

Oseba in datoteke Razredu Oseba dodaj metodi public void Shrani(StreamWriter ime) in konstruktor public Oseba(StreamReader ime) za zapisovanje in branje osebe z datoteke. Metoda shrani(w) zapie na w v eno vrstico podatke o osebi v obliki, ki je primerna za branje, na primer nekaj takega kot

Miha:Novak:23:7:1982 Konstruktor Oseba(r) prebere z r eno vrstico, ki je bila predhodno zapisana s Shrani, in zapie podatke v komponente objekta this.
Preveri, ali metoda in konstruktor pravilno delujeta.

Programiranje 1 VS Informatika

C# . NET

77

Oseba in datoteke 2 Razredu Oseba dodaj statini metodi public

static void ShraniSpisek(Oseba[] spisek, string dat) in public Oseba[] static NaloziSpisek(string dat), ki shranita in naloita tabelo oseb na datoteko z imenom dat.
Preveri, ali metodi pravilno delujeta. V pomo naj ti bo spisek naslednjih oseb: osebe.dat Miha:Novak:23:7:1982 Josip:Broz:7:5:1892 Josip:Plemelj:11:12:1873 Britney:Spears:12:2:1981 Kurt:Goedel:28:4:1906 Alan:Turing:23:6:1912 Leonhard:Euler:15:4:1707 Carl Friedrich:Gauss:30:4:1777 Oseba in datoteke 3 Napii statino metodo public static void rojeni_pred(string dat, Datum d), ki iz datoteke z imenom dat prebere spisek oseb in na zaslon izpie tiste osebe, ki so rojene pred datumom d. Preveri, ali metoda pravilno deluje. Majica Sestavite razred Majica, ki hrani osnovne podatke o majici: o velikost: tevilo med 1 in 5, o barvo: poljuben niz in o ali ima majica kratke ali dolge rokave. Vse spremenljivke razreda morajo biti privatne, razred pa mora tudi poznati metode za nastavljanje in branje teh vrednosti. Podpisi teh metod naj bodo: o public int VrniVelikost() ter public void SpremeniVelikost(int velikost) o public string VrniBarvo() ter public void SpremeniBarvo(string barva) o public boolean ImaKratkeRokave() ter public void NastaviKratkeRokave(boolean imaKratkeRokave) Metoda za nastavljanje velikosti majice naj poskrbi tudi za to, da bo velikost vedno ostala znotraj sprejemljivih meja! e uporabnik poskusi doloiti napano velikost, naj se obdri prejnja vrednost. Kandidat za direktorja banke V banki je direktor uspel povzroiti politini kandal taknih razsenosti, da je moral odstopiti (seveda z odpravnino v viini 50 povprenih pla) in zato sedaj isejo novega direktorja. Za to slubo se je prijavilo kar nekaj kandidatov, od katerih je vsak predloil sledee podatke: o ime o priimek o starost (v letih) o stopnjo izobrazbe - tevilka med 3 in 8 (vkljuno) Banka eli izbrati direktorja, ki ne bi bil stareji od 50 let (da bo lepo izgledal v medijih) in ima vsaj 6. stopnjo izobrazbe. Tvoja naloga je: sestaviti razred, ki bo hranil podatke o kandidatih za direktorja dopolniti priloen testni program tako, da bo nael primerne kandidate za to mesto in jih izpisal Razred Kandidat mora poleg ustreznih spremenljivk (ki naj bodo privatne!) vsebovati vsaj javne metode: Programiranje 1 VS Informatika

C# . NET

78

o o

public Kandidat () - konstruktor brez parametrov - ustvari kandidata s starostjo


20, stopnjo izobrazbe 6 in imenom in priimkom ko Neznani Neznanec.

public void NastaviImePriimek(string ime, string priimek) metoda, ki nastavi ime in priimek kandidata. e je sluajno ime oz. priimek enak null, naj starega imena in priimka ne spremeni. public string[] VrniImePriimek() - metoda, ki vrne ime in priimek kandidata. Metoda naj vrne seznam nizov doline 2 - v prvem polju naj bo zapisano ime, v drugem pa priimek kandidata. public void NastaviStarost(int starost) - metoda, ki nastavi starost kandidata. Starost mora biti v mejah med 20 in 80 let - e ni, naj se stara starost ne spremeni. public int VrniStarost() - metoda, ki vrne starost kandidata. public void NastaviIzobrazbo(int izobrazba) - metoda, ki nastavi izobrazbo kandidata. Izobrazba mora biti v mejah med 3 in 8 - e ni, naj se stara izobrazba ne spremeni. public int VrniIzobrazbo() - metoda, ki vrne izobrazbo kandidata.

o o

o o

public string ToString()

Dano je okostje programa, ki obravnava prijavljene kandidate.

598: 599: 600: 601: 602: 603: 604: 605: 606: 607: 608: 609: 610: 611: 612: 613: 614: 615: 616: 617: 618: 619: 620: 621: 622: 623: 624: 625: 626: 627: 628: 629: 630: 631:

public static Kandidat NajPrimerneji(Kandidat[] tabelaKandid) { // tu poskrbi, da bodo v ime, priimek, ... // prili podatki o najprimern. kandidatu string ime = "Moj"; string priimek = "Prijatelj"; int starost = 42; int izobrazba = 6; Kandidat nov = new Kandidat(); nov.NastaviImePriimek(ime, priimek); nov.NastaviIzobrazbo(izobrazba); nov.NastaviStarost(starost); return nov; } public static void Main(string[] args) { public string[] imena = {"Jana", "Jure", "Bernarda", "Ane", "Danijel", "Primo", "Anita", "Tina", "Matija"}; public string[] priimki = {"Mali", "Ankimer", "Zupan", "Zevnik", "Bogataj", "Koci", "Vilis", "Jere", "Lokar"}; int kolikoKandidatov = 30; public Kandidat[] kandidati = new Kandidati[kolikoKandidatov]; Random gen = new Random(); for(int i=0; i < kolikoKandidatov; i++) { Kandidat tmp = new Kandidat(); int randime = gen.Next(0, imena.Length - 1); int randpriimek = gen.Next(0,priimki.Length - 1); int randizobrazba = gen.Next(3,8); int randstarost = gen.Next(20,90); tmp.NastaviImePriimek(randime, randpriimek); tmp.NastaviIzobrazbo(randizobrazba); tmp.NastaviStarost(randstarost); kandidati[i] = tmp; }
Programiranje 1 VS Informatika

C# . NET

79

632: // tu poii najprimernejega kandidata in ga izpii 633: Console.WriteLine("Najprimernejsi je: NajPrimernejsi(kandidati)); 634: 635: 636: Console.Write("Press any key to continue . . . "); 637: Console.ReadKey(true); 638: } 639: }

"

Spremeni metodo NajPrimernejsi, tako, da vrne kandidata, ki je najmlaji in ima zahtevano stopnjo izobrazbe (ali vijo). Kandidat - najstareji Recimo, da so si v banki premislili in bi radi namesto mladega neizkuenega direktorja zaposlili najstarejega (ne glede na izobrazbo). Poii ga! Denarnica

Sestavi razred Denarnica, ki vsebuje celotevilsko spremenljivko, ki predstavlja koliino denarja v njej kot javno spremenljivko (v centih) in metodo public string ToString(), ki vrne niz "V denarnici je # centov". Ustvari tudi tabelo desetih denarnic z nakljuno mnogo denarja in jih izpii.
o o

Ali lahko na ta nain zagotovi, da v denarnici nikoli ne bo negativno mnogo denarja? Seveda ne. To bi se na primer zgodilo, e bi programer s firme Nekaj pacamo d.o.o. po pomoti vstavil v spremenljivko, ki predstavlja koliino denarja, negativno vrednost. Zato moramo razred popraviti! Namesto javne spremenljivke vzemimo privatno, poleg tega pa dopiimo e metodi dvigni in placaj, ki v denarnico dodata oz. iz nje odvzameta denar. e elimo plaati ve, kot imamo denarja v denarnici, naj metoda placaj vre napako! Opomba: namesto teh dveh metod bi lahko napisali samo t.i. "set" metodo: public void SetVrednost(int vrednost), ki koliino denarja v denarnici nastavi na vrednost (in pri tem seveda pregleda, e je ta vrednost pozitivna). Ampak glede na na razred je izbira dveh metod bolj naravna. Sestavi tudi testni program, kjer preizkusi delovanje tojega razreda. V denarnico dodaj nekaj denarja, nekaj ga odvzemi in se prepriaj, da je v njej pravilna koliina denarja. Preveri tudi plailo prevelikega zneska in ustrezno odreagiraj! Ali prejnjo nalogo sploh lahko v celoti izpolni? Denar res lahko doda in ga odvzame, ker pa je koliina denarja privatna spremenljivka razreda, je od zunaj nikakor ne more prebrati! Ta problem se rei tako, da v razred doda javno metodo public int KolicinaDenarja(), ki nam vrne koliino denarja v denarnici. Dopolni razred s konstruktorjem public Denarnica(int denar), ki ustvari denarnico z dano koliino denarja. S pomojo metode KolicinaDenarja
Programiranje 1 VS Informatika

C# . NET

80

o o

preveri, e se je tvoja denarnica pravilno inicializirala. Ustvari tudi denarnico z negativno mnogo denarja in preveri, e metode razreda Denarnica v tem primeru vrejo napako. Ne pozabi je tudi ujeti v glavnem programu, sicer se ti bo program sesul! Denarnica ima tudi svojega lastnika. Dodaj privatno spremenljivko lastnik tipa string, ki vsebuje ime lastnika denarnice. Dopolni konstruktor tako, da poleg koliine denarja sprejme tudi ime lastnika. Razredu dodaj tudi metodo VrniLastnik, ki vrne ime lastnika denarnice. Popravi tudi metodo ToString, tako da izpis vkljuuje tudi ime lastnika denarnice. Dopolni testni program tako, da ustvari tabelo desetih denarnic z nakljuno koliino denarja med 0 in 1000. Izpii jih! Kdo izmed lastnikov si lahko privoi nakup banjice sladoleda, ki stane 800 centov?

Podatkovni nosilec Sestavite razred PodatkovniNosilec, ki predstavlja medij za shranjevanje podakov. Vsebuje naj informacije o kapaciteti medija (celo tevilo, enota je bajt), izdelovalcu (niz ), osnovni ceni (celo tevilo, enota je evroCent) in stopnji obdavitve (celo tevilo, enota je procent). Vsebovati mora vsaj javne metode: public PodatkovniNosilec() - konstruktor, ki ustvari nosilec kapacitete 650Mb, proizvajalca "neznan", s ceno 100 centov in 20% davkom. public PodatkovniNosilec(string ime, int kapaciteta, int cena, int davek) - konstruktor s parametri. public void NastaviKapaciteto(int bajti) - nastavi kapaciteto medija v bajtih. e je kapaciteta negativna, naj se ne spremeni. public void NastaviIme(string ime) - nastavi ime izdelovalca medija. e je ime enako null, naj se ne spremeni. public void NastaviCeno(int cena) - nastavi ceno. e je negativna, naj se ne spremeni. public void NastaviObdavcitev(int pocent) - nastavi obdavitev v procentih. e so procenti izven meja 0-100, naj se ne stara vrednost ne spremeni. public int VrniOsnovnoCeno() - vrne osnovno ceno medija (brez davka). public double VrniDavek() - koliko davka je potrebno plaati za ta medij (v evrih). public double VrniProdajnoCeno() - vrne osnovno ceno + davek (v evrih). public string VrniIme() - vrne ime proizvajalca medija. public double VrniKapaciteto(char enota) - vrni kapaciteto v enoti, ki jo doloa znak enota: o 'b' - bajti o 'k' - kilobajti o 'M' - megabajti o 'G' - gigabajti Pazi na to, da je en kilobajt 1024 (in ne 1000) bajtov! public override string ToString() - vrne niz, ki smiselno opisuje razred. Sestavi tudi testni program, v katerem preveri delovanje tvojega razreda. Razred Zajec Denimo, da piemo program, ki bo pomagal upravljati farmo zajcev. Za vsakega zajca poznamo serijsko tevilko, spol in maso Sestavi razred Zajec, ki vsebuje komponente: spol //vrednost true, e je zajec mokega spola in false, e enskega (kaj hoete, moki ovinisti ...) masa //masa zajca v kilogramih (tip double) serijska //serijska tevilka zajca (tip string) Programiranje 1 VS Informatika

C# . NET

81

Razred Zajec naj vsebuje vsaj dva konstruktorja: Prazen konstruktor, v katerem zajcu nastavimo teo na 1.0 kg, doloimo moki spol in nastavimo serijsko tevilko na "NEDOLOENO". Konstruktor, ki sprejme maso (spremenljivka tipa double), spol (spremenljivka tipa boolean) in serijsko tevilko (spremenljivka tipa string) zajca. e eli, lahko doda e kakne konstruktorje, npr. takega, ki sprejme samo spol in serijsko tevilko zajca. Sestavi program, ki naredi tri zajce s teami, ki so nakljuna tevila med 1.2 in 5.5. Izpii vse tri tee zajcev. Enemu poveaj njegovo teo za 2kg. Izpii serijsko tevilko najlajega zajca. Metoda toString, razred Zajec V razredu Zajec napii metodo public String ToString(), ki vrne niz s smiselnim izpisom spola, serijske tevilke in mase zajca. Prejnji program spremeni tako, da vedno izpie kompletne podatke o zajcu. Metoda VrednostZajca, razred Zajec Napii metodo VrednostZajca, ki sprejme ceno za kg ive tee v evrih, in vrne vrednost zajca v . Uporaba razreda Zajec Sestavi program, ki ustvari farmo zajcev (tabelo 10 zajcev) in med njimi poie: najtejega najcenejega vse zajklje najtejega samca Spol je true za samico, razred Zajec Zaradi demostracij (al tudi nasilnih), ki jih je povzroila odloitev glede naina hranjenja podatka o spolu, smo se odloili, da v spremenljivki spol ne bomo ve hranili true za samca, ampak za samico. Kaj vse moramo spremeniti v razredu Zajec? Kaken vpliv ima to na program, ki si ga napisal pri nalogi Uporaba razreda Zajec? Spol ni ne true, ne false ampak m in f, razred Zajec Po spremembi opisani zgoraj je ponorel moki del populacije. Zato bomo spremenljivko spol spremenili v tip char in tam hranili 'm' za samca in 'f' za samico. Kaj vse moramo spremeniti v razredu Zajec? Get in set metode v razredu Zajec Vsem trem komponentam v razredu Zajec spremeni nain dostopa iz public v private. Ker sedaj ni ve mogoe dostopati do komponent neposredno (npr. zajcek.serijska), dodaj e get in set metode za vraanje in nastavljanje vrednosti vseh treh komponent. Set metode napii tako, da v njih preveri, e je podana vrednost smiselna (npr. smislena nova masa je le med 0 in 10 kg). e je podana vrednost smiselna, naj metoda nastavi komponento na to vrednost in vrne true. Sicer naj se vrednost komponente ne spremeni in metoda naj vrne false. Metode za nastavljanje vrednosti komponent uporabi tudi v tistih konstruktorjih, ki sprejmejo podatke od uporabnika. Toka Da bi se zajci bolje poutili, jim kmet vsak dan dovoli par ur skakljanja po travniku. Ker pa je travnik velik, je moral spremljati poloaj vsakega zajca (da jih ne bi kdo ukradel in snedel). V tam namem napii razred Tocka, ki naj vsebuje spremenljivki x in y tipa double. Napii ustrezne konstruktorje - osnovni konstruktor (brez parametrov) naj toko postavi v koordinatno izhodie. Dopii tudi metodi za nastavljanje in spreminjanje lege toke (vsake kompomente posebej). Zajci na travniku Popravi razred Zajec tako, da mu doda parameter tipa Tocka, ki doloa lego na travniku. Dodaj ustrezen konstruktor in upotevaj, da mora toko ustvariti tudi v konstruktorjih, kjer lege ne dobi kot podatek. V takem primeru naj bo zajec v koordinatnem izhodiu. Dopolni razred Zajec z metodama za branje in spreminjanje lege zajca. Zajci na travniku II Ker je kmet travnik ogradil z ograjo, se zajci lahko nahajajo samo znotraj v naprej znanega obmoja, recimo v kvadratu s spodnjim levim krajiem v toki (0,0) in irino ter viino 100 metrov. Programiranje 1 VS Informatika

C# . NET

82

Popravi konstruktor in metodo za nastavljanje pozicije zajca tako, da ne bo dovolil vnosa napane lege zajca (izven dovoljenga obmoja)! Pri tem bodi pozoren na to, da mora pri branju lege zajca vrniti duplikat toke, saj bo drugae uporabnik lahko v toko od zunaj vnesel napane podatke! Mogoe se ti splaa napisati metodo public static Tocka Kopija(Tocka t) v razredu Tocka, ki vrne kopijo toke t - torej novo toko na istih koordinatah. Razdalja med dvema tokama Ker velikokrat pride prav, da izraunamo razdaljo med dvema tokama, dopolni razred Tocka z metodo public double Razdalja(Tocka t), ki vrne razdaljo med trenutno toko in toko t, ki jo metoda dobi kot parameter. Razdalja med dvema zajcema Dopolni razred Zajec z metodo RazdaljaMedZajcema, ki kot parameter sprejme drugega zajca in vrne razdaljo med njima. Uporaba razreda Zajec II Oboroeni z novimi metodami dopolnimo na program za gojenje zajcev tako, da generira zajce na nakljunih poloajih. Nazadnje poiimo zajca, ki je: 1. najbolj oddaljen od prvega zajca 2. najbolj oddaljen od koordinatnega izhodia 3. ima najveji produkt med maso in oddaljenostjo od zhodia Razred Ulomek

Podana je koda razreda Ulomek. Dopolni manjkajoe metode ter v glavnem programu (metoda Main) ustvari dva ulomka, katerih tevec in imenovalec naj bo nakljuno tevilo med med 1 in 9 (vkljuno z mejama). Ulomka setej in rezultat izpii na zaslon. RAZRED ULOMEK
public class Ulomek { 640: int stevec; 641: int imenovalec;

642: 643: 644: 645: 646: 647: 648: 649: 650: 651: 652: 653: 654: 655: 656: 657: 658: 659: 660: 661: 662:

// Privzeti konstruktor ustvari ulomek 1/1 // DOPOLNI!

// Ustvari podani ulomek. Pazi tudi na pravilnost podatkov.

// Ce so napani, ustvari enak ulomek kot v privzetem // konstruktorju. public Ulomek(int stevec, int imenovalec) { // DOPOLNI! } // Metoda priteje ulomek u k trenutnemu ulomku. public void Pristej(Ulomek u) { // DOPOLNI! } // Metoda zmnoi trenutni ulomek z ulomkom u ter // zmnoek vrne kot rezultat. Trenutni ulomek ter // ulomek u se pri tem ne smeta spremeniti. public DOPOLNI Zmnozi(Ulomek u) {
Programiranje 1 VS Informatika

C# . NET

83

663: // DOPOLNI! 664: } 665: // Metoda vrne vrednost ulomka kot realno tevilo. 666: public DOPOLNI Vrednost() { 667: // DOPOLNI! 668: } 669: 670: // Vrne niz oblike stevec/imenovalec 671: DOPOLNI string ToString() { 672: // DOPOLNI! 673: } 674: 675: // Metoda okraja dani ulomek 676: public void Okrajsaj() { 677: // DOPOLNI 678: } 679: 680: // Obratna vrednost. 681: public void Obrni() { 682: // DOPOLNI 683: } 684: } TESTNI PROGRAM
public class TestUl 685: public static void Main(string[] argc) { 686: // DOPOLNI po navodilih naloge! 687: } 688: }
Razred Stranka Na osnovi kode spodaj podanega razreda Oseba sestavite razred Stranka, ki predstavlja banno strankoega komitenta. Poleg lastnosti, so enake kot v razredu Oseba, mora hraniti tudi podatke o tekoem raunu (niz), tevilki EMO (niz) ter povprenem mesenem prilivu na tekoi raun (realno tevilo).

RAZRED OSEBA
public class Oseba { private string ime; private string priimek; public Oseba(string ime, string priimek) { this.ime = ime; this.priimek = priimek; } public string VrniIme() { return this.ime; } public string VrniPriimek() { return this.priimek; }
Programiranje 1 VS Informatika

C# . NET

84

}
Pri tem mora razred zadoati naslednjim pogojem: Vse spremenljivke v njem morajo biti privatne. Poznati mora javni konstruktor, ki sprejme pet parametrov: ime, priimek, tevilko tekoega rauna, tevilko EMO ter podatek o povprenem mesenem prilivu na raun. Pri tem mora biti zadnji podatek pozitivni+o realno tevilo, prvi tirje pa neprazni nizi. e to ni izpolnjeno, ustrezno reagiraj. Poznati mora metode za vraanje podatkov, ki jih hrani: imena, priimka, tevilke tekoega rauna, tevilke EMO ter povprenega priliva na raun. Metoto ToString, ki na smiselen nain izpie podatke o stranki. Nazadnje sestavite testni program, kjer ustvarite tabelo desetih strank z izmiljenimi podatki, ter med njimi poite stranko z najvijim mesenim prilivom na raun ter tistega z po leksikografski urejenosti prvim imenom (e jih je ve z enakim najvejim prilivom ali enakim prvim imenom poiite kateregakoli) ter izpiite njune podatke na zaslon (z uporabo metode ToString). Kubini polinom Na osnovi razreda Polinom, ki hrani polinome do stopnje dva in pozna operacijo setevanja dveh polinomov (njegovo kodo glej spodaj) sestavi razred KubicniPolinom, ki bo lahko hranil kubine polinome ter bo poleg vsote podpiral tudi operacijo, ki obstojei polinom pomnoi s skalarjem (spremeni torej obstojei objekt in ne ustvari novega). Seveda naj tvoj razred ne pozabi na metodo ToString, ki v razredu Polinom manjka.

RAZRED POLINOM
//razred predstavlja polinom oblike ax^2 + bx + c public class Polinom { private double a, int b, int c; //Ustvari nielni polinom. public Polinom() { this.a = this.b = this.c = 0; } //Ustvari polinom z danimi koeficienti. public Polinom (double a, double b, double c) { this.a = a; this.b = b; this.c = c; } public Polinom Sestej(Polinom p) { return new Polinom(this.vrniKoeficient(2) + p.vrniKoeficient(2), this.vrniKoeficient(1) + p.vrniKoeficient(1), this.vrniKoeficient(0) + p.vrniKoeficient(0)); } //metoda nam vrne koeficient pred x^i public int VrniKoeficient(int i) { if (i == 2) return this.a; if (i == 1) return this.b;
Programiranje 1 VS Informatika

C# . NET

85

if (i == 0) return this.c; return 0; } //Metoda nastavi koeficient pred x^i na k. //e je i napaen, naj ne stori ni public void NastaviKoeficient (int i, double k) { if (i == 2) this.a = k; else if (i == 1) this.b = k; else if (i == 0) this.c = k; } }
Sestavi testni program, ki vsebuje metodo, ki zna odteti dva kubina polinoma (vrne polinom, ki je razlika dveh polinomov). Namig. p1 p2 lahko izrauna kot p1 + ((-1)*p2). Pregledno izpii nekaj raunov s polinomi. Polinom Sestavi razred s pomojo katerega predstavi poljubni polinom. Namig: koeficiente hrani v tabeli. Razred naj pozna enake metode kot razred KubicniPolinom. Dalmatinci I (brez raunalnika) Denimo, da smo eleli sestaviti razred Dalmatinec, ki ima lastnosti ime psa in tevilo njegovih pik. Koda razreda je:

RAZRED DALMATINEC
public class Dalmatinec{ public string ime; private int steviloPik; public Dalmatinec() { this.ime = "Reks"; this.steviloPik = 0; } public void ImePsa(string ime) { ime = this.ime; } private void NastaviIme(string ime) { this.ime = ime; } public void NastaviSteviloPik(int steviloPik) { this.steviloPik = steviloPik; } }
V glavnem programu smo ustvarili objekt Dalmatinec z imenom d in mu elimo nastaviti tevilo pik na 100 in ime na Pika. Kateri nain je pravilen? Pri nepravilnih povej, kaj in zakaj ni pravilno. a) d.NastaviIme("Pika"); d.NastaviSteviloPik(100); Programiranje 1 VS Informatika

C# . NET

86

b) d.ime = "Pika"; d.steviloPik = 100; c) d.ime = "Pika"; d.NastaviSteviloPik(100); d) d.imePsa("Pika"); d.NastaviSteviloPik(100); e) d.imePsa("Pika"); d.steviloPik = 100; f) d.NastaviIme("Pika"); d.steviloPik = 100; g) nobeden, ker tega sploh ne moremo storiti Dalmatinci II Sedaj elimo naemo razredu Dalmatinec dodati tudi podatke o spolu psa. Ta podatek bomo hranili v spremenljivki spol. Interno (znotraj razreda) naj logina vrednost true pomeni enski, false pa moki spol. Dopolnite razred tako, da bo zadoal naslednjim trem pogojem: Spremenljivka spol naj ne bo dostopna izven razreda Dalmatinec obstaja naj metoda KaksenSpol, ki v primeru samca vrne 'm', v primeru samice pa 'f'. spol se nastavi le ob ustvarjanju objekta. Morali boste torej napisati konstruktor razreda Dalmatinec, ki sprejme kot parameter znak za spol. Ta naj bo kot zgoraj 'm' za samca in 'f' za samico. Predpostavite, da bo parameter zagotovo znak 'm' ali 'f'.

Dalmatinci III Predpostavimo, da razred, ki zadoa kriterijem naloge Dalmatinci III, e imamo. Sestavi metodo public static int SteviloSamcev(Dalmatinec[] dalmatinci), ki preteje tevilo samcev v tabeli dalmatincev. Oseba Podan imamo razred Oseba z objektnima metodama VrniIme() ter VrniPriimek() (ki nam vrneta niza, ki predstavljata ime oz. priimek osebe). Sestavite metodi, ki: a. iz tabele tipa Oseba[] izpie vse osebe z imeni dolgimi 5 znakov. b. iz tabele tipa Oseba[], kjer so osebe urejene po priimkih (ter nato po imenih), uinkovito poiite osebo Janez Novak, ter kot rezultat metode vrnite referenco na to osebo. e takna oseba ne obstaja, vrnite null. Oseba II Podan imamo razred Oseba z objektnima metodama VrniIme() ter VrniPriimek() (ki nam vrneta niza, ki predstavljata ime oz. priimek osebe). Sestavite statini metodi, ki: a. Za dano tabelo tipa Oseba[] izpie priimke vseh oseb, katerih skupna dolina imena in priimka presega k znakov, kjer je k parameter metode. b. V tabeli tipa Oseba[], kjer so osebe urejene po priimkih, uinkovito poiite poljubno osebo s priimkom Novak (ime torej ni pomembno), ter kot rezultat metode vrnite nov objekt, ki ima podatke enake kot najdena oseba. e takna oseba ne obstaja, vrnite null. Zgoenka Pesem na zgoenki je predstavljena z objektom razreda Pesem: public class Pesem { public string naslov; public int minute; public int sekunde; Programiranje 1 VS Informatika

C# . NET

87

public Pesem(string nasl, int min, int sek) { naslov = nasl; minute = min; sekunde = sek; } } Na primer, objekt new Pesem("Echoes",15,24) predstavlja pesem Echoes, ki traja 15 minut in 24 sekund. (a) Sestavi razred Zgoscenka, ki vsebuje naslov zgoenke, ime izvajalca in tabelo pesmi na zgoenki. Predpostavi, da vse podatke (naslov, izvajalca in tabelo pesmi) obvezno dobi s konstruktorjem in jih naknadno nikoli ne sme (more) spremeniti. Definiraj ustrezne komponente s pravilnim dostopom in konstruktor. (b) Razredu Zgoscenka dodaj objektno metodo Dolzina(), ki vrne skupno dolino vseh pesmi na zgoenki, izraeno v sekundah. (c) Razredu Zgoscenka dodaj objektno metodo PovprecnaDolzina(), ki vrne povpreno dolino vseh pesmi na zgoenki, izraeno v sekundah.

Statino in objektno
Statine komponente o V razredu Kvader public static final int MIN_DOL_STR = 1; o final gre za konstanto Ni novega, e poznamo o static Obstajajo neodvisno od obstoja objekta tega razreda Le en primerek za cel razred! Math.PI Statine spremenljivke public class Foo { public static int x = 13; public int y; public Foo(int z) { this.y = z; } } o x: statina komponenta, y: objektna (nestatina) komponenta o Statine komponente: vsebovane v razredu, objektne komponente: v objektih. o Vsak objekt vsebuje svojo kopijo objektnih komponent, vsaka statina komponenta pa vedno obstaja v eni sami kopiji. Foo t1 = new Foo(42); Foo t2 = new Foo(30);

o Dva objekta - dve kopiji komponente y, po eno v vsakem objektu. Ker je komponenta x statina, vedno obstaja v eni sami kopiji, tudi e nimamo nobenih objektov razreda Foo:

Programiranje 1 VS Informatika

C# . NET

88

Uporaba statinih spremenljivk o Razline konstante o Enolina identifikacija Objekt naj ima svojo serijsko tevilko Denimo, da so te tevilke zaporedne Vedeti, katera je bila dodeljena zadnja Zadnja dodeljena tevilka: ni lastnost objekta, ampak cele skupine objektov o Vedno, ko je doloen podatek skupen za vse objekte tega razreda o Kako vemo, ali naj bo komponenta statina ali objektna? Statine komponente so tiste, ki so skupne za celoten razred niso posebna lastnost enega (ali nekaj) primerkov objektov tega razreda. Statine komponente dostop o public ali private (odvisno od eljenega naina dostopa) o public praviloma le, e gre za konstante zaradi final ni teav s pravilnostjo podatkov konstante imajo nain dostopa private, e jih elimo "skriti" pred uporabniki Statine komponente naslavljanje Naslavljanje (e je dostop public): ime_objekta.ime_komponente ali ime_razreda.ime_komponente ali (znotraj razreda) ime_komponente Praviloma: ime_razreda.ime_komponente Izogibamo se ime_objekta.ime_komponente, saj ta komponenta ni vezana na objekt! Ni potrebno, da bi sploh obstajal kak objekt te vrste Zajec o Radi bi vedeli, koliko zajcev imamo o tevec ustvarjenih objektov NI lastnost posameznega zajca SKUPNA lastnost private static int kolikoZajcev = 0; Na zaetku 0 Spreminjamo takrat, ko ustvarimo novega zajca new V konstruktorju! o Serijska tevilka naj bo zagotovo enolina Doloimo jo le enkrat ob rojstvu (konstruktor) ZAJEC_n (e je to n-ti zajec)

Programiranje 1 VS Informatika

C# . NET

89

RAZRED ZAJEC
418: public class Zajec { 419: // SKUPNE SPREMENLJIVKE 420: private static string OsnovaSerijska = "ZAJEC_"; 421: private static int kolikoZajcev = 0; 422: public static final int MIN_TEZA = 0; // minimalna tea 423: public static final int MAX_TEZA = 10; // maksmialna tea 424: 425: // OBJEKTNE SPREMENLJIVKE 426: private string serijska; 427: private bool spol; 428: private double masa; 429: 430: // konstruktorji 431: 432: public Zajec() { 433: this.spol = true; // vsem zajcem na zaetku doloimo m. spol 434: this.masa = 1.0; // in tehtajo 1kg 435: ZajecNov.kolikoZajcev++; // NAREDILI SMO NOVEGA ZAJCA 436: this.serijska = ZajecNov.OsnovaSerijska + ZajecNov.kolikoZajcev; 437: } 438: public Zajec(bool spol, double masa) { 439: this(); // poklicali smo konstruktor Zajec() - ta 440: // bo e poveal tevilo zajcev + naredil 441: // nj. ser. tevilko 442: this.SpremeniTezo(masa); // uporabimo metodo za sprem. 443: this.spol = spol; 444: } 445: 446: // get/set metode 447: 448: public double PovejTezo() { 449: // teo bomo povedali le na 0.5 kg natanno 450: int tezaKg = (int)this.masa; 451: int decim = (int)((this.masa - tezaKg) * 10); 452: if (decim < 3) return tezaKg + 0.0; 453: if (decim < 8) return tezaKg + 0.5; 454: return tezaKg + 1.0; 455: } 456: 457: public bool SpremeniTezo(double novaTeza) { 458: // smislena nova teza je le med MIN_TEZA in MAX_TEZA 459: if ((novaTeza > MIN_TEZA) && (novaTeza <= MAX_TEZA)){ 460: this.masa = novaTeza; 461: return true; // sprememba uspela 462: } 463: // v nasprotnem primeru NE spremenimo tee 464: // in javimo, da spremembe nismo naredili 465: return false; 466: } 467: 468: public string PovejSerijsko() { 469: return this.serijska; 470: }
Programiranje 1 VS Informatika

C# . NET

90

471: 472: // public void SpremeniSerijsko(string s) { TO IZLOIMO; 473: // KER SE SER_T NE SPREMINJA! 474: 475: public bool JeSamec() { 476: return this.spol; 477: } 478: 479: // ker se spol naknadno NE spremeni, metode za 480: // spreminjanje spola sploh ne ponudimo uporabniku! 481: 482: // Ostale metode 483: 484: public double Vrednost(double cenaZaKg) { 485: // pove vrednost zajca 486: // zajce tehtamo na dogovorjeno natannost 487: return cenaZaKg * this.povejTezo(); 488: } 489: 490: public bool MeNapojiti() { 491: // ugotovimo, e ga je smiselno 492: // napojiti, da bomo "ujeli" naslednjih pol kg 493: // dejanska tea je veja od "izmerjene" 494: return (this.masa - this.povejTezo() > 0); 495: } 496: 497: } // Zajec
tetje ustvarjenih objektov V konstruktorjih poveujemo tevec

RAZRED KVADER
498: public class Kvader { 499: // z /* ... */ so oznaceni komentarji za razlago 500: // zakaj doloceni konstrukcijski prijemi 501: // v "pravem" programu jih ne bi bilo! 502: 503: private double a; /* uporabnika ne zanima, kako 504: imamo shranjene podatke */ 505: private double b; 506: private double c; 507: 508: private int serijskaStevilka; // serijska stevila objekta 509: 510: private static int kolikoNasJe = 0; // koliko je 511: // ustvarjenih objektov 512: 513: public static final int MIN_DOL_STR = 1; // minimalna 514: // dolzina stranice 515: public static final int MAX_DOL_STR = 100; // maksimalna 516: // dolzina stranice 517: /* Ker menimo, da je smiselno, da uporabnik neposredno 518: vidi ti dve kolicini - dostop 519: public. Spreminjati ju ne more zaradi final. 520: Dostop: Kvader.MIN_DOL_STR
Programiranje 1 VS Informatika

C# . NET

91

521: 522: 523: 524: 525: 526: 527: 528: 529: 530: 531: 532: 533: 534: 535: 536: 537: 538: 539: 540: 541: 542: 543: 544: 545: 546: 547: 548: 549: 550: 551: 552: 553: 554: 555: 556: 557: 558: 559: 560: 561: 562: 563: 564: 565: 566: 567: 568: 569: 570: 571: 572: 573: 574:

Doloilo static - gre za razredno spremenljivko - 1 kopija za vse objekte */ // vrni podatek public int PovejA() { /* omogocimo uporabniku dostop do vrednosti zanj zanimivih podatkov */ return (int)this.a; } public int PovejB() { return (int)this.b; } public int PovejC() { return (int)c; } private bool Kontrola(int x){ /* pomozna metoda, zato private */ // preverimo, ce velja MIN_DOL_STR <= x <= MAX_DOL_STR return ((MIN_DOL_STR <= x) && (x <= MAX_DOL_STR)); } // nastavi podatek public void StranicaA(int a) { /* omogocimo uporabniku spreminjanje podatkov */ // Ce je podatek v mejah med 1 in 100, ga spremenimo, // drugace pustimo // taksnega, kot je if (Kontrola(a)) this.a = a; /* this je potreben, da locimo med imenom podatka objekta in parametrom a */ /* verjetno bi bilo bolj smiselno namesto a parameter poimenovati s ali kako drugae */ } public void StranicaB(int a) { // Ce je podatek v mejah med 1 in 100, ga spremenimo, // drugace pustimo // taksnega, kot je if (Kontrola(a)) this.b = a; /* this v nasprotju s prejsnjo metodo tu ni potreben. se vedno pa velja, da bi bilo boljse, da bi parameter a poimenovali drugace - npr. s */ } public void StranicaC(int s) { // Ce je podatek v mejah med 1 in 100, ga spremenimo, // drugace pustimo // taksnega, kot je if (Kontrola(s)) /* na ta nacin bi verjetno "zares" sprogramirali tudi
Programiranje 1 VS Informatika

C# . NET

92

575: 576: 577: 578: 579: 580: 581: 582: 583: 584: 585: 586: 587: 588: 589: 590: 591: 592: 593: 594: 595: 596: 597: 598: 599: 600: 601: 602: 603: 604: 605: 606: 607: 608: 609: 610: 611: 612: 613: 614: 615: 616: 617: 618: 619: 620: 621: 622: 623: 624: 625: 626: 627: 628:

zgornji metodi */ c = s; } //........................................... // konstruktorji public Kvader() { a = b = c = 1; kolikoNasJe++; serijskaStevilka = kolikoNasJe; } public Kvader(int s) { // kocka s stranico s. e podatek ni v redu - kocka z robom 1 if (!kontrola(s)) s = 1; // ce podatek ni v mejah, // ga postavimo na 1 a = b = c = s; kolikoNasJe++; serijskaStevilka = kolikoNasJe; } public Kvader(int s1, int s2, int s3) { // kvader s1 x s2 x s3 // Ce kak podatek ni v redu - ga postavimo na 1 if (!kontrola(s1)) s1 = 1; // ce podatek ni v mejah, // ga postavimo na 1 a = s1; if (!Kontrola(s2)) s2 = 1; // ce podatek ni v mejah, // ga postavimo na 1 b = s2; if (!Kontrola(s3)) s3 = 1; // ce podatek ni v mejah, // ga postavimo na 1 c = s3; kolikoNasJe++; serijskaStevilka = kolikoNasJe; } public Kvader(Kvader sk) { // Novi objekt je kopija obstojecega objekta sk this.a = sk.a; /* this ni potreben */ StranicaB(sk.PovejB()); /* tudi znotraj razreda se splaca uporabljati metode za delo s podatki */ StranicaC(sk.PovejC()); /* ceprav imamo neposreden dostop do spremenljivk, saj nam ob morebitni spremembi predstavitve ni potrebno toliko popravljati! */ kolikoNasJe++; serijskaStevilka = kolikoNasJe; }
Programiranje 1 VS Informatika

C# . NET

93

629: 630: public static int PovejKolikoNasJe() { 631: return kolikoNasJe; 632: } 633: 634: // 635: // --------------- to string 636: // 637: public string ToString() { /* prekrivanje metode iz razreda 638: Object */ 639: // Metoda vrne podatek v obliki Kvader: a x b x c 640: return "Kvader: " + PovejA() + " x " + PovejB() + " x " 641: + PovejC(); 642: /* tudi znotraj razreda se splaca uporabljati metode za 643: delo s podatki ceprav imamo neposreden dostop do 644: spremenljivk, saj nam ob morebitni spremembi predstavitve 645: ni potrebno toliko popravljati! */ 646: } 647: 648: } // class Kvader
Zgled 2: Uporaba konstant Meje pravilnosti podatkov so konstantne

689: public class Kovanec_nov { 690: 691: private int polmer; 692: private int visina; 693: public static final int OBI_POLMER = 3; // obicajni polmer 694: public static final int OBI_VISINA = 1; // obicajna visina 695: public static final int NAJ_POLMER = 3; // najveji moni polmer 696: public static final int NAJ_VISINA = 1; // najveja mona visina 697: 698: 699: // konstruktorji 700: public Kovanec() { 701: // "obicajni" kovanec 702: this.polmer = OBI_POLMER; 703: this.visina = OBI_VISINA; 704: } 705: 706: public Kovanec(int polmer, int visina) { 707: // "drugacni" kovanec 708: // ce ni ustreznih dimenzij, naredimo "obicajni" kovanec 709: if { (Vmes(polmer, 1, NAJ_POLMER) && 710: Vmes(visina, 1, NAJ_VISINA)) 711: // mere so v redu 712: this.visina = visina; 713: this.polmer = polmer; 714: } 715: else { // ce ni ustreznih dimenzij 716: this.polmer = OBI_POLMER;
Programiranje 1 VS Informatika

C# . NET

94

717: 718: 719: 720: 721: 722: 723: 724: 725: 726: 727: 728: 729: 730: 731: 732: 733: 734: 735: 736: 737: 738: 739: 740: 741: 742: 743: 744: 745: 746: 747: 748: 749: 750: 751: 752: 753: 754: 755: 756: 757: 758: 759: 760: 761: 762: 763: 764: 765: 766: 767: 768: 769: 770:

this.visina = OBI_VISINA; } } // "SET" metode public bool NastaviPolmer(int r) { // smiselni polmer je le med 1 in NAJ_POLMER // drugace ga pustimo pri miru // metoda vrne vrednost true, ce smo polmer spremenili if (Vmes(r, 1, NAJ_POLMER)) { this.polmer = r; return true; } return false; // polmer je ostal nespremenjen } public bool NastaviVisino(int visina) { // smiselni polmer je le med 1 in NAJ_VISINA // drugace jo pustimo pri miru // metoda vrne vrednost true, ce smo visino spremenili if (vmes(visina, 1, NAJ_VISINA)) { this.visina = visina; return true; } return false; // visina je ostala nespremenjena } // "GET" metode public int PovejPolmer() { return polmer; } public int PovejVisino() { return visina; } // tostring override public string ToString() { return "Polmer: " + this.polmer + " visina: " + this.visina; } // volumen in povrsina public double Volumen() { // volumen kovanca PI * r^2 * v return Math.PI * this.polmer * this.polmer * this.visina; } public double Povrsina() { // povrsina kovanca 2 * PI * r * v + 2 * PI * r^2 return (2 * Math.PI * this.polmer) * (this.polmer + this.visina); } // pomozne metode private static bool Vmes(int x, int a, int b) {
Programiranje 1 VS Informatika

C# . NET

95

771: // ali je x med a in b 772: return (a <= x) && (x <= b); 773: } 774: }
Statine metode Objekt: Objektne komponente Objektne metode Skupno vse objektom na nivoju razreda: statine metode statine komponente Statine metode se v neobjektnih programskih jezikih imenujejo "funkcije" ali "procedure", statine komponente pa se imenujejo "globalne spremenljivke". Statine/objektne metode Statino metodo bla() v razredu Foo lahko vedno izvedemo z ukazom Foo.bla(). Znotraj statine metode objekt this ni definiran, ker se statina metode ne klie na objektu. Objektno metodo hej() v razredu Foo lahko izvedemo, e imamo neki objekt x razreda Foo, z ukazom x.hej(). Znotraj metode hej() oznauje this objekt, na katerem je metoda poklicana. Zgled

649: public class Foo { 650: static public int x = 12; 651: public int y; 652: 653: public Foo(int z) { 654: this.y = z; 655: } 656: 657: public static int F(int a) { 658: return x + a; 659: } 660: // ali return Foo.x + a; 661: 662: public int G(int a) { 663: return this.y + Foo.x + a; 664: } 665: // ali y + Foo.x + a ALI y + x + y ALI ... 666: }
Statina metoda F ima dostop do (statine) komponente x. Dostopa do komponente y nima, saj znotraj statine metode ne moremo pisati this.y. Objektna metoda G ima dostop do komponente this.y, kjer je this objekt, na katerem je metoda g klicana. Prav tako ima dostop do (statine) komponente x.

int p Foo.x int q Foo t Foo s int r

= = = = = =

Foo.G(7); // p == 12 + 7 == 19 -3; Foo.F(5); // q == -3 + 5 == 2 new Foo(100); new Foo(200); t.G(50); // r == 100 + (-3) + 50 == 147
Programiranje 1 VS Informatika

C# . NET

96

Statine metode o Kadar za izvajanje ne potrebujemo objekta tega razreda. o Praviloma ne spreminjajo stanja nekega objekta. o Vsi podatki podani preko parametrov metode. o Main

667: public class Kovanec_nov { 668: 669: private int polmer; 670: private int visina; 671: public static final int OBI_POLMER = 3; // obicajni polmer 672: public static final int OBI_VISINA = 1; // obicajna visina 673: public static final int NAJ_POLMER = 3; // najveji moni polmer 674: public static final int NAJ_VISINA = 1; // najveja mona visina 675: 676: // konstruktorji 677: public Kovanec() { 678: // "obicajni" kovanec 679: this.polmer = OBI_POLMER; 680: this.visina = OBI_VISINA; 681: } 682: 683: public Kovanec(int polmer, int visina) { 684: // "drugacni" kovanec 685: // ce ni ustreznih dimenzij, naredimo "obicajni" kovanec 686: if (Vmes(polmer, 1, NAJ_POLMER) && Vmes(visina,1,NAJ_VISINA)){ 687: // mere so v redu 688: this.visina = visina; 689: this.polmer = polmer; 690: } 691: else { // ce ni ustreznih dimenzij 692: this.polmer = OBI_POLMER; 693: this.visina = OBI_VISINA; 694: } 695: } 696: 697: // "SET" metode 698: public bool NastaviPolmer(int r) { 699: // smiselni polmer je le med 1 in NAJ_POLMER 700: // drugace ga pustimo pri miru 701: // metoda vrne vrednost true, ce smo polmer spremenili 702: if (Vmes(r, 1, NAJ_POLMER)) { 703: this.polmer = r; 704: return true; 705: } 706: return false; // polmer je ostal nespremenjen 707: } 708: 709: public bool NastaviVisino(int visina) { 710: // smiselni polmer je le med 1 in NAJ_VISINA 711: // drugace jo pustimo pri miru 712: // metoda vrne vrednost true, ce smo visino spremenili 713: if (Vmes(visina, 1, NAJ_VISINA)) {
Programiranje 1 VS Informatika

C# . NET

97

714: 715: 716: 717: 718: 719: 720: 721: 722: 723: 724: 725: 726: 727: 728: 729: 730: 731: 732: 733: 734: 735: 736: 737: 738: 739: 740: 741: 742: 743: 744: 745: 746: 747: 748: 749: 750: 751: }

this.visina = visina; return true; } return false; // visina je ostala nespremenjena } // "GET" metode public int PovejPolmer() { return polmer; } public int PovejVisino() { return visina; } // ToString override public string ToString() { return "Polmer: " + this.polmer + " visina: " + this.visina; } // volumen in povrsina public double Volumen() { // volumen kovanca PI * r^2 * v return Math.PI * this.polmer * this.polmer * this.visina; } public double Povrsina() { // povrsina kovanca 2 * PI * r * v + 2 * PI * r^2 return (2 * Math.PI * this.polmer) * (this.polmer + this.visina); } // pomozne metode private static bool Vmes(int x, int a, int b) { // ali je x med a in b return (a <= x) && (x <= b); }

Privatne metode o Tudi metode so lahko privatne (glej prejnji zgled) objektne, statine o private void metodaA() {...}; o private static int metodaB{...}; o Kadar metodo potrebujemo interno uporabnikom ni potrebna!

Dedovanje
Pogosto uporabljani postopki I Imamo razred Ulomek: Programiranje 1 VS Informatika

C# . NET

98

Denimo, da z ulomki zelo pogosto izvajamo doloen postopek: npr. jim spremnimo predznak Napiemo ustrezno metodo. Vedno, ko elimo ulomkom spreminjati predznak, moramo napisati to metodo: Naredimo iz nje knjinico "zaprimo v svoj razred" Ampak to ni "objektno": Znanje spreminjanja predznaka je ulomku elvi objektu Ulomek (objekt) naj bi znala spremniti predznak : Odzvati se metodi spremeniPredznak: nekUlomek.spremeniPredznak() Imamo Ulomek.java: Ni problem, dopiemo metodo Popravljati dobro preizkuen razred? ... Do not fix, until you are completely desperate ... Kaj pa, e izvorne kode nimamo? Dedovanje o "razirjanje" objektov o Naredimo nart za razred boljih ulomkov Bolji: Znajo spremniti predznak o public class BoljsiUlomek : Ulomek o Vsaka bolji ulomek "zna" vse, kar zna obipajni ulomek iz razreda Ulomek in morda e kaj o Ima ista stanja/lastnosti Morebiti tudi dodatna Razred BoljsiUlomek

752: public class BoljsiUlomek : Ulomek { 753: // naredimo nov razred "boljih ulomkov" 754: public void SpremeniPredznak() { 755: // Vsaka bolji ulomek si zna 756: // spremeniti predznak 757: Ulomek pom = new Ulomek(-1, 1); 758: this.Pomnozi(pom); // lahko tudi brez this 759: // metoda pomnozi je podedovana iz razreda Ulomek 760: } 761: }
Uporaba Boljega ulomka

762: public class Test4 { 763: public static void Main(string[] args) { 764: BolsiUlomek boUl; 765: boUl = new BoljsiUlomek(); // "ustvarimo" bolji ulomek 766: Ulomek navadniUl = new Ulomek(); 767: // spremenimo predznak navadnega ulomka 768: navadniUl.Pomnozi(new Ulomek(-1,1)); // "aramo" 769: boUl.SpremeniPredznak(); // pri "boljih" ulomkih je zadeva
Programiranje 1 VS Informatika

C# . NET

99

770: 771: 772: }

// elegantneja }

Pogosto uporabljani postopki Denimo, da imamo na voljo razred Turtle. S tem razredom znamo ustvariti objekt, elvo, ki zna reagirati na ukaze (pozna metode):

Fd(int n) Rt(int st) PenUp() PenDown()

Zgled: Denimo, da z elvo zelo pogosto izvajamo doloen postopek. Npr. riemo kvadrat. Napiemo ustrezno metodo. Vedno, ko z elvo riemo kvadrate, moramo napisati to metodo: Ampak to ni "objektno": Znanje risanja kvadratov je lastno elvi objektu elva (objekt) naj bi znala narisati kvadrat: Odzvati se metodi kvadrat: nekaZelva.kvadrat(100) Imamo dostop do knjinice : Ni problem, dopiemo metodo Popravljati dobro preizkuen razred? ... Do not fix, until you are completely desperate ... Kaj pa, e izvorne kode nimamo? Dedovanje

o "razirjanje" objektov
o Naredimo nart za razred pametnih elv: Znajo risati kvadrate

o public class PametnaZelva : Turtle


o Vsaka pametna elva "zna" vse, kar zna razred Turtle in morda e kaj o Ima ista stanja/lastnosti: Morebiti tudi dodatna

RAZRED PAMETNAZELVA
773: public class PametnaZelva : Turtle { 774: // naredimo nov razred "pametnih zelv" 775: public void Kvadrat(int velikost) { 776: // Vsaka pametna zelva ve, kako se narie 777: // kvadrat s stranico velikost 778: int i = 1; 779: while (i <= 4) { 780: base.Fd(velikost); // lahko tudi brez base 781: // metoda fd je podedovana iz razreda Turtle 782: base.Rt(90); 783: // metoda rt je podedovana iz razreda Turtle
Programiranje 1 VS Informatika

C# . NET

100

784: 785: 786: }

} }

Naredimo pametno elvo

787: public class Zelva4 { 788: public static void main(string[] args) { 789: PametnaZelva zelvak; // zelvak bo ime moje pametne elve 790: zelvak = new PametnaZelva(); // "ustvarimo" "pametno" elvo 791: 792: // naj elva zelvak narie kvadrat 793: // ker je pametna, ji ni potrebno posredovati 794: // podrobnih navodil, ampak le ukaz za risanje kvadrata 795: 796: zelvak.Kvadrat(40); 797: 798: } 799: }
Dedovanje o Izpeljava novih razredov iz obstojeih o Uvajanje dodatnih metod o Lahko tudi dodatne lastnosti (podatki) o Primer: matrike Setevanje, odtevanje, mnoenje Kvadratne matrike / class KvMatrike : Matrike Ker je razred izpeljan ni potrebno na novo pisati metod za setevanje, odtevanje, mnoenje Mone dodatne operacije Inverz, deljenje, o Hierarina zgradba razredov o Vrhnji objekt: Object Iz njega izpeljani vsi drugi razredi : Object (deluje iz razreda Object) Ima metodo ToString() Zato jo "imajo" vsi razredi o specializacija objektov Sestavi razred Zlatnik, ki deduje iz razreda Kovanec. Zlatnik ima poleg osnovnih lastnosti kovanca podano e gostoto materiala, iz katerega je izdelan, istoo zlata (podano z realnim tevilom med 0 in 1) in vrednost istega zlata na masno enoto. Razred naj pozna tudi metodo double Vrednost(), ki vrne vrednost zlatnika. o "razirjanje" objektov o Naredimo nart za razred Zlatnik Kovanec s posebnimi lastnostmi o public class Zlatnik : Kovanec o Vsaka zlatnik "je in zna" vse, kar zna kovanec in morda e kaj o Vrednost istega zlata je enaka za VSE zlatnike razredna spremenljivka (static)

Programiranje 1 VS Informatika

C# . NET

101

ZLATNIK -SKICA
800: public class Zlatnik : Kovanec { 801: 802: private static double vrednostCistegaZlata = 125.4; 803: // za vse zlatnike je to enako! 804: 805: private int polmer; 806: private int visina; 807: private double gostota; 808: private double cistost; 809: // "SET" metode 810: public bool NastaviPolmer(int r) { } 811: public bool NastaviVisino(int visina) { } 812: public void NastaviGostoto(double x) { } 813: public void NastaviCistost(double x) { } 814: public static void NastaviVrednostCistegaZlata(int v) { } 815: // vrednost lahko spreminajmo tudi, ce se ni nobenega zlatnika! 816: 817: // "GET" metode 818: public int PovejPolmer() { } 819: public int PovejVisino() { } 820: public double PovejGostoto() { } 821: public double PovejCistost() { } 822: public static double PovejVrednostCistegaZlata() { } 823: // vrednost lahko zvemo tudi, ce se ni nobenega zlatnika! 824: 825: // tostring 826: override public string ToString() { } 827: // podedovana tostring metoda nam ne ustreza! 828: 829: // "znanje" 830: public double Volumen() { } 831: public double Povrsina() { } 832: public double Vrednost() {} 833: }
S krepko, leeo pisavo smo oznaili tistio, kar smo podedovali. Tega ne piemo v razredu!!

RAZRED ZLATNIK
834: public class Zlatnik : Kovanec { 835: 836: private static double vrednostCistegaZlata = 125.4; 837: // za vse zlatnike je to enako! 838: 839: private double gostota; 840: private double cistost; 841: public static double OBI_GOSTOTA = 19.3; // obicajna gostota g/cm^3 842: public static double OBI_CISTOST = 0.81; // obicajna cistost 843: 844: /* TA del NE spada v razred, je podedovan iz razreda Kovanec 845: tukaj ga napisemo v komentar le zaradi preglednosti pri 846: uenju - pravi program ga NE BI vseboval !! 847:
Programiranje 1 VS Informatika

C# . NET

102

848: 849: 850: 851: 852: 853: 854: 855: 856: 857: 858: 859: 860: 861: 862: 863: 864: 865: 866: 867: 868: 869: 870: 871: 872: 873: 874: 875: 876: 877: 878: 879: 880: 881: 882: 883: 884: 885: 886: 887: 888: 889: 890: 891: 892: 893: 894: 895: 896: 897: 898: 899: 900: 901:

private int polmer; private int visina; public static final int OBI_POLMER = 3; // obicajni polmer public static final int OBI_VISINA = 1; // obicajna visina public static final int NAJ_POLMER = 3; // najveji moni polmer public static final int NAJ_VISINA = 1; // najveja mona visina */ // konstruktorji public Zlatnik() : base() { // Ustvarimo obiajni kovanec s klicem // konstruktorja razreda Kovanec ( : base() ) this.gostota = OBI_GOSTOTA; this.cistost = OBI_CISTOST; } public Zlatnik(int polmer, int visina, double gostota, double cistost) : base(polmer, visina) { // "drugacni" zlatnik // ce ni ustreznih dimenzij, naredimo "obicajni" kovanec, // gostota in cistost sta posebej! // konstruktor v kovancu je poskrbel // za kontrolo mer! // Poklicali smo ga s kodo : base(polmer, visina) this.gostota = SmiselnaGostota(gostota); // pravilnost podatkov! this.cistost = SmiselnaCistost(cistost); // pravilnost podatkov! } // "SET" metode /* TA del NE spada v razred, je podedovan iz razreda Kovanec tukaj ga napisemo v komentar le zaradi preglednosti pri uenju - pravi program ga NE BI vseboval !! public bool NastaviPolmer(int r) public bool NastaviVisino(int visina) */ public void NastaviGostoto(double x) { // ce uporabnik poskusi gostoto nastaviti na napano vrednost // uporabimo privzeto gostoto this.gostota = SmiselnaGostota(x); } public void NastaviCistost(double x) { // ce uporabnik poskusi cistost nastaviti na napano vrednost // uporabimo privzeto cistost this.cistost = SmiselnaCistost(cistost); // pravilnost podatkov! } public static void NastaviVrednostCistegaZlata(int v) { // vrednost lahko spreminajmo tudi, ce se ni nobenega zlatnika!
Programiranje 1 VS Informatika

C# . NET

103

902: 903: 904: 905: 906: 907: 908: 909: 910: 911: 912: 913: 914: 915: 916: 917: 918: 919: 920: 921: 922: 923: 924: 925: 926: 927: 928: 929: 930: 931: 932: 933: 934: 935: 936: 937: 938: 939: 940: 941: 942: 943: 944: 945: 946: 947: 948: 949: 950: 951: 952: 953: 954: 955:

if (v > 0) vrednostCistegaZlata = v; // vsaka pozitivna vrednost je OK } // "GET" metode /* Ta del NE spada v razred, je podedovan iz razreda Kovanec tukaj ga napisemo v komentar le zaradi preglednosti pri uenju - pravi program ga NE BI vseboval !! public int PovejPolmer() public int PovejVisino() */ public double PovejGostoto() { return this.gostota; } public double PovejCistost() { return this.cistost; } public static double PovejVrednostCistegaZlata() { return vrednostCistegaZlata; } // tostring public override string ToString() { return "Polmer: " + base.PovejPolmer() + // zakaj ne gre // this.polmer! " visina: " + base.PovejVisino() + " gostota: " + this.gostota + " cistost: " + this.cistost; } /* Ta del NE spada v razred, je podedovan iz razreda Kovanec tukaj ga napisemo v komentar le zaradi preglednosti pri uenju - pravi program ga NE BI vseboval !! // volumen in povrsina public double Volumen() public double Povrsina() */ public double Vrednost() { // vrednost je volumen * gostota * cistost * vrednost enote // metodo volumen dobimo iz Kovanca! return base.Volumen()* gostota * cistost * vrednostCistegaZlata; } // pomozne metode private static double SmiselnaGostota(double gostota) { // vrne smiselno gostoto final double DOPUSTNO_ODSTOPANJE = 0.1;
Programiranje 1 VS Informatika

C# . NET

104

956: 957: 958: 959: 960: 961: 962: 963: 964: 965: 966: 967: 968: 969: 970: 971: }

double rel_razlika = (Math.Abs(gostota - OBI_GOSTOTA) / OBI_GOSTOTA); if (rel_razlika > DOPUSTNO_ODSTOPANJE) gostota = OBI_GOSTOTA; // ce so podatki "neumni" return gostota; } private static double SmiselnaCistost(double cistost) { // vrne smiselno cistost if ((cistost <= 0) || (cistost >= 1)) // cistost naj bo med 0 // in 1, brez robnih vrednosti cistost = OBI_CISTOST; return cistost; } // ce so podatki "neumni"

RAZRED ZLATNIK -

ZARES

972: public class Zlatnik : Kovanec { 973: 974: private static double vrednostCistegaZlata = 125.4; 975: // za vse zlatnike je to enako! 976: 977: private double gostota; 978: private double cistost; 979: public static double OBI_GOSTOTA = 19.3; // obicajna gostota g/cm^3 980: public static double OBI_CISTOST = 0.81; // obicajna cistost 981: 982: // konstruktorji 983: public Zlatnik() : base() { 984: // "obicajni" zlatnik 985: this.gostota = OBI_GOSTOTA; 986: this.cistost = OBI_CISTOST; 987: } 988: 989: public Zlatnik(int polmer, int visina, double gostota, 990: double cistost) : base(polmer, visina) { 991: // "drugacni" zlatnik 992: // ce ni ustreznih dimenzij, naredimo "obicajni" kovanec, 993: // gostota in cistost sta posebej! 994: // konstruktor v kovancu je poskrbel za kontrolo mer! 995: this.gostota = SmiselnaGostota(gostota); // pravilnost podatkov! 996: this.cistost = SmiselnaCistost(cistost); // pravilnost podatkov! 997: } 998: 999: // "SET" metode 1000: public void NastaviGostoto(double x) { 1001: // ce uporabnik poskusi gostoto nastaviti na napano vrednost 1002: // uporabimo privzeto gostoto 1003: this.gostota = SmiselnaGostota(x); 1004: } 1005: 1006: public void NastaviCistost(double x) { 1007: // ce uporabnik poskusi cistost nastaviti na napano vrednost
Programiranje 1 VS Informatika

C# . NET

105

1008: 1009: 1010: 1011: 1012: 1013: 1014: 1015: 1016: 1017: 1018: 1019: 1020: 1021: 1022: 1023: 1024: 1025: 1026: 1027: 1028: 1029: 1030: 1031: 1032: 1033: 1034: 1035: 1036: 1037: 1038: 1039: 1040: 1041: 1042: 1043: 1044: 1045: 1046: 1047: 1048: 1049: 1050: 1051: 1052: 1053: 1054: 1055: 1056: 1057: 1058: 1059: }

// uporabimo privzeto cistost this.cistost = SmiselnaCistost(cistost); // pravilnost podatkov! } public static void NastaviVrednostCistegaZlata(int v) { // vrednost lahko spreminajmo tudi, ce se ni nobenega zlatnika! if (v > 0) vrednostCistegaZlata = v; // vsaka pozitivna vrednost je OK } // "GET" metode public double PovejGostoto() { return this.gostota; } public double PovejCistost() { return this.cistost; } public static double PovejVrednostCistegaZlata() { return vrednostCistegaZlata; } // tostring public override string ToString() { return "Polmer: " + base.PovejPolmer() + " visina: " + base.PovejVisino() + " gostota: " + this.gostota + " cistost: " + this.cistost; } public double Vrednost() { // vrednost je volumen * gostota * cistost * vrednost enote return this.Volumen() * gostota * cistost * vrednostCistegaZlata; // pomozne metode private static double SmiselnaGostota(double gostota) { // vrne smiselno gostoto final double DOPUSTNO_ODSTOPANJE = 0.1; // lokalna konstanta double rel_razlika = (Math.Abs(gostota - OBI_GOSTOTA) / OBI_GOSTOTA); if (rel_razlika > DOPUSTNO_ODSTOPANJE) gostota = OBI_GOSTOTA; // ce so podatki "neumni" return gostota; } private static double SmiselnaCistost(double cistost) { // vrne smiselno cistost if ((cistost <= 0) || (cistost >= 1)) // cistost naj bo med // 0 in 1, brez robnih vrednosti cistost = OBI_CISTOST; // ce so podatki "neumni" return cistost; }

Programiranje 1 VS Informatika

C# . NET

106

Iz muhe slon Ne, iz muhe ne bomo naredili slona, ampak pri nas zajci postanejo ovce. Pri nas se je oglasil bogati Rus, ki je bil tako navduen nad naim programom za vodenje farme zajcev, da hoe, da mu zanj pripravimo podoben program. Posebno nad metodo MeNapojiti() je bil navduen! A al on ne vodi farme zajcev, ampak farmo ovac. Poleg tega, da ovce redi za zakol, prodaja tudi njihove kouhe, zato bi rad, da vodimo e barvo njihovega kouha. Osnova: razred ZajecNov Kakne spremembe so potrebne? Napane lastnosti: OsnovaSerijska ni OK Prav tako MAX_TEZA Dodati lastnosti: Barva kouha Get/set metodi: denimo, da si tudi ovce barvajo kouhe Popraviti konstruktor in dodati metodo ToString: V razredu ZajecNov smo nanjo pozabili! Prekrite metode o o o o o o V predniku (neposrednem ali posrednem) definirana metoda nam ne ustreza Predefiniranje: prekrite metode Overriding Enak podpis metode kot pri predniku velja naa definicija ToString() doloilo override

"Umazane" podrobnosti o o o o o o o base() serijska ponovno! ker zaradi private ne moremo do serijska iz ZajecNov PovejSerijska() na novo enaka e v ZajecNov Razlog: nova spremenljivka serijska e ne navedemo - metoda bi vraala serijsko iz zajcev!!

Uporaba

1060: public class Ovce { 1061: public static void Main(string[] ar) { 1062: Ovca z1 = new Ovca(); 1063: System.Console.WriteLine(z1); 1064: System.Console.WriteLine(z1.PovejSerijsko()); 1065: z1.nastaviBarvo("rdea"); 1066: System.Console.WriteLine(z1); 1067: System.Console.WriteLine(z1.PovejSerijsko()); 1068: z1.spremeniTezo(12);
Programiranje 1 VS Informatika

C# . NET

107

1069: System.Console.WriteLine(z1 z1.Vrednost(12.8)); 1070: } 1071: }

"

Vredna

sem

"

Zgledi Vaje
Razred Kovanec Sestavi razred Kovanec, s katerim predstavimo kovance. Denimo, da so kovanci okrogli, z danim polmerom in viino. Poleg konstruktorjev in standardnih metod, ki nastavijo in vrnejo vrednosti lastnosti in za pretvorbo v niz, naj razred pozna e metodi, ki vrneta povrino in volumen kovanca. Razred Zlatnik Sestavi razred Zlatnik, ki deduje iz razreda Kovanec. Zlatnik ima poleg osnovnih lastnosti kovanca podano e gostoto materiala, iz katerega je izdelan, istoo zlata (podano z realnim tevilom med 0 in 1) in vrednost istega zlata na masno enoto. Napii get in set metode za nastavljanje in branje dodanih komponent. Razred naj pozna tudi metodo double Vrednost(), ki vrne vrednost zlatnika. Namig: Vrednost istega zlata je enaka za VSE zlatnike, torej je razredna spremenljivka ( static) Razred BoljsiZlatnik V deeli Fiksniji so se odloili prevzeti finanni sistem deele Spremenije, kjer je bila osnovna enota zlatnik, opisan v razredu Zlatnik. Vladar Fiksnije se je temu dolgo upiral, a na koncu le popustil. Zahteval pa je: V deeli bodo le ene vrste zlatniki in njihove lastnosti se ne smejo spreminjati. Svetovalci so ga opozarjali, da bo vsa stvar videti preve diktatorska, e ne bo na voljo vsaj navideznih monosti sprememb. Zato so mu svetovali, naj obdri vse monosti razreda Zlatnik, a le navidezno, torej tako, da bo vse ostalo nespremenjeno. Tvoja naloga je, da pripravi razred BoljsiZlatnik, ki bo tak, kot Zlatnik iz Spremenije, le da upoteva zahteve vladarja Fiksnije, ohrani vse metode razreda Zlatnik na zunaj enake, a jih predrugai tako, da ne bodo omogoale sprememb. Razred Ovca Pri tebi se je oglasil bogati Rus, ki je bil tako navduen nad tvojim programom za vodenje farme zajcev, da hoe, da mu zanj pripravi podoben program. Vendar on ne vodi farme zajcev, ampak farmo ovac. Poleg tega, da ovce redi za zakol, prodaja tudi njihove kouhe, zato bi rad, da vodimo e barvo njihovega kouha. Iz razreda Zajec izpelji razred Ovca, razredu Ovca dodaj lastnost barvaKouha in napii get in set metodo za to lastnost (recimo, da si tudi ovce barvajo kouhe ). Ustrezno popravi konstruktorje. Napii tudi metodo toString , ki bo prekrila metodo toString iz razreda Zajec in bo vrnila smiselen izpis podatkov o ovci. Zival Sestavi razred Zival, ki vsebuje spremenljivke o private int steviloNog; o private String vrsta; o private String ime; in metode za nastavljanje in spreminjanje le-teh. Vsebuje tudi konstruktor brez parametrov, ki postavi spremenljivke na smiselno zaetno vrednost.

Programiranje 1 VS Informatika

C# . NET

108

Dopolnite razred z metodo public string toString(), ki naj izpie podatke o razredu v obliki: #Ime: je vrste #vrsta in ima #steviloNog nog.

Pri tem seveda zamenjajte #vrsta in #steviloNog z vrednostmi v istoimenskih spremenljivkah. Nato napiite testni program, kjer ustvarite 5 ivali in jim nastavite smiselno vrsto in imena ter tevilo nog. Izpiite jih! Vzemi razred Kvader in iz njega izpelji razred Kocka. Dodaj mu konstruktor, ki sprejme le en parameter in pravilno nastavi irino, viino in globino (objektne spremenljivke v razredu Kvader). Seveda obstaja problem, da lahko uporabnik od zunaj preko metod NastaviSirino, NastaviGlobino in NastaviVisino spremeni nao kocko v kvader - zaenkrat to pustimo ob strani. Sestavi tudi testni program, kjer ustvari nekaj kock in izpie njihovo povrino in volumen.

775: 776: 777: 778: 779: 780: 781: 782: 783: 784: 785: 786: 787: 788: 789: 790: 791: 792: 793: 794: 795: 796: 797: 798: 799: 800: 801: 802: 803: 804: 805: 806: 807: 808: 809: 810: 811: 812: 813: 814:

public class Kvader { private int sirina, visina, globina; //ustvarimo kvader visine, sirine in globine ena public Kvader() { sirina = visina = globina = 1; } //ustvarimo kvader dane sirine, globine in visine //pri tem pazimo na to, da so podatki pravilni public Kvader(int sirina, int globina, int visina) NastaviSirino(sirina); NastaviGlobino(globina); NastaviVisino(visina); } //metoda vrne visino kvadra pub lic int VrniVisinO() { return visina; } //metoda vrne globino kvadra public int VrniGlobinO() { return globina; } //metoda vrne sirino kvadra public int VrniSirino() { return sirina; } //nastavi globino kvadra - pazi na pravilnost podatkov! public void NastaviGlobino(int globina) { if(globina >= 0) { this.globina = globina; } } //nastavi sirino kvadra - pazi na pravilnost podatkov!
Programiranje 1 VS Informatika

C# . NET

109

815: 816: 817: 818: 819: 820: 821: 822: 823: 824: 825: 826: 827: 828: 829: 830: 831: 832: 833: 834: 835: 836: 837: 838: 839:

public void NastaviSirino(int sirina) { if(sirina >= 0) { this.sirina = sirina; } } //nastavi visino kvadra - pazi na pravilnost podatkov! public void NastaviVisino(int visina) { if(visina >= 0) { this.visina = visina; } } public int Volumen() { return this.VrniSirino() * this.VrniVisino() * this.VrniGlobino(); } public int return 2 2 2 } } Povrsina() { * this.VrniSirino() * this.VrniVisino() + * this.VrniGlobino() * this.VrniVisino() + * this.VrniSirino() * this.VrniGlobino();

Razred Pes Iz razreda Zival izpelji razred Pes. Razred naj vsebuje dodatne metode: o public void NastaviPasmo(String pasma): e uporabnik "podtakne" prazen niz, naj vre napako! o public String VrniPasmo() o public void NastaviStarost(int starost): poskrbite, da bo starost vedno med 1 in 25 let. o public int VrniStarost() Seveda boste za hrambo dodatnih podatkov rabili nekaj dodatnih objektnih spremenljivk. Poskrbi tudi, da bo osnovni konstruktor razreda Pes nastavil vrsto na pes, tevilo nog na tiri ter pasmo in starost postavil na smiselno vrednost (naredite tabelo vsaj desetih pasem in izbirajte med njimi). Nato vsakemu objektu nekajkrat (nakljuno mnogokrat) spremenite pasmo in tevilo nog. Ko boste ustvarili razred, dopolnite testni program tako, da vam namesto petih ivali ustvari pet objektov tipa Pes. Denimo, da nas zanima statistika ustvarjanja objektov, in sicer: o o o koliko objektov smo tekom delovanja programa ustvarili? kolikokrat smo prebrali tevilo nog? kolikokrat smo spremenili pasmo?

Dopolni program tako, da bo na koncu delovanja te podatke izpisal. Namig: razredne spremenljivke (kljuna beseda: static). Razred Dalmatinec Iz razreda Pes izpelji razred Dalmatinec. Razred naj vsebuje dodatne metode: o o public void NastaviSteviloPik(int pike): poskrbi za to, da bo tevilo pik med 1 in 1000. public int VrniSteviloPik()

Programiranje 1 VS Informatika

C# . NET

110

public int VrniVrednost(): vrne vrednost dalmatinca glede na njegovo starost in tevilo pik. Ve ko ima pik, ve naj bo vreden, in sicer naj bo vsaka pika vredna 1000 - #steviloLet tolarjev. Poleg tega je e omejitev na zgornjo in spodnjo ceno: dalmatinec ne more stati ve manj kot 10000SIT in ne ve kot 1000000 SIT.

Dopolni testni program tako, da ustvari 100 dalmatincev z nakljunim tevilom pik. Poii med njimi najdrajega in ga izpii! e je taki dalmatincev ve, izpii vse. Naloge brez raunalnika 1. Kakna je razlika med statinimi in dinaminimi spremenljivkami oz. metodami v razredu? Katere izmed spodnjih trditev o dinaminih/statinih spremenljivkah v razredu so pravilne? Za dostop do statine spremenljivke oz. metode ne potrebujemo primerka razreda. Za dostop do dinamine spremenljivke oz. metode ne potrebujemo primerka razreda. e posebej ne poudarimo, je metoda statina. Objekt razreda lahko klie statino metodo oz. dostopa do statine spremenljivke. 2. Ali se sledea koda prevede? Kaj izpie?

840: 841: 842: 843: 844: 845: 846: 847: 848: 849: 850: 851: 852: 853: 854: 855:
3.

public class CharZ { private static char c = 'a'; public CharZ(char c) { this.c = c; } public char GetChar() { return c; } } public static void Main(string[] argc) { CharZ a, b; a = new CharZ('a'); b = new CharZ('b'); Console.WriteLine("a: " + a.GetChar() + ", " + " b: " + b.GetChar()); }

Sledea koda predstavlja razred atleta na olimpijskih igrah.

856: public public class Athlete { 857: private string name; 858: private string country; 859: private int age; 860: private static int numCanadians, numAmericans, numMexicans, numOther = 0; 861: 862: public Athlete(string name, string country, int age) { 863: this.name = name; 864: this.country = country; 865: this.age = age; 866: if(country.equals("Canada")) 867: numCanadians++; 868: else if(country.equals("USA")) 869: numAmericans++; 870: else if(country.equals("Mexico")) 871: numMexicans++;
Programiranje 1 VS Informatika

C# . NET

111

872: 873: 874: 875: 876: 877: 878: 879: 880: 881: 882: 883: 884: 885: 886: 887: 888: 889: 890: 891: }

else numOther++; } public string GetName() { return name; } public String GetCountry() { return country; } public int GetAge() { return age; } public void IncreaseAge() { age++; }

Ustvarimo dva nova objekta Athlete a1 = new Athlete("Lewis","USA",30); Athlete a2 = new Athlete("Johnson","Canada",28); Kateri izmed spodnjih stavkov niso v pravilni obliki? Zakaj? a1.GetName(); a2.age = a2.age + 1; a2.GetAge(); a2.IncreaseAge(); a1.country = "Mexico"; a2.IncreaseAge(); a2.GetAge(); Athlete a3 = new Athlete("Hamm","USA",31); a4.GetAge(); Athlete a1 = new Athlete("Gretzky","Canada",39); a1 = a3; a1.GetAge(); a1 == a2; a1 == a3; a3.IncreaseAge(); a1.GetAge(); Kaj pravilni stavki pomenijo in kaken uinek imajo? Kaj bi lo lahko narobe, e bi bila spremenljivka country v zgornji kodi javna? Napii funkcijo public void setCountry(String country), ki bo spremenila vrednost drave. Ali je dovolj popraviti le spremenljivko country, ali je potrebno paziti na e kaj drugega? Razred Pes II Razred Pes ima nekaj pomankljivosti, in sicer: o o uporabnik lahko spremeni tevilo nog uporabnik lahko spremeni vrsto ivali Programiranje 1 VS Informatika

C# . NET

112

Problema se lotimo na slede nain: o spremenite razred Zival tako, da mu dodate konstruktor, ki sprejme vrsto, tevilo nog in ime ivali in jih nastavi na smiselne vrednosti. Za nastavljanje uporabite metode NastaviXyz, saj le te preverijo tudi pravilnost podatkov! uporabniku onemogoite spreminjanje tevila nog in vrste ivali tako, da spremenite tip metode v protected. Metodo sedaj lahko uporabljamo interno v razredu in v vseh iz njega izpeljanih razredih, le uporabnik je ne more klicati "od zunaj". Popravi tudi testni program za razred Zival! denimo, da nas pri razredu Zival moti, ker moramo za vse vrste ivali podajati tevilo nog, eprav je to pravzaprav e v naprej znan podatek. Zato razred dopolnite z dvema razrednima tabelama (torej tipa static, saj bosta za vse objekte tipa Zival vedno enaki) string[] pasme in int[] steviloNog, kjer v prvo vpiemo nekaj pasem, v drugo pa na isto mesto vpiemo tevilo nog, ki pripada tej vrsti. dopolni metodo nastaviVrsto tako, da v primeru poznane vrste (takne, ki je v nai tabeli), pravilno nastavi tudi tevilo nog ivali. napii tudi konstruktor, ki sprejme le ime in pasmo ivali in pravilno nastavi tevilo nog. e mu pasma ni poznana, naj uporabnika vpraa e za tevilo nog in poklie star konstruktor, ki sprejme vse parametre. Ustrezno popravite tudi testni program, o napiite nov konstruktor v razredu Pes, ki sprejme pasmo in ime psa, tevilo nog in vrsto ivali pa nastavi na 4 oz. na "pes".

V nei prejnjih vaj smo iz razreda Kvader izpeljali razred Kocka, ki je preko konstruktorja nastavil viino, irino in globino kvadra na enake vrednosti (dolino stranice kocke). Obstajal pa je problem, da je uporabnik lahko od zunaj preko metod nastaviSirino, nastaviGlobino oz. nastaviViino nao kocko spremenil v kvader. Ker pa poznamo prekrivanje metod, znamo to storiti bolje: prekrij metode za nastavljanje globine, irine in viine v razredu Kvader tako, da bodo spreminjale edino mero za kocko. Razredu Kocka dodaj tudi dodatni metodi public void NastaviStranico(double a) in public double PreberiStranico(), ki nastavi oz. vrne dolino stranice kocke. Pri tem bodi pozoren na veljavnost podatkov! Prekrij tudi metodo public string ToString(). Razred Kocka je nastavil viino, irino in globino kocke v konstruktorju z uporabo metod NastaviSirino, NastaviGlobino in NastaviVisino baznega razreda. Spremeni kodo tako, da bo konstruktor razreda Kocka, ki kot parameter dobi dolino stranice kocke, klical konstruktor razreda Kvader in mu podal irino, viino in globino kocke, ki jo ustvarjamo (torej tri enaka tevila). Vpraanje: kako lahko sedaj iz razreda Kocka kliemo metode NastaviSirina, NastaviGlobina in NastaviVisina iz razreda Kvader? Novi razred Kocka tudi preizkusi: ustvari testni program, kjer naredi tabelo vsaj 100 kock z nakljuno dolgimi stranicami med 10 in 100 enot. Poizkusi jim nastaviti irino, viino in globino. Med njimi poii kocki z najvejo povrino in prostornino ter ju izpii. Podoben problem kot pri razredu Kocka smo imeli tudi pri razredu Pes, kjer je uporabnik lahko spreminjal vrsto ivali in tevilo njenih nog preko metod v razredu Zival. Problem smo reili tako, da smo uporabniku popolnoma onemogoili dostop do metod za spreminjanje tevila nog in vrste ivali, kar pa ni najlepa reitev. Zato spremeni razred Pes tako, da prekrije metodi za nastavljanje tevila nog in vrste ivali - naj enostavno ne naredita ni! e metode res delujejo kot je potrebno preverite s testnim programom, kjer poskusite spremeniti vrsto in tevilo nog objekta tipa Pes. Razred Dalmatinec iz prejnjih vaj dopolni z lastnostma maksimalna hitrost (celo tevilo med 10 in 50 kilometrov na uro) in poloaj (poloaj dalmatinca v ravnini - je spremenljivka tipa Tocka, ki smo jo naredili v eni prejnjih nalog). Razred mora seveda imeti tudi metode za branje oz. spreminjanje hitrosti oz. poloaja dalmatinca. Pazi na to, da preveri podatke preden jih nastavi! Ustvari tudi testni program, kjer ustvari 100 nakljunih dalmatincev, ki so razporeni na nakljunih lokacijah na ravnini (nakljuni dalmatinec pomeni, da je nakljuno star, hiter in ima nakljuno mnogo pik). Nato med njih na Programiranje 1 VS Informatika

C# . NET

113

nakljuno toko vri klobaso. e predpostavimo, da se v trenutku ko klobasa prileti med njih vsi dalmatinci naenkrat zapodijo ponjo, kateri jo bo dobil prvi? Izpii ga. Poii tudi najblija in najbolj oddaljena dalmatinca in ju izpii. Zajec iz ivali Iz razreda Zival izpelji razred Zajec. Poleg osnovnih lastnosti iz razreda Zival naj pozna e: o o o teo zajca v kilogramih (med 0 in 50 kilogramov (Garfield)) spol zajca (spremenljivka tipa bool) starost zajca (med 0 in 20 let)

Sestavi tudi metode za spreminjanje in branje teh lastnosti. Tako kot v razredu Pes prekrij metodi razreda Zival za nastavljanje tevila nog in vrste ivali, ki naj vre napako. Sestavi tudi primerne konstruktorje (vsaj dva) in prekrij metodo ToString. Sestavi testni program, kjer ustvari tabelo desetih zajcev nakjune tee, spola in starosti. Nato med njimi poii najtejega samca in samico ter ju izpii. Smiselno bi bilo, da lastnosti kot so tea, starost in spol premake v osnivni razred ival (ker so lastnosti vsake ivali). Tja premakni tudi metode za branje in spreminjanje teh lastnosti in dodaj smiselne konstruktorje. Poleg tega ne pozabi, da mora v obstojeih konstruktorjih razreda ival postaviti te lastnosti na smiselno vrednost. Ko to kona, vzemi razreda Pes in Zajec tej jima odstrani lastnosti, ki so sedaj na voljo e v razredu ival. e si stvari zastavil pravilno, bi morali sedaj vsi psi in zajci imeti spol, teo in starost. Preveri to s testnim programom! Embi d.o.o Podjetje Embi d.o.o. izdeluje embalae vseh vrst (kartonske, plastine, kovinske...) in oblik (kocka, piramida...). Sestavi jim osnovni razred za vse embalae Embalaza, e ve, da vsaka embalaa vsebuje podatke o: tipu embalae: ker izdelujejo le konno mnogo tipov embalae, se sme tip izbrati le izmed nekaj v naprej definiranih. V razredu Embalaza zato definirajte tabelo nizov, ki predstavljajo dovoljene tipe embalae. Tip embalae naj bo mono spremeniti tako, da direktno povemo tip embalae kot niz ali pa tako, da podamo indeks tipa embalae v tabeli tipov. e tak tip embalae ne obstaja, naj se vre napaka. Poznamo vsaj plastino in kartonsko embalao. obliki embalae: za obliko veljajo enaka pravila kot za tip, le da zaenkrat poznamo le oblike: kocka, tetraeder in valj. barvo embalae: barva je lahko poljuben neprazen niz. maso embalae: pozitivno tevilo. ceno izdelave: ker cene izdelave za splono embalao ne poznamo, naj bo nastavljena na 0.

Seveda mora razred vsebovati metode za nastavljanje in branje teh lastnosti ter vsaj konstruktor brez parametrov, ki ustvari embalao s smiselnimi lastnostmi. Poleg tega podjetje zanima tudi, koliko embalae so izdelali. V ta namen bo potrebno v razred dodati razredno spremenljivko, ki se povea vsaki ko se ustvari nov objekt tipa Embalaza in metodo, ki vraa njeno vrednost. Nikakor pa ne smete dodati metode za spreminjanje te vrednosti! Zakaj? Seveda je takna embalaa e povsem neuporabna (ne vemo npr. na kakni temperaturi jo lahko skladiimo...), dodatne lastnosti embalae pa so mono odvisne od materiala, iz katerega je embalaa izdelana. Denimo, da nas trenutno najbolj zanima plastina embalaa. Zato iz razreda Embalaza izpelji razred PlasticnaEmbalaza, ki vsebuje lastnosti: vrsta plastinega materiala, iz katerega je narejena ta embalaa (izbira iz nekaj vnaprej definiranih monosti) temperaturno obmoje, v katerem je embalaa primerna za skladienje. To je lastnost razreda in ne posameznega objekta! maksimalna nosilnost embalae - odvisna od vrste plastinega materiala in je enaka za vse embalae, ki so narejene iz doloene vrste plastike! Programiranje 1 VS Informatika

C# . NET

114

ali je primerna za skladienje hrane: nekatere vrste plastike niso primene za skladienje hrane. Ker pa je stvar odvisna tudi od naina izdelave, je potrebno to posebej povedati za vsak objekt posebej. cena za kg embalae: koliko stane 1kg plastine embalae. Predpostavi, da vsaka plastina embalaa stane enako za kg.

Razred naj vsebuje tudi nekaj smiselnih konstruktorjev. Vsebuje naj metodo, ki pove koliko kilogramov tovora e lahko spravimo v embalao. Je linearno odvisna od mase emblae(v embalai, ki tehta 1kg, lahko shranimo 5kg tovora), a ne veja od neke v naprej doloene vrednosti, ki je shranjena v maksimalni nosilnosti embalae, in jo dobimo na podlagi testiranja naega plastinega materiala. Ker se metodologija testiranja lahko spremeni, se lahko tudi najveja nosilnost velikokrat spremeni. Vsebuje naj tudi metodo, ki pove, koliko stane doloena plastina embalaa. Cena je odvisna od tee te embalae, ter od oblike. Izdelava v obliki tetraedra podrai izdelavo za 20%, izdelava v obliki valja pa za 35%. Razred tudi preizkusi: ustvari tabelo 100 plastinih embala z nakljunimi zaetnimi podatki. Nato med njimi poii tako, v kateri bi lahko prepeljali hrano teko 10kg, ki stane najmanj (oblika ni pomembna, pomembno pa je, da je material ustrezen - torej tak, da dovoljuje pakiranje hrane). Ali nas stane kaj manj, e namesto hrane elimo prepeljati raunalniko opremo iste tee? Kaj pa, e je pomembna tudi oblika embalae? Denimo, da letalski prevoznik sprejme le embalao v obliki kocke. Katera embalaa je najbolj ugodna v tem primeru (torej v prej ustvarjeni tabeli embala upotevaj le tiste, ki so v obliki kocke)? Ustvari tudi razred KartonEmbalaza, ki naj ima iste lastnosti kor razred PlasticnaEmbalaza. Vemo, da je ta embalaa vedno primerna za hrano, a ima nijo nosilnost kot plastina embalaa (embalaa tee 1kg zdri le okrog 2kg tovora) in nekoliko nije stroke izdelave (izdelava embalae teke 1kg nas stane 900 SIT). Razred preveri na enak nain kot razred PlasticnaEmbalaza. Sestavi testni program, ki bo ustvaril nakljuno mnogo plastinih in kartonastih embala (a vsaj 100 vsake vrste) in jih shrani v tabelo. Med njimi nato poii takno embalao, ki bo: najprimerneja za prevoz hrane tee 1 kg v obliki valja. najprimerneja za prevoz hrane tee 100 kg v obliki kocke. najprimerneja za prevoz strojenih ko mase 2 kg katerekoli oblike. najprimerneja za prevoz strojenih ko mase 20 kg v obliki tetraedra.

Opomba: z "najprimerneja" seveda mislimo najceneja. Na koncu e izpii, koliko embalae si ustvaril tekom programa. Pri tem si lahko pomaga le z lastnostmi razreda Embalaza. Vaje "pe" 1. Podana ima razreda

892: public class Vozilo { 893: public int steviloKoles; 894: private string barva; 895: private int maxHitrost; 896: 897: public Vozilo() { 898: barva = "bela"; 899: maxHitrost = 100; 900: steviloKoles = 4; 901: } 902: 903: public Vozilo(int steviloKoles, string barva) {
Programiranje 1 VS Informatika

C# . NET

115

904: this.barva = barva; 905: this.maxHitrost = 100; 906: this.steviloKoles = steviloKoles; 907: } 908: 909: private Vozilo(int steviloKoles, string barva, int maxHitrost) { 910: this.barva = barva; 911: this.maxHitrost = maxHitrost; 912: this.steviloKoles = steviloKoles; 913: } 914: 915: public Tovornjak Klonirajv0() { 916: return new Tovornjak(this.steviloKoles, this.barva, 917: this.maxHitrost); 918: } 919: 920: 921: public Tovornjak Klonirajv1() { 922: return new Tovornjak(this.steviloKoles, this.barva, 923: this.maxHitrost, nosilnost); 924: } 925: 926: public Tovornjak Klonirajv2() { 927: return new Tovornjak(this.steviloKoles, this.barva, 928: this.maxHitrost, 1000); 929: } 930: 931: public void Hitrost(int mh) { 932: this.maxHitrost = mh; 933: } 934: 935: public int JeHitrost() { 936: return this.maxHitrost; 937: } 938: public string Barva() { 939: return this.barva; 940: } 941: 942: override public string ToString() { 943: return "Avtomobil barve " + barva + " s " + 944: steviloKoles + " kolesi razvije najvecjo hitrost " 945: + maxHitrost; 946: } 947: 948: }
in

949: public class Tovornjak : Vozilo { 950: private int nosilnost; 951: 952: public Tovornjak() : base() { 953: nosilnost = 1000; 954: this.steviloKoles = 8;
Programiranje 1 VS Informatika

C# . NET

116

955: } 956: 957: public Tovornjak(string barva) : base(8, barva) { 958: } 959: 960: public Tovornjak(int maxHitrost) : this() { 961: this.maxHitrost = maxHitrost; 962: } 963: 964: public Tovornjak(int steviloKoles, string barva, int maxHitrost) : 965: base(steviloKoles, barva, maxHitrost) { 966: this.nosilnost = 10000; 967: } 968: 969: public Tovornjak(int steviloKoles, string barva, int maxHitrost, 970: int nosilnost) : base(steviloKoles, barva) { 971: this.Hitrost(maxHitrost); 972: this.nosilnost = nosilnost; 973: } 974: 975: public Vozilo Klonirajt0() { 976: return new Vozilo(this.steviloKoles, this.barva, this.maxHitrost); 977: } 978: 979: public Vozilo Klonirajt1() { 980: return new Vozilo(this.steviloKoles, this.barva()); 981: } 982: 983: public Vozilo Klonirajt2() { 984: Vozilo a = new Vozilo(this.steviloKoles, this.barva()); 985: a.Hitrost(this.JeHitrost()); 986: return a; 987: } 988: 989: public override string ToString() { 990: return "Tovornjak barve " + this.Barva() + " s " 991: + steviloKoles + " kolesi ima nosilnost " + this.nosilnost; 992: } 993: }
o o o kateri konstruktorji v razredu Tovornjak so sintaktino pravilni? Razloi katere od metdo Klonirajv0, Klonirajv1, Klonirajt0 in Klonirajt1 so nepravilne in zakaj! kaj izpie stori spodnja koda

994: public static void Main(string[] argc) { 995: Tovornjak t = new Tovornjak(8, "zelena", 70, 996: Vozilo a = t.Klonirajt2(); 997: Tovornjak tt = t.Klonirajt2().Klonirajv2(); 998: System.Console.WriteLine(t); 999: System.Console.WriteLine (a); 1000: System.out.println(tt); 1001: }
Programiranje 1 VS Informatika

500);

C# . NET

117

6.

Denimo, da smo eleli sestaviti razred Dalmatinec, ki ima lastnosti ime in tevilo pik. Koda razreda je:

1002: 1003: 1004: 1005: 1006: 1007: 1008: 1009: 1010: 1011: 1012: 1013: 1014: 1015: 1016: 1017: 1018: 1019: 1020: 1021:

public class Dalmatinec{ public string ime; private int steviloPik; public Dalmatinec() { this.ime = "Reks"; this.steviloPik = 0; } public void ImePsa(string ime) { ime = this.ime; } private void NastaviIme(string ime) { this.ime = ime; } public void NastaviSteviloPik(int steviloPik) { this.steviloPik = steviloPik; } }

V glavnem programu smo ustvarili objekt Dalmatinec z imenom d in mu elimo nastaviti tevilo pik na 100 in ime na Pika. Kateri nain je pravilen? Pri nepravilnih povej, kaj in zakaj ni pravilno.
h) d.NastaviIme("Pika"); d.NastaviSteviloPik(100); i) d.ime = "Pika"; d.steviloPik = 100; j) d.ime = "Pika"; d.NastaviSteviloPik(100); k) d.ImePsa("Pika"); d.NastaviSteviloPik(100); l) d.ImePsa("Pika"); d.steviloPik = 100; m) d.NastaviIme("Pika"); d.steviloPik = 100; n) nobeden, ker tega sploh ne moremo storiti Sedaj elimo naemo razredu Dalmatinec dodati tudi podatke o spolu psa. Ta podatek bomo hranili v spremenljivki spol. Interno (znotraj razreda) naj logina vrednost true pomeni enski, false pa moki spol. Dopolnite razred tako, da bo zadoal naslednjim trem pogojem: a) Spremenljivka spol naj ne bo dostopna izven razreda Dalmatinec

b) obstaja naj metoda kaksenSpol, ki v primeru samca vrne 'm', v primeru samice pa 'f'. c) spol se nastavi le ob ustvarjanju objekta. Morali boste torej napisati konstruktor razreda Dalmatinec, ki sprejme kot parameter znak za spol. Ta naj bo kot zgoraj 'm' za samca in 'f' za samico. Predpostavite, da bo parameter zagotovo znak 'm' ali 'f'.

1022: public class Dalmatinec { 1023: public string ime; 1024: private int steviloPik;
Programiranje 1 VS Informatika

C# . NET

118

1025: 1026: 1027: 1028: 1029: 1030: 1031: 1032: 1033: 1034: 1035: 1036: 1037: 1038: 1039: 1040: 1041: 1042: 1043: 1044: 1045: 1046: 1047: 1048: 1049: 1050: 1051: 1052: 1053: 1054: 1055: 1056:

// PO POTREBI DOPOLNI // DO SEM // konstruktorji public Dalmatinec() { this.ime = "Reks"; this.steviloPik = 0; } // PO POTREBI DOPOLNI // DO SEM public void ImePsa(string ime) { ime = this.ime; } private void NastaviIme(string ime) { this.ime = ime; } public void NastaviSteviloPik(int steviloPik) { this.steviloPik = steviloPik; } // kaken spol ima (metoda kaksenSpol) // PO POTREBI DOPOLNI // DO SEM }

Predpostavimo, da razred, ki zadoa zgornjim kriterijem, e imamo. Sestavi metodo public static int steviloSamcev(Dalmatinec[] dalmatinci), ki preteje tevilo samcev v tabeli dalmatincev. Halo Kitajc Po koncu prejnje naloge morate imeti tri razrede: Embalaza, PlasticnaEmbalaza in KartonEmbalaza. Uporabite jih za reitev sledeih problemov: o Podjetu "Halo, Kitajc!" se je nabralo kar nekaj kosov plastine in kartonske embalae (1000 kosov vsake). Upotevajte, da so embalae razlinih te, oblik, varv, tipov plastike... zato jih nakljuno generirajte. Ker so se sklenili porabiti zalogo, za vsako naroilo posebej vzamejo najprimernejo (beri najcenejo) embalao, ki je ustrezna. Pomagaj jim izbati najprimernejo embalao, e za vsako naroilo pozna teo blaga, ki ga je potrebno dostaviti in ali je blago hrana. Podatke o naroilu nakljuno generiraj - naroil naj bo vsaj 100 in ko enkrat neko embalao porabi, je ne sme ve uporabiti. Prevozniki so podjetje opozorili, da vsaka oblika embalae ni primerna za vse vrste transporta. Tako na letala sprejemajo le embalao v obliki kocke, za transport mleka hoejo le tetraedre... Zato poleg vsakega naroila izve e, kakne oblike naj bo embalaa. Poii najcenejo! Za dostavo nekega zdravila zdravnika zbornica zahteva, da je zapakirano v embalai iz plastike tipa HDPE ali PETE, ki mora biti valjaste oblike in mora imeti nosilnost vsaj 200% vijo, kot je dejanska masa zdravila. Poii najprimernejo embalao, e ti povedo maso zdravila. Programiranje 1 VS Informatika

C# . NET

119

Na koncu leta so v podjetju delali inventuro in zanimalo jih je, koliko denarja lahko dobijo s prodajo vse embalae, ki jim je ostala. Pomagaj jim in izraunaj skopno vrednost vseh vrst embalae e ve, da je v tem asu embalaa v obliki kocke izgubila 10%, emblaa v obliki valja 20% in embalaa v obliki tetraedra 30% svoje vrednosti.

Trojiko Sestavi razred Trojisko, v katerem hranimo tevila v trojikem zapisu kot nize z obveznim predznakom. Tako tevilo 13 zapiemo kot '+111', tevilo -5 pa kot '-12'. Razred naj vsebuje: konstruktor public Trojisko(), ki ustvari nov objekt, v katerem hranimo tevilo z vrednostjo 3. konstruktor public Trojisko (int vrednost), ki ustvari nov objekt, ki predstavlja tevilo vrednost. konstruktor public Trojisko (Trojisko a), ki ustvari kopijo objekta a. metodo override public String ToString(), ki vrne tevilo v trojiki obliki, a brez predznaka, e je le-ta pozitiven. metodo public int Vrednost(), ki vrne vrednost tega objekta. metodo public Trojisko objektom a in vrne rezultat. Zmnozi(Trojisko a), ki zmnoi trenutni objekt z

Pri tem si lahko pomaga z metodama : public static int ParseInt(String parse, int radix) , ki pretvori niz parse, ki vsebuje tevilo v tevilskem sistemu z bazo radix v tevilo tipa int. public static string ConvertToString(int i, int radix), ki vzame tevilo i in vrne niz, v katerem je to tevilo zapisano v bazi radix. e je tevilo negativno, na zaetek niza zapie minus, za pozitivno tevilo pa plusa pred niz ne doda! Torej klic ConvertToString (3,3) vrne niz 10, klic ConvertToString (-3,3) pa niz -10.

Redki vektorji Redek vektor je vektor, ki vsebuje veliko niel. Taken vektor namesto z obiajno tabelo predstavimo s seznamom nenielnih elementov, kjer poleg vsakega elementa hranimo e indeks tega elementa v tabeli. Seznam je naraajoe urejen po indeksih. Na osnovi sheme razreda RedekVektor podane spodaj, sestavi ustrezni razred, potreben za predstavitev redkega vektorja. Dopolni razred Naloga1 s statino metodo, ki seteje dva redka vektorja. Rezultat naj bo nov redek vektor (sumanda ostaneta nespremenjena). Primer (neformalen zapis!):
{(2,1),(5,3),(-1,6)} + {(3,1),(8,2),(1,6),(3,15)} = {(5,1),(8,2),(5,3),(3,15)}

1057: public class RedekVektor 1058: { 1059: ???????? 1060: 1061: ??? RedekVektor(int[][] vektor) 1062: { 1063: // vektor[i][0] - koeficient 1064: // vektor[i][1] - indeks 1065: // vektor je UREJEN po drugi komponenti! 1066: // morebitne nicelne elemente izpustimo! 1067: 1068: ???? 1069: } 1070: 1071: ??? int SteviloClenov()
Programiranje 1 VS Informatika

C# . NET

120

1072: 1073: 1074: 1075: 1076: 1077: 1078: 1079: 1080: 1081: 1082: 1083: 1084: 1085: 1086: 1087: 1088: 1089: 1090: 1091: 1092: 1093: 1094: 1095: 1096: 1097: 1098: 1099: 1100: 1101: 1102: 1103: 1104: 1105: 1106: 1107: 1108:

{ // stevilo clenov redkega vektorja ???? } ???? Koeficienti() { // tabela koeficientov ????? } ???? int[] Indeksi() { // tabela indeksov ???? } ??????? } public class Naloga1 { public static void Main(string[] param) { int[][] podatki1={{2,1},{5,3},{0, 5},{-1, 6}}; int[][] podatki2={{3,1}, {8,2}, {1, 6}, {3, 15}}; RedekVektor v1 = new RedekVektor(podatki1); RedekVektor v2 = new RedekVektor(podatki2); RedekVektor v3 = Vsota(v1, v2); System.Console.WriteLine("V1 = " + v1); System.Console.WriteLine("V2 = " + v2); System.Console.WriteLine("Vsota = " + v3); } // staticna metoda vsota !! ???????? }

Plavalec Podan imamo razred Oseba z objektnima metodama VrniIme() ter VrniPriimek() (ki nam vrneta niza, ki predstavljata ime oz. priimek osebe). Iz zgoraj opisanega razreda Oseba, ki poleg zgoraj omenjenih metod pozna e metode za nastavljanje imena (NastaviIme) in priimka (NastaviPriimek) ter konstruktor Oseba(), ki naredi osebo z imenom Janez in priimkom Novak, izpeljite razred Plavalec, ki poleg imena in priimka vsebuje e podatke o: starosti plavalca (celo tevilo med 10 in 80 let) ter stilu plavanja plavalca (niz).

Programiranje 1 VS Informatika

C# . NET

121

Vsebuje naj dva konstruktorja: privzetega, ki ustvari plavalca Janeza Novaka, ki je star 20 let in plava kravl konstruktor s tirimi parametri (ime, priimek, starost in stil plavanja), ki ustvari podanega plavalca. e parametri niso pravilni, naj se ustvari privzeti plavalec.

ter metode za branje in spreminjanje lastnosti (pri tem pazite na pravilnost podatkov) plavalca. Vsebuje naj tudi objektno metodo public void Zapisi (string imeDatoteke), ki podatke o plavalcu zapie v datoteko z imenom imeDatoteke. Vanjo naj se zapie vrstica Plavalec #ime #priimek plava #slog. kjer namesto #ime, #priimek ter #slog vstavite prave vrednosti. Sestavite tudi testni program, kjer ustvarite plavalca Danijel Animer, starega 20 let, ki plava prsno, ter podatke o njem zapiite v datoteko c:\plavalec.txt. Plavalec II Podan imamo razred Oseba z objektnima metodama VrniIme() ter VrniPriimek() (ki nam vrneta niza, ki predstavljata ime oz. priimek osebe). Iz zgoraj opisanega razreda Oseba, ki poleg zgoraj omenjenih metod pozna e metode za nastavljanje imena (NastaviIme) in priimka (NastaviPriimek) ter konstruktor Oseba(), ki naredi osebo z imenom Janez in priimkom Novak, izpeljite razred Plavalec, ki poleg imena in priimka vsebuje e podatke o: najljubem stilu plavanja plavalca (indeks ustreznega stila, ki ustrezna vnosu iz spodaj omenjene tabele e je npr. v tabeli stilov plavanja niz "prsno" na 2. tem mestu v tabeli, in elimo za tega plavalca povedati, da najraje plava prsno, imamo tu shranjeno 2, e je "vseeno" in je niz "vseeno" v tabeli na zaetku, pa imamo shranjeno 0) monih stilih plavanja (tabela nizov) tabela vsebuje vsaj nize "vseeno", "kravl" in "prsno". Tabela se nikoli ne spreminja!

Vsebuje naj dva konstruktorja: privzetega, ki ustvari plavalca Janeza Novaka, ki plava kravl konstruktor s tremi parametri (ime, priimek in stil plavanja), ki ustvari podanega plavalca. e parametri niso pravilni, naj se ustvari privzeti plavalec.

ter potrebni metodi za branje (vrne naj opisno ime stila iz tabele stilov in ne indeks) in spreminjanje najljubega stila posameznega plavalca (parameter je ime stila). e parameter pri tej metodi, ki oznauje stil, v tabeli stilov ne obstaja, nastavimo najljubi stil plavanja na "vseeno" (torej shranimo podatek 0). Vsebuje naj tudi objektno metodo public void Zapisi (string imeDatoteke), ki podatke o plavalcu zapie v datoteko z imenom imeDatoteke. Vanjo naj se zapie vrstica Plavalec #ime #priimek plava #slog. kjer namesto #ime, #priimek ter #slog vstavite prave vrednosti (v datoteki naj bo izkljuno ta vrstica). Sestavite tudi testni program, kjer ustvarite plavalca Danijel Animer, ki najraje plava prsno, ter podatke o njem zapiite v datoteko c:\plavalec.txt.

Razredi in objekti (osnove)

Programiranje 1 VS Informatika

C# . NET

122

Razred - class
Pojem razred (class) je temeljni pojem objektno (predmetno) orientiranega programiranja. Kreirati nov razred pomeni sistematino urediti podatke in informacije, ter manipulacije nad njimi v neko pomensko celoto. Takno urejanje podatkov in informacij je nekaj, kar je obiajen pojav tudi v vsakdanjem ivljenju in ne velja le za programiranje. Kot primer iz vsakdanjega ivljenja vzemimo pojem avto: vsi avtomobili imajo nekaj skupnih zmonosti (lahko jih usmerjamo oz. vodimo, lahko jih zaustavimo, pospeujemo, itd. ) in nekaj skupnih lastnosti oz. atributov ( imajo volanski obro, pogonski motor, kolesa itd.). Ko torej pomislimo na avto, takoj vemo, da gre za pojem oz. objekte ki si delijo prej omenjene skupne lastnosti in zmonosti. Klasificiranje oz. razvranje pojmov v neko celoto je torej temeljna spretnost, ki je lastna vsem ljudem in brez katere si teko zamiljamo, kako bi ljudje razmiljali in komunicirali med seboj. Prav zaradi tega so tudi programerji prili na idejo, da bi posamezne pojme, njihove lastnosti (atribute) in operacije nad njimi, zdruili v neko celoto, ki so jo poimenovali razred class. Prav to pa je natanko tisto, kar nam ponujajo moderno zasnovani objektno orientirani programski jeziki, kot je npr. Microsoft Visual C#. Omogoajo definicijo novih razredov, ki v sebi zdruujejo lastnosti (atribute oz. podatke) in operacije nad njimi oz obnaanje (metode). Sveta trojica predmetno usmerjenega programiranja so pojmi enkapsulacija, dedovanje in polimorfizem

Enkapsulacija
Glavni del pojma enkapsulacija predstavlja besedica kapsula: enkapsulacija pomeni postaviti nekaj v kapsulo. Za kapsulo je znailno, da ima vidno (javno) povrino in nevidno (zasebno) notranjost, v kateri se nekaj nahaja. Vsak predmet ali pojem si lahko ponazorimo s kapsulo. Povrino predstavljajo podatki in operacije, ki jih lahko od zunaj spreminjamo. Notranjost pa so zasebni deli predmeta, ki od zunaj niso dostopni. Tudi v svetu programiranja poznamo dve pomembni uporabi oz razlagi pojma enkapsulacija: Princip, kako v enoto zdruimo podatke in metode, ki operirajo nad temi podatki. Gre torej za kombinacijo metod in podatkov znotraj razreda, z drugimi besedami razvranju oz. klasifikaciji; Notranje podatke in procese navzven skrijemo gre torej za kontrolo dostopa do metod in podatkov v kapsuli, z drugimi besedami za kontrolo uporabe razreda.

Razred class je programska struktura, ki zagotavlja sintakso in semantiko za podporo teh dveh dveh temeljnih nael enkapsulacije. Kot primer kreirajmo razred krog, ki vsebuje eno metodo (za izraun ploine kroga) in eno lastnost oz. podatek (polmer kroga). Deklaracijo novega razreda zanemo z rezervirano besedico class, ki ji sledi ime razreda, nato pa e telo razreda, zapisano med dvema zavitima oklepajema. V telesu razreda so metode (npr. metoda za ploino), spremenljivke, ki jim pravimo tudi polja razreda ( npr. polmer kroga) in pa lastnosti (properties) o lastnostih bo ve zapisanega kasneje.
class krog { double Ploscina() //metoda razreda { return Math.PI * polmer * polmer; } double polmer; //polje razreda }

Tako deklariran razred krog pa nima praktine uporabe, saj nismo upotevali drugega naela enkapsulacije: dostopnost. Potem, ko smo enkapsulirali metode in polje znotraj razreda, smo pred temeljno odloitvijo, kaj naj bo javno, kaj pa zasebno. Vse kar smo zapisali med zavita oklepaja v razredu, spada v notranjost razreda, vse kar pa je pred prvim oklepajem in za zadnjim oklepajem pa je zunaj razreda. Z besedicama public, private in protected pa lahko kontroliramo, katere metode in polja bodo dostopna tudi od zunaj: Programiranje 1 VS Informatika

C# . NET

123

Metoda ali polje je miljeno kot privatno (private), kadar je dostopno le znotraj razreda. Tako polje oz. metodo deklariramo tako, da pred tipom metode oz. polja postavimo besedico private. Metoda ali polje je miljeno kot javno (public), kadar je dostopno tako znotraj, kot tudi izven razreda. Tako polje oz. metodo deklariramo tako, da pred tipom metode oz. polja postavimo besedico public.. Metoda ali polje je miljeno kot zaiteno (protected), kadar je vidno le znotraj razreda, ali pa v podedovanih (izpeljanih) razredih.

Deklaracijo naega razreda krog sedaj napiimo e enkrat. Tokrat bomo metodo Ploscina deklarirali kot javno metodo, polje polmer pa kot privatno polje. Metodo Ploscina bomo v tem primeru lahko poklicali oz. uporabili tudi izven razreda, neposrednega dostopa do polja polmer pa ne bomo imeli.
class Krog { public double Ploscina() //javna metoda razreda { return Math.PI * polmer * polmer; } private double polmer; //zasebno polje razreda }

e metode ali polja ne deklariramo kot public ali pa private, bo privzeto, da je metoda oz. polje private. Seveda pa velja, da e so vse metode in polja znotraj razreda privatne, razred nima praktine uporabe. e hoemo razred, ki smo ga definirali tudi uporabiti, moramo kreirati novo spremenljivko tega tipa, oz. kot temu pravimo v svetu objektnega programiranje, kreirati moramo novo instanco (primerek) razreda, ki ji pravimo tudi objekt. Novo spremenljivko tipa Krog lahko deklariramo tako kot vsako drugo spremenljivko. Naredimo primerjavo med kreiranjem in inicializacijo spremenljivk osnovnih (primitivnih) podatkovnih tipov in spremenljivk izpeljanih iz razredov (objektov). Osnovna sintaksa je enaka:
int i; Krog K //deklaracija spremenljike i, ki je celotevilnega tipa //deklaracija spremenljivke K ki je tipa Krog (razred)

e hoemo uporabiti vrednost katerekoli spremenljivke, moramo biti prepriani, da ta spremenljivka e ima vrednost.
int i; //deklaracija spremenljike i, celotevilnega tipa Console.WriteLine(i); //NAPAKA uporaba neinicilaizirane spremenljivke

To pravilo velja seveda za vse spremenljivke, ne glede na njihov tip.


Krog K //deklaracija spremenljivke k, ki je tipa Krog (razred) Console.WriteLine(K); //NAPAKA uporaba neinicilaizirane spremenljivke

Spremenljivke osnovnih podatkovnih tipov seveda lahko inicializiramo enostavno takole:


int i=10; //deklaracija in inicilaizacija spremenljike i, celotevilnega tipa Console.WriteLine(i); //OK!! //ali pa takole int j; j = 10; Console.WriteLine(j); //OK!!

Spremenljivkam, ki so izpeljane (ustvarjene) iz razreda pa vrednosti ne moremo prirejati tako kot spremenljivkam osnovnih (vrednostih) tipov. Uporabiti moramo rezervirano besedo new in za na razred poklicati ustrezen konstruktor. Novo spremenljivko (nov objekt oz. novo instanco) razreda Krog torej ustvarimo s pomojo rezervirane besede new takole:

Programiranje 1 VS Informatika

C# . NET

124

Krog K = new Krog();/*ustvarili smo nov objekt razreda Krog: pri tem smo uporabili privzeti konstruktor to je metodo Krog(), ki ima enako ime kot razred. */ //Ali pa takole Krog K; K = new Krog();

Primer:
class Zgradba//deklaracija razreda Zgradba z dvema javnima poljema. Razred nima nobene metode. { public int kvadratura; public int stanovalcev; } static void Main(string[] args) { Zgradba hia = new Zgradba(); //nov objekt razreda Zgradba Zgradba pisarna = new Zgradba(); //nov objekt razreda Zgradba int kvadraturaPP; // kvadratura na osebo hia.stanovalcev = 4; hia.kvadratura = 2500; pisarna.stanovalcev = 25; pisarna.kvadratura = 4200; kvadraturaPP = hia.kvadratura / hia.stanovalcev; Console.WriteLine("Hia ima:\n " + hia.stanovalcev + " stanovalcev\n " + hia.kvadratura + " skupna kvadratura\n kvadraturaPP + " kvadratura na osebo"); Console.WriteLine(); kvadraturaPP = pisarna.kvadratura / pisarna.stanovalcev; Console.WriteLine("Pisarna ima:\n " + pisarna.stanovalcev + " stanovalcev\n " + pisarna.kvadratura + " skupna kvadratura\n kvadraturaPP + " kvadratura na osebo"); }

" +

" +

Vaja:
/*Kreirajmo razred oseba s tirimi polji (ime, priimek, letnik in viina), ter dvema metodama: metodo za prirejanje podatkov posameznim poljem in metodo za izpis podatkov*/ class Oseba { //razred ima tiri zasebna polja private string ime; private string priimek; private int letnik; private int visina; //razred ima tudi dve javni metodi public void VpisiOsebo(string ime,string priimek,int letnik,int visina) { //ker imajo parametri metode enako ime kot polja razreda, smo za dostop do polj razreda //uporabili rezervirano besedo this - ta pomeni referenco na konkreten primerek razreda //(objekt), oz. referenco na polje konkretnega objekta this.ime = ime; this.priimek = priimek; this. letnik = letnik; this.visina = visina; } public void IzpisiOsebo() {

Programiranje 1 VS Informatika

C# . NET

125

Console.Write("Ime: " + ime + "\nPriimek: " + priimek + "\nStarost: " + letnik + "\nViina: " + visina+"\n"); } } //glavni program static void Main(string[] args) { Oseba nogometas = new Oseba();//nova instanca (primerek) razreda Oseba nogometas.VpisiOsebo("David", "Becham", 1980, 181); nogometas.IzpisiOsebo(); Oseba predsednik = new Oseba();//nova instanca (primerek) razreda Oseba predsednik.VpisiOsebo("George", "Bush", 1951, 173); predsednik.IzpisiOsebo(); }

Vaja:
/*Kreirajmo razred avto s tirimi zasebnimi polji (znamka, model, najvecjahitrost in teza), ter dvema javnima metodama: metodo za inicializacijo (vnos) polj tega razreda, ter javno metodo za izpis polj tega razreda. Nato kreirajmo dva objekta, ju inicializirajmo ter izpiimo njune podatke*/ class avto { //zasebna polja razreda avto private string znamka; private string model; private int najvecjahitrost; private double teza; public void Inicializacija()//javna metoda za vnos podatkov o konkretnem avtomobilu { Console.Write("\nZnamka: "); znamka = Console.ReadLine(); Console.Write("\nModel: "); model = Console.ReadLine(); Console.Write("\nNajveja hitrost: "); najvecjahitrost = Convert.ToInt32(Console.ReadLine()); Console.Write("\nTea vozila: "); teza = Convert.ToDouble(Console.ReadLine()); } public void IzpisPodatkov()//javna metoda za izpis podatkov o konkretnem avtomobilu { Console.WriteLine("\nIzpis podatkov o vozilu:\n"); Console.WriteLine("Znamka: "+znamka +"\nModel: "+model +"\nNajveja hitrost: "+najvecjahitrost +"\ntea vozila: "+teza); } } static void Main(string[] args) { avto mojavto=new avto(); //nov objekt tipa avto (nova instanca razreda) mojavto.Inicializacija(); //klic metode za inicializac.(vnos) podatkov za konkreten avto mojavto.IzpisPodatkov(); //klic metode za izpis podatkov o avtomobilu //kreiramo e drugi objekt, ga inicializiramo in izpiimo e njegove podatke avto prijateljevavto = new avto(); prijateljevavto.Inicializacija(); prijateljevavto.IzpisPodatkov(); }

Vaja:
/*Kreirajmo razred Prodajalec, ki bo imel zasebno polje zneski (tabela 12 tevil tipa double), ter javne metode za inicializacijo te tabele: metodo za doloanje prodaje za posamezen mesec, metodo za izraun celoletne prodaje in metodo za izpis celoletne prodaje*/ class Prodajalec { private double[] zneski; //zasebna tabela ki hrani mesene zneske prodaje public void inicializacija() //metoda ki inicializira tabelo prodaje {

Programiranje 1 VS Informatika

C# . NET

126

zneski = new double[12]; } public void doloci_prodajo(int mesec, double znesek) //Vnos zneska prodaje za posam. mesec { if (mesec >= 1 && mesec <= 12 && znesek > 0) zneski[mesec - 1] = znesek; //[mesec -1] zato, ker v gredo tabeli indeksi od 0 d0 11 else Console.WriteLine("Napaen mesec ali znesek prodaje"); } public void izpisi_letno_prodajo() { Console.WriteLine("Skupna letna prodaja je : " + skupna_letna_prodaja() + " EUR"); } public double skupna_letna_prodaja() // funkcija ki vrne skupno letno prodajo { double vsota = 0.0; for (int i = 0; i < 12; i++) vsota += zneski[i]; return vsota; } }; static void Main(string[] args) { Prodajalec p = new Prodajalec(); // tvorba objekta p tipa Prodajalec p.inicializacija(); //inicializacija tabele zneskov prodaje double znesek_prodaje; for (int i = 1; i <= 12; i++) { Console.Write("Vnesi znesek prodaje za mesec "+i+": "); znesek_prodaje = Convert.ToDouble(Console.ReadLine()); p.doloci_prodajo(i, znesek_prodaje); } p.izpisi_letno_prodajo(); }

Vaja:
/*Napiimo razred mojstring, v katerem bomo napisali nekaj javnih metod za delo s stringi, ki naj pomenijo alternativo obstojeim metodam npr. Length, Replace, ToUpper, ...*/ class mojstring { private string stavek; //zasebno polje razreda mojstring public void DolociStavek(string st) //metoda za inicializacijo polja stavek { stavek = st; } public int dolzina()//metoda ki vrne tevilo znakov v stringu { return stavek.Length; } //metoda za zamenjavo doloenih znakov v stringu z novimi znaki public void ZamenjajZnak(string stari, string novi) { stavek = stavek.Replace(stari, novi); } public string IzpisStavka() { return stavek; } public void VelikeCrke() { stavek = stavek.ToUpper(); } } static void Main(string[] args) { mojstring st=new mojstring(); st.DolociStavek("Razred mojstring: metodam za delo s stringi smo priredili slovenska imena!"); Console.WriteLine("\nV stavku:\n\n"+st.IzpisStavka()+"\n\nje "+st.dolzina()+" znakov!"); st.ZamenjajZnak(" ", "X");//presledke nadomestimo z znakom X

Programiranje 1 VS Informatika

C# . NET

127

Console.WriteLine(st.IzpisStavka()); st.ZamenjajZnak("X"," ");//vse znake "X" nadomestimo s presledki st.VelikeCrke(); //vse rke v stringu spremenimo v velike rke Console.WriteLine(st.IzpisStavka()); }

Naloge: Napii razred Kosarka, za spremljanje koarkake tekme. Voditi mora tevilo prekrkov za vsakega tekmovalca (10 igralcev), tevilo doseenih tok (posebej 1 toka, 2 toki in 3 toke), ter metodo za izpis statistike tekme. Doseganje koev in prekrkov realiziraj preko metode zadelProstiMet(), zadelZa2Tocki, zadelZa3Tocke in prekrsek. Sestavi razred, ki bo v svoja polja lahko shranil ulico, tevilko nepreminine ter vrsto nepreminine. Ustvari poljuben objekt, ga inicializiraj in ustvari izpis, ki naj zgleda priblino takole: Na naslovu Cankarjeva ulica 32, Kranj je blok.

Konstruktor
Konstruktor je metoda razreda, ki se uporablja za kreiranje novega primerka (instance) razreda. Njegovo ime je vedno enako kot je ime njegovega razreda. Namen konstruktorja pa je, da poskrbi za inicializacijo polj novo kreiranega objekta. e konstruktorja ne napiemo sami, ga avtomatino za nas skreira prevajalnik. Z drugimi besedami, originalni razred Krog, za katerega smo zgoraj napisali eno samo metodi in eno polje, v resnici vsebuje e eno metodo: to je nevidni konstruktor, ki poskrbi za inicializacijo polja polmer. Ta metoda je povsem enaka, kot e bi napisali celoten razred takole:
class Krog { public Krog() { polmer = 0.0; } public double Ploscina() { return Math.PI * polmer * polmer; } private double polmer; }

Konstruktor, ki ga avtomatino generira prevajalnik, je vedno public, nima nobenega tipa (niti void), nima argumentov, vrednosti numerinih polj postavi na 0, polja tipa bool postavi na false, vsem referennim poljem (spremenljivkam) pa priredi vrednost null. Ko je nov objekt inicializiran, lahko dostopamo do njegovih polj in uporabljamo njegove metode. Do javnih (public) polj (lastnosti razreda) in javnih metod dostopamo s pomojo operatorja pika, tako kot pri strukturah.
Krog K = new Krog(); Console.WriteLine(K.Ploscina()); /*Izpis bo seveda enak 0, ker je privzeti konstruktor polju polmer avtomatino dodelil vrednost 0!*/

Primer:
/*Kreiraj razred Pravokotnik z dvema poljema (dolina in viina pravokotnika) in dvema metodama (metoda za izraun ploine in metoda za izraun obsega pravokotnika. Nato ustvari nov objekt tipa Pravokotnik, doloi stranice pravokotnika in s pomojo metod razreda Pravokotnik izraunaj njegovo ploino in obseg*/ public class Pravokotnik {

Programiranje 1 VS Informatika

C# . NET

128

//deklariramo polja; polja bodo javna (public), da bomo imeli do njih dostop izven razreda public int dolzina,visina; //polji (lastnosti) razreda sta stranici pravokotnika public Pravokotnik() //konstruktor (na konstruktor je enak privzetemu konstruktorju!) { dolzina=0; visina=0; } public double ploscina() //metoda, ki izrauna in vrne ploino pravokotnika { return (dolzina*visina); } public double obseg() //metoda, ki izrauna in vrne obseg pravokotnika { return (2*dolzina+2*visina); } }; static void Main(string[] args) { Pravokotnik P = new Pravokotnik(); //na kopici ustvarimo nov objekt razreda pravokotnik P.dolzina = 10; //doloimo dolino pravokotnika P.visina = 8; //doloimo viino pravokotnika Console.WriteLine("Ploina pravokotnika: " + P.ploscina()); //klic metode za izraun //ploine Console.WriteLine("Obseg pravokotnika: " + P.obseg()); //klic metode za izraun obsega }

Vaja:
/*Kreiraj razred Kocka z enim privatnim poljem (rob kocke) in s tremi javnimi metodami (metoda za doloanje robu kocke, metoda za izpis robu kocke in metoda za izraun prostornine kocke. Nato ustvari nov objekt tipa Kocka, doloi rob kocke in s pomojo metode razreda Kocka izraunaj njegovo prostornino */ public class Kocka { private double rob; public Kocka() //konstruktor (enak je privzetemu konstruktorju) { rob = 0; } public void Nastavi_Rob(double x) //metoda, ki omogoa nastavitev roba kocke { rob = x; } public double izpis_Roba() { return rob; } public double prostornina() //metoda, ki izracuna in vrne prostornino kocke { return (rob*rob*rob); } }; static void Main(string[] args) { Kocka K = new Kocka(); //na kopici ustvarimo novo instanco oz. nov objekt razreda Kocka Random naklj=new Random(); K.Nastavi_Rob(Math.Round(naklj.NextDouble()*10,1)+1); //Rob kocke bo nakljuno realno //tevilo med 1 in 10 Console.WriteLine("Rob kocke: " + K.izpis_Roba()); Console.WriteLine("Prostornina kocke: " + K. prostornina ());//klic metode za izraun //prostornine }

Vaja:
/*Napii razred Kompleksno z dvema poljema (realna in imaginarna), ki naj predstavljata realno in imaginarno komponento nekega kompleksnega tevila. Napii konstruktor, ki komponentama priredi doloeni vrednosti. Napii e metodo, ki v primerni obliki izpie poljuben objekt tega razreda!*/

Programiranje 1 VS Informatika

C# . NET

129

class Kompleksno { private int realna, imaginarna; //zasebni polji razreda public Kompleksno (int real, int imag) // konstruktor, ki poljema priredi celot.vrednosti { realna = real; imaginarna = imag; } public void izpisi(string ime) //metoda za izpis { Console.WriteLine(ime+" = "+realna + " + " + imaginarna + " * i"); } } static void Main(string[] args) { Kompleksno alfa=new Kompleksno(1,1); //kreiranje novega objekta tipa Kompleksno alfa.izpisi("alfa"); Kompleksno beta=new Kompleksno(6,8); //kreiranje novega objekta tipa Kompleksno alfa.izpisi("beta"); }

Preobloeni (overloaded) konstruktorji


Poglejmo si e enkrat prvotno deklaracijo razreda Krog, ki ima deklarirano eno privatno polje (polmer) in javno metodo Ploscina().
class Krog { public double Ploscina() { return Math.PI * polmer * polmer; } private double polmer; }

Deklarirajmo novo spremenljivko tipa Krog, ji priredimo vrednost novega objekta Krog, nato pa pokliimo metodo Ploscina:
Krog K = new Krog(); Console.WriteLine(K.Ploscina());

Privzeti konstruktor v vsakem primeru postavi polmer na 0 (ker je polmer private, ga tudi ne moremo spremeniti), zaradi esar bo tudi ploina objekta Krog vsaki enaka 0. Reitev tega problema je v dejstvu, da je konstruktor prav tako metoda (sicer metoda posebne vrste), za metode pa velja, da so lahko preobloene (preobloene metode so metode, ki imajo enako ime, razlikujejo pa se v tevilu ali pa tipu parametrov). Z drugimi besedami, napiemo lahko svoj lasten konstruktor z vrednostjo polmera kot parametrom. Novi konstruktor ima seveda enako ime kot razred, ne vraa pa niesar. Razred Krog bo sedaj izgledal takole:
class Krog { public Krog(double inicPolmer) //na lasten konstruktor { polmer = inicPolmer; } public double Ploscina() { return Math.PI * polmer * polmer; } private double polmer; }

V primeru, da za nek razred napiemo lasten konstruktor velja, da prevajalnik ne generira privzeti konstruktor. e pa smo napisali lasten konstruktor, ki sprejme en parameter in bi kljub temu eleli poklicati Programiranje 1 VS Informatika

C# . NET

130

tudi privzeti konstruktor, ga moramo napisati sami. Pri tem pa moramo biti pozorni na dejstvo, da bodo vrednosti polj, ki jih v konstruktorju ne bomo inicializirali, e vedno ostala implicitno inicializirana na 0, false ali pa null.

Kopirni (copy) konstruktorji


Kopirni konstruktor je konstruktor, ki kreira nov objekt tako, da kopira polja nekega e obstojeega objekta istega tipa. Primer:
public class Cas { // konstruktor public Cas(DateTime dt) { Leto = dt.Year; Mesec = dt.Month; Dan = dt.Day; }

// kopirni konstruktor
public Cas(Cas obstojeciObjekt) { Leto = obstojeciObjekt.Leto; Mesec = obstojeciObjekt.Mesec; Dan = obstojeciObjekt.Dan; } // zasebna polja razreda Cas int Leto; int Mesec; int Dan; }

// kreiranje objektov
DateTime trenutniCas = DateTime.Now; Cas t = new Cas(trenutniCas); // kreiranje Cas t3 = new Cas(t);

objekta t s pomojo konstruktorja

// kreiranje objekta t3 s pomojo kopirnega konstruktorja

Statini (static) konstruktorji


Statini konstruktor je konstruktor, ki se izvede e preden je iz tega razreda izpeljan katerikoli objekt. Kdaj se bo statini konstruktor izvedel ne moremo vnaprej natanno vedeti, vemo pa, da se bo zagotovo izvedel nekje med zagonom naega programa in pred kreiranjem prve instance razreda, v katerem je ta konstruktor napisan. Pred statinim konstruktorjem nikoli ne napiemo nivoja dostopnosti (besedic private, public, ..), ampak le besedico static. Ker gre za statino metodo (tudi konstruktor je metoda) v njem ne moremo dostopati do nestatinih lanov, ampak le do statinih lanov. Primer:
public class Sporocilo { public static string Naslov = "Knjiga"; static Sporocilo() { Naslov= "C#"; } ... }

Programiranje 1 VS Informatika

C# . NET

131

Za zagon statinega konstruktorja ne potrebujemo nobenega objekta, saj lahko do njega dostopamo kar preko imena razreda, npr.:
Console.WriteLine (Sporocilo.Naslov); //Izpis: C#

Polja tipa readonly


Vasih elimo narediti javno polje, ki pa naj ga uporabnik ne bo mogel spremeniti. V takem priemru oznaimo da je polje readonly. Primer:
public class DanasnjiDatum { static DanasnjiDatum() // statini konstruktor { DateTime dt = DateTime.Now; Leto = dt.Year; Mesec = dt.Month; Dan = dt.Day; } // zasebna readonly polja razreda public static readonly int Leto; public static readonly int Mesec; public static readonly int Dan; }

Ker so polja readonly njihove vrednosti ne moremo spreminjati_


Console.WriteLine("Leto: {0}", DanasnjiDatum.Leto); //izpis trenutne letnice DanasnjiDatum.Leto = 2009; //NAPAKA: polje Leto je readonly

Destruktorji
Destruktor je metoda, ki poisti za objektom. Destruktor se torej izvede, ko objekt odmre ( npr. ko se zakljui nek blok, ali pa se zakljui neka metoda, v kateri je bil objekt ustvarjen) poklie ga torej smetar (Garbage Collector). Destruktor torej sprosti pomnilniki prostor objekta (prostor, ki ga zasedajo njegovi podatki). Destruktor ima enako kot konstruktor, enako ime kot razred sam in nima tipa. Ne sprejema argumentov, za razliko od konstruktorja pa pred destruktorjem stoji e znak '~ '. Med konstruktorjem in destruktorjem pa obstaja e ena velika razlika. Medtem ko je konstruktorjev doloenega objekta lahko ve, je destruktor vedno samo eden. Pomembno je tudi to, da destruktorji za razliko od konstruktorjev ne obstajajo v strukturah obstajajo le v razredih.
class Krog { ... //deklaracija polj public Krog() //prvi konstruktor { ... } public Krog(double inicPolmer) //drugi konstruktor { ... } ~ Krog() //destruktor { ... } }

Programiranje 1 VS Informatika

C# . NET

132

Glede destruktorjev je torej pomembno sledee : Destruktor je metoda razreda, ki ima isto ime kot razred in dodan prvi znak '~ '. Destruktor je metoda razreda, ki ni ne vraa ( pred njo ne sme stati niti void!) in ni ne sprejme. Razred ima lahko samo en destruktor. Destruktor se izvede, ko se objekt unii.

Dogovor o poimenovanju Pri poimenovanju javnih polj in metod se skuajmo drati pravila, ki ga imenujemo PascalCase (ker je bilo prvi uporabljeno v programskem jeziku Pascal). Imena javnih polj in metod naj se zaenjajo z veliko rko (v zgornjem primeru Ploscina). Pri poimenovanju zasebnih polj in metod pa se skuajmo drati pravila, ki ga imenujemo camelCase. Imena zasebnih polj in metod naj se zaenjajo z malo rko (v zgornjem primeru polmer). Pri tako dogovorjenem poimenovanju je ena sama izjema. Imena razredov naj bi se zaenjala z veliko rko. Ker pa se mora ime konstruktorja natanno ujemati z imenom razreda, se mora torej tudi ime konstruktorja v vsakem primeru zaeti z veliko rko, ne glede na to ali je javen ali zaseben.

Primer: Kot primer napiimo razred Tocka, ki naj ima dve privatni polji x in y, ter dva lastna konstruktorja. Prvi naj bo brez parametrov in v njegovem telesu le zapiimo stavek, ki bo v oknu izpisal, da je bil ta konstruktor poklican. Drugi konstruktor pa naj ima dva parametra, s katerima inicializiramo obe polji razreda. V telesu drugega konstruktorja napiimo stavek, ki izpie vrednosti obeh polj.
class Tocka { public Tocka()//Konstruktor brez parametrov { Console.WriteLine("Klican je bil privzeti konstruktor!"); } public Tocka(int x, int y) //Preobloeni konstruktor z dvema parametroma { Console.WriteLine("x:{0} , y:{1}", x, y); } private int x, y; } static void Main(string[] args) { Tocka A = new Tocka(); //Klic konstruktorja brez parametrov Tocka B = new Tocka(600, 800); //KLic konstruktorja z dvema parametroma }

Vaja:
/*Napiimo razred Tocka, ki nja ima dve zasebni polji (koordinati toke), privzeti konstruktor, ki obe koordinati postavi na 0, ter konstruktor z dvema parametroma, s katerima inicializiramo koordinati nove toke. Napiimo e metodo, ki izrauna in vrne razdaljo toke od neke druge toke*/ class Tocka { public Tocka()//lasten privzeti konstruktor { x = 0; y = 0;

Programiranje 1 VS Informatika

C# . NET

133

} public Tocka(int initX, int initY) //Preobloeni konstruktor z dvema parametroma { x = initX; y = initY; } public double RazdaljaOd(Tocka druga) //metoda za izraun razrdalje od poljubne toke { int xRazd = x - druga.x; int yRazd = y - druga.y; return Math.Sqrt(Math.Pow(xRazd,2) + Math.Pow(yRazd,2)); } private int x, y; } static void Main(string[] args) { Tocka A = new Tocka(); //Klic konstruktorja brez parametrov Tocka B = new Tocka(600, 800); //Klic konstruktorja z dvema parametroma double razdalja = A.RazdaljaOd(B); //Izraun razdalje obeh tok Console.WriteLine("Razdalja toke A od toke B je enaka " + razdalja+" enot!"); }

Vaja:
/*Napiimo razred Zaposleni z enim samim zasebnim poljem (dohodek) in dvema konstruktorjema. Prvi konstruktor naj ima kot parameter letni dodek zaposlenega, drugi pa naj imam dva paramera: tedenski dohodek in tevilo tednov. Napiimo e metodo za izpis skupnega dohodka*/ public class Zaposleni { private double dohodek; public Zaposleni(int letniDohodek) //konstruktur { dohodek = letniDohodek; } public Zaposleni(int tedenskiDohodek, int teviloTednov)//preobloeni konstruktur { dohodek = tedenskiDohodek * teviloTednov; } public double vrniDohodek() //metoda ki vrne vrednost zasebnega polja dohodek { return dohodek; } } static void Main(string[] args) { Zaposleni Janez = new Zaposleni(20000); //nov objekt, izvede se prvi konstruktor Zaposleni Tina = new Zaposleni(550, 54); //nov objekt, izvede se drugi (preobloeni) //konstruktor Console.WriteLine("Janez ima letni dohodek : " + Janez.vrniDohodek()+" EUR" ); Console.WriteLine("Tina ima letni dohodek : " + Tina.vrniDohodek()+ " EUR"); }

Naloge: Sestavi razred denarnica, ki bo omogoal naslednje operacije: dvig, vlogo in ugotavljanje stanja. Zaetna vrednost se naj postavi s konstruktorjem. Ustvari tabelo desetih denarnic z nakljuno mnogo denarja in jih izpii. Potrebujemo razred, ki bo hranil podatke o objektih tipa Instrukcije z naslednjimi komponentami: vrsta intrukcije, tevilo opravljenih ur in ali je intrukcija mona. Razred naj ima tudi metode in sicer: intrukcija se opravlja, intrukcija se ne opravlja. Z osnovnim konstruktorjem doloi vrednost (poljubno) vsem komponentam razreda. Z dodatnim konstruktorjem poskrbi za monost nastavitve Programiranje 1 VS Informatika

C# . NET

134

zaetne vrednosti za vrsto intrukcije, opravljene ure ter ali je intrukcija mona. Na osnovi razreda Instrukcije napii e testni program, ki bo kreiral in izpisal dva objekta razreda Instrukcije in sicer tako, da bodo zaetne vrednosti pri prvem objektu nastavljene z osnovnim konstruktorjem, pri drugem objektu pa z dodatnim konstruktorjem. Sestavi razred, ki predstavlja osnovo za izdelavo programa, s pomojo katerega bomo pregledovali rezultate nekega portnega tekmovanja. Sestavi razred Tekmovalec, ki ima naslednje komponente: startno tevilko, ime, priimek in klub. Vsa polja so tipa string. Napii vsaj dva konstruktorja in pripravi ustrezne get/set metode za vse te podatke. Z metodo public string tostring() naj se izpiejo podatki o tekmovalcih (startna tevilka, ime, priimek, klub). Sestavi razred Pacient, ki ima tri komponente: ime, priimek, krvna_skupina. Komponenti ime in priimek naj bosta public, krvna_skupina private, vse tri pa tipa string. Napii vsaj dva konstruktorja: prazen konstruktor, ki vse tri komponente nastavi na "NI PODATKOV", konstruktor, ki sprejme vse tri podatke in ustrezno nastavi komponente. Z metodo public string tostring() naj se izpiejo podatki o pacientu (ime, priimek, krvna skupina).

Lastnost (Property)
Polja so znotraj razreda obiajno deklarirana kot zasebna (private). Vrednosti jim priredimo tako, da zapiemo ustrezen konstruktor (konstruktorje), ali pa da napiemo posebno javno metodo (metode) za prirejanje vrednosti polj. Ostaja pa e tretji nain, ki je najbolj razirjen za vsako polje lahko definiramo ustrezno lastnost (property), s pomojo katere dostopamo do posameznega polja, ali pa z njeno pomojo prirejamo (nastavljamo) vrednosti polja. Lastnosti (properties) v razredih torej uporabljamo za inicializacijo oziroma dostop do polj razreda (objektov). Lastnost (property) je nekaken krianec med spremenljivko in metodo. Pomen lastnosti je v tem, da ko jo beremo, ali pa vanjo piemo, se izvede koda, ki jo zapiemo pri tej lastnosti. Branje in izpis (dostop) vrednosti je znotraj lastnosti realizirana s pomojo rezerviranih besed get in set imenujemo ju pristopnika (accessors). Accessor get mora vrniti vrednost, ki mora biti istega tipa kot lastnost (seveda pa mora biti lastnost istega tipa kot polje, kateremu je naemnjena), v accessor-ju set pa s pomojo implicitnega parametra value lastnosti priredimo (nastavimo) vrednost. Navzven pa so lastnosti vidne kot spremenljivke, zato lastnosti v izrazih in prirejanjih uporabljamo kot obiajne spremenljivke. Primer:
class LastnostDemo { int polje; public LastnostDemo() { polje = 0; }

//zasebno polje //konstruktor

public int MojaLastnost //deklaracija lastnosti (property) razreda LastnostDemo { get //metoda get za pridobivaje vrednosti lastnosti polje { return polje ; } set //metoda set za prirejanje (nastavljanje) vrednosti lastnosti polje { polje = value; } } }

Programiranje 1 VS Informatika

C# . NET

135

static void Main(string[] args) { LastnostDemo ob = new LastnostDemo();//nov objekt razreda LastnostDemo Console.WriteLine("Originalna vrednost ob.MojaLastnost: " + ob.MojaLastnost); ob.MojaLastnost = 100; Console.WriteLine("Vrednost ob.MojaLastnost: " + ob.MojaLastnost); Console.WriteLine("Prirejanje nove vrednosti -10 za ob.MojaLastnost"); ob.MojaLastnost = -10; Console.WriteLine("Vrednost ob.MojaLastnost: " + ob.MojaLastnost); }

Vaja:
/*Deklarirajmo razred Oseba z dvema poljema (_ime in _priimek) ter javno metodo za nastavljanje vrednosti obeh polj. Razred naj ima tudi lastnost PolnoIme, za prirejanje in vraanje polnega imena osebe (imena in priimka). Ustvarimo nov objekt in demonstrirajmo uporabo lastnosti PolnoIme*/ class Oseba { private string _priimek; //zasebno polje razreda Oseba private string _ime; //zasebno polje razreda Oseba public void NastaviIme(string ime, string priimek) //javna metoda razreda { _priimek = priimek; _ime = ime; } public string PolnoIme //javna lastnost razreda { get { return _ime + " " + _priimek; } set { string zacasna = value; string[] imena = zacasna.Split(' '); //Celotno ime razdelimo na posamezne besede //in jih spravimo tabelo _ime = imena[0]; //za ime vzamemo prvi string v tabeli _priimek = imena[imena.Length - 1]; //za priimek vzamemo drugi string v tabeli } } } static void Main(string[] args) { Oseba politik = new Oseba(); politik.NastaviIme("Nelson", "Mandela"); Console.WriteLine("Polno ime osebe je " + politik.PolnoIme); politik.PolnoIme = "George Walker Bush"; Console.WriteLine("Polno ime osebe je " + politik.PolnoIme); politik.PolnoIme = "France Preeren"; Console.WriteLine("Polno ime osebe je " + politik.PolnoIme); }

//Izpis: Polno ime osebe je // Neslon Mandela //Izpis: Polno ime osebe je // George Bush //Izpis: Polno ime osebe je // France Preeren

Za posamezno polje lahko napiemo le eno lastnost, v kateri s pomojo stavkov get ali set dostopamo oz. nastavljamo vrednosti posameznega polja. Besedici get ali set lahko izpustimo in dobimo write-only ali read-only lastnosti. Primer:
class MojRazred { double A = 3;

//zasebno polje

Programiranje 1 VS Informatika

C# . NET

136

double B = 4;

//zasebno polje

public double MojaVrednost //MojaVrednost je ReadOnly: vsebuje le get, ne pa tudi set { get { return A * B; } //lastnost vrne vrednost produkta obeh polj } } static void Main(string[] args) { MojRazred c = new MojRazred(); //nov objekt tipa MojRazred Console.WriteLine("MojaVrednost: "+c.MojaVrednost); //prikaz vrednosti lastnosti //MojaVrednost }

Naloge: Sestavi razred Piramida, ki predstavlja pokonno piramido, ki ima za osnovno ploskev kvadrat. V razredu hrani podatke o dolini stranice osnovne ploskve in viino piramide. Obe komponenti naj imata tip dostopa private. Viina in stranica nista nujno celi tevili. Napii vsaj dva konstruktorja: prazen konstruktor, ki ustvari piramido viine 1 in s stranico osnovne ploskve doline 1 konstruktor, ki sprejme podatka o viini in dolini stranice osnovne ploskve Napii program, ki ustvari tabelo 50 nakljunih piramid in med njimi poie piramido z najvejo viino. Napii get in set metode. V set metodah pazi na smiselnost podatkov (viina in dolina stranice ne smeta biti negativni,...). Napii tudi metodo tostring, ki vrne niz s smiselnim izpisom podatkov o piramidi. Sestavi razred, kjer bo v objektih te vrste hranil ime drave, njeno glavno mesto, povrino (v km ) in tevilo prebivalcev. Pripravi ustrezne get/set metode za vse te podatke in vsaj dva konstruktorja. Ne pozabi tudi na smiselno metodo tostring. Sestavi razred Igraa, ki ima tri privatne spremenljivke: tip igrae(tip string), tevilo igra na zalogi(tip int) ter ceno igrae(tip double). sestavi prazen konstruktor; sestavi konstruktor s tremi parametri; napii ustrezne set in get metode (pazi na smiselne vrednosti spremenljivk); napii metodo tostring, ki naj smiselno izpie, kateri tip igrae, koliko kosov je na zalogi in kakna je cena; dodaj e metodo zalogaIgrac, ki sprejme pozitivno celo tevilo, e se je tevilo igra povealo (dobava novih) ter negativno celo tevilo e se je tevilo igra zmanjalo (prodane igrae). Temu primerno spremeni tevilo igra na zalogi in pri tem pazi, da tevilo igra ne pade pod ni; napii metodo znizanaCena, ki sprejme celo tevilo med 0 in 100 (%), to je za koliko procentov se bo zniala cena igrae, in nastavi novo ceno igrae; napii glavni program, ki bo ustvaril pet tipov igra, tri izmed njih znial za 10, 20 in 50% ter dvema spremenil zalogo. V kemijskem laboratoriju vekrat preverjamo kislost snovi in jo definiramo s pH vrednostjo. Napii razred Snov, ki bo imel tri komponente: imeSnovi, ion in kislost. Prvi dve sta tipa string, tretja pa int. Ker je kislost zelo pomemben podatek o snovi, zagotovi, da bo zagotovo pravilen. Zato bo ustrezna spremenljivka imela privaten dostop. Sestavi tudi ustrezni get in set metodi. Pazi, da bo tudi v konstruktorju s parametri poskrbel, da ne bo prilo do napane nastavitve. e bo uporabnik podal napano kislost, ustvari objekt, kjer za prva dva podatka napie, da sta neobstojea, kislino pa pusti tako, kot jo je vnesel uporabnik. Sestavi tudi konstruktor brez parametrov, ki naredi objekt, ki predstavlja vodo. Kreiraj tabelo snovi in napii stavke za izpis vseh objektov.
2

Programiranje 1 VS Informatika

C# . NET

137

Statine metode
Za laje razumevanje pojma statina metoda, si oglejmo metodo Sqrt razreda Math. e pomislimo na to, kako smo jo v vseh dosedanjih primerih uporabili (poklicali), potem je v teh klicih nekaj udnega. Metodo Sqrt smo namre vselej poklicali tako, da smo pred njo navedli ime razreda (Math.Sqrt) in ne tako, da bi najprej naredili nov objekt tipa Math, pa potem nad njim poklicali metodo Sqrt. Kako je to mono? Pogosto se bomo sreali s primeri, ko metode ne bodo pripadale objektom (instancam) nekega razreda. To so uporabne metode, ki so tako pomembne, da so neodvisne od kateregakoli objekta. Metoda Sqrt je tipien primer take metode. e bila metoda Sqrt obiajna metoda objekta izpeljanega iz nekega razreda, potem bi za njeno uporabo morali najprej kreirati nov objekt tipa Math, npr takole:
Math m = new Math(); double d = m.Sqrt(42.24);

Tak nain uporabe metode pa bi bil neroden. Vrednost, ki jo v tem primeru elimo izraunati in uporabiti, je namre neodvisna od objekta. Podobno je pri ostalih metodah tega razreda (npr. Sin, Cos, Tan, Log, ). Razred Math prav tako vsebuje polje PI (iracionalno tevilo Pi), za katerega uporabo bi potemtakem prav tako potrebovali nov objekt. Reitev je v t.i. statinih poljih oz.metodah. V C# morajo biti vse metode deklarirane znotraj razreda. Kadar pa je metoda ali pa polje deklarirano kot statino (static), lahko tako metodo ali pa polje uporabimo tako, da pred imenom polja oz. metode navedemo ime razreda. Metoda Sqrt (in seveda tudi druge metode razreda Math) je tako znotraj razreda Math deklarirana kot statina, takole:
class Math { public static double Sqrt(double d) { . . . } }

Zapomnimo pa si, da statino metodo ne kliemo tako kot objekt. Kadar definiramo statino metodo, le-ta nima dostopa do kateregakoli polja definiranega za ta razred. Uporablja lahko le polja, ki so oznaena kot static (statina polja). Poleg tega, lahko statina metoda klie le tiste metode razreda, ki so prav tako oznaene kot statine metode. Ne-statine metode lahko, kot vemo e od prej, uporabimo le tako, da najprej kreiramo nov objekt. Primer: Napiimo razred toka in v njem statino metodo, katere naloga je le ta, da vrne string, v katerem so zapisane osnovni podatki o tem razredu
class Tocka { public static string Navodila()//Statina metoda { string stavek="Vsaka toka ima dve koordinati/polji: x je abscisa, y je ordinata!"; return stavek; } } //Zato, da pokliemo statino metodo oz. statino polje NE //Primer klica npr. v glavnem programu Console.WriteLine(Tocka.Navodila());//Klic statine metode

POTREBUJEMO OBJEKTA!!!

Statina polja
Tako kot obstajajo statine metode, obstajajo tudi statina polja. Vasih je npr. je potrebno, da imajo vsi objekti doloenega razreda dostop do istega polja. To lahko doseemo le tako, da tako polje deklariramo kot statino. Programiranje 1 VS Informatika

C# . NET

138

class Test { public const double Konstanta = 20;//Statino polje } //Zato, da pokliemo statino metodo oz. statino polje NE POTREBUJEMO OBJEKTA!!! Console.WriteLine(Test.Konstanta);//klic statinega polja

Vaja:
class Nekaj { static int stevilo=0; public Nekaj() { stevilo++; }

//Statino polje // Konstruktor //tevilo objektov se je povealo

public void Hello() { if (stevilo>3) { Console.WriteLine("Sedaj smo pa e ve kot trije! Skupaj nas je e "+stevilo); } switch (stevilo) { case 1 : Console.WriteLine("V tej vrstici sem sam !!"); break; case 2 : Console.WriteLine("Aha, e nekdo je tukaj, v tej vrstici sva dva!!"); break; case 3 : Console.WriteLine("Opala, v tej vrstici smo e trije."); break; } } } static void Main(string[] args) { Nekaj a=new Nekaj(); //konstruktor a.Hello(); { Nekaj b=new Nekaj(); //konstruktor b.Hello(); { Nekaj c=new Nekaj(); //konstruktor c.Hello(); { Nekaj d=new Nekaj(); //konstruktor d.Hello(); } } } } //Konec programa-> Garbage Collector poskrbi za

za a za b za c za d

unienje vseh objektov

Polje razreda je lahko statino a se njegova vrednost ne more spremeniti: pri deklaraciji takega statinega polja zapiemo besedico const (const = Constant konstanta). Besedica static pri deklaraciji konstantnega polja NI potrebna, pa je polje e vedno statino. Konstantno polje je torej avtomatino statino in je tako dostopno preko imena razreda in ne preko imena objekta! Vrednost statinega polja se NE da spremeniti. Tako je npr. deklarirana konstanta PI razreda Math. Primer:
class Test { public static double kons1 = 3.14; //Statino polje public const double kons = 3.1416; //Konstantno polje je avtomatino tudi statino . . .

Programiranje 1 VS Informatika

C# . NET

139

} //Zato, da pokliemo statino polje NE POTREBUJEMO OBJEKTA!!! Console.WriteLine(Test.kons1);//klic statinega polja Console.WriteLine(Test.kons);//klic konstantnega statinega polja Test.kons1= Test.kons1 + 1; //OK -> Statino polje LAHKO spremenimo Test.kons= Test.kons + 1; //NAPAKA -> Konstantnega polja ne moremo spremeniti

Dedovanje (Inheritance) izpeljani razredi


Kaj je to dedovanje
Dedovanje (Inheritance) je kljuni koncept objektno orientiranega programiranja. Smisel in pomen dedovanja je v tem, da iz e zgrajenih razredov skuamo zgraditi bolj kompleksne, ki bodo znali narediti nekaj uporabnega. Dedovanje je torej orodje, s katerim se izognemo ponavljanju pri definiranju razlinih razredov, ki pa imajo ve ali manj znailnosti skupnih. Opredeljuje torej odnos med posameznimi razredi. Vzemimo pojem sesalec iz biologije. Kot primer za sesalce vzemimo npr. konje in kite. Tako konji kot kiti ponejo vse kar ponejo sesalci nasploh (dihajo zrak, skotijo ive mladie, ), a prav tako pa imajo nekatere svoje znailnosti (konji imajo npr. tiri noge, ki jih kiti nimajo, imajo kopita, , obratno pa imajo npr. kiti plavuti, ki pa jih konji nimajo, ..). V Microsoft C# bi lahko za ta primer modelirali dva razreda: prvega bi poimenovali Sesalec, in drugega Konj, in obenem deklarirali, da je Konj podeduje (inherits) Sesalca. Na ta nain bi med sesalci in konjem vzpostavili povezavo v tem smislu, da so vsi konji sesalci (obratno pa seveda ne velja!). Podobno lahko deklariramo razred z imenom Kit, ki je prav tako podedovan iz razreda Sesalec. Lastnosti, kot so npr, kopita ali pa plavuti pa lahko dodatno postavimo v razred Konj oz. razred Kit.

Bazini razredi in izpeljani razredi


Sintaksa, ki jo uporabimo za deklaracijo, s katero elimo povedati, da razred podeduje nek drug razred, je takale:
class IzpeljaniRazred : BaziniRazred { . . . }

Izpeljani razred deduje od bazinega razreda. Za razliko od C++, lahko razred v C# deduje najve en razred in ni mono dedovanje dveh ali ve razredov. Seveda pa je lahko razred, ki podeduje nek bazini razred, zopet podedovan v e bolj kompleksen razred. Primer: Radi bi napisali razred, s katerim bi lahko predstavili toko v dvodimenzionalnem koordinatnem sistemu. Razred poimenujmo Tocka:
class Tocka //bazini razred { public Tocka(int x, int y) { //telo konstruktorja } //telo razreda Tocka }

//konstruktor

Sedaj lahko definiramo razred za tridimenzionalno toko z imenom Tocka3D, s katerim bomo lahko delali objekte, ki bodo predstavljali toke v tridimenzionalnem koordinatnem sistemu in po potrebi dodamo e dodatne metode:
class Tocka3D : Tocka //razred Tocka3D podeduje razred Tocka { //telo razreda Tocka3D tukaj zapiemo e dodatne metode tega razreda!

Programiranje 1 VS Informatika

C# . NET

140

Klic konstruktorja bazinega razreda


Vsi razredi imajo vsaj en konstruktor (e ga ne napiemo sami, nam prevajalnik zgenerira privzeti konstruktor). Izpeljani razred avtomatino vsebuje vsa polja bazinega razreda, a ta polja je potrebno ob kreiranju novega objekta inicializirati. Zaradi tega mora konstruktor v izpeljanem razredu poklicati konstruktor svojega bazinega razreda. V ta namen se uporablja rezervirana besedica base:
class Tocka3D : Tocka ////razred Tocka3D podeduje razred Tocka { public Toca3D(int z) :base(x,y) //klic bazinega konstruktorja Tocka(x,y) { //telo konstruktorja Tocka3D } //telo razreda Tocka3D }

e bazinega konstruktorja v izpeljanem razredu ne kliemo eksplicitno (e vrstice :base(x,y) ne napiemo!), bo prevajalnik avtomatino zgeneriral privzeti konstruktor. Ker pa vsi razredi nimajo privzetega konstruktorja (v veliko primerih napiemo lastni konstruktor), moramo v konstruktorju znotraj izpeljanega razreda obvezno najprej klicati bazini konstruktor (rezervirana besedica base). e klic izpustimo (ali ga pozabimo napisati) bo rezultat prevajanja compile-time error:
class Tocka3D : Tocka //razred Tocka3D podeduje razred Tocka { public Tocka3D(int z) //NAPAKA - POZABILI smo klicati bazini konstruktor razreda Tocka { //telo konstruktorja Tocka3D } //telo razreda Tocka3D }

Doloanje oz. prirejanje razredov


Poglejmo e, kako lahko kreiramo objekte iz izpeljanih razredov. Kot primer vzemimo zgornji razred Tocka in iz njega izpeljani razred Tocka3D.
class Tocka //bazini razred { //telo razreda Tocka } class Tocka3D: Tocka //razred Tocka3D podeduje razred Tocka { //telo razreda Tocka3D }

Iz razreda Tocka izpeljimo e dodatni razred Daljica


class Daljica:Tocka //razred Daljica podeduje razred Tocka { //telo razreda Daljica }

Kreirajmo sedaj nekaj objektov:


Tocka A = new Tocka(); Tocka3D B = A; //NAPAKA

- razlini tipi

Tocka3D C = new Tocka3D (); Tocka D = C; //OK!

Programiranje 1 VS Informatika

C# . NET

141

Nove metode
Razredi lahko vsebujejo ve ali manj metod in slej ko prej se lahko zgodi, da se pri dedovanju v izpeljanih razredih ime metode ponovi v izpeljanem razredu torej napiemo metodo, katere ime, tevilo in tipi parametrov se ujemajo z metodo bazinega razreda. Pri prevajanju bomo zato o tem dobili ustrezno opozorilo - warning. Metoda v izpeljanem razredu namre v tem primeru prekrije metodo bazinega razreda. e npr. napiemo razred Tocka in nato iz njega izpeljemo razred Tocka3D,
class Tocka //bazni razred { private int x, y; //polji razreda Tocka public void Izpis() //metoda za izpis koordinat razreda Tocka { Console.WriteLine("Koordinate toke:\nx = " + x + "\ny = " + y); } } class Tocka3D : Tocka { private int z; //razred Tocka3D je izpeljan iz razreda Tocka //dodatno polje razreda Tocka3D

//Metoda Izpis prepie istoimensko metodo razreda Tocka public void Izpis() { Console.Write("z = " + z + "\n"); } }

nam bo prevajalnik zgeneriral opozorilo, s katerim nas obvesti, da metoda Tocka3D.Izpis prekrije metodo Tocka.Izpis:

Program se bo sicer prevedel in tudi zagnal, a opozorilo moramo vzeti resno. e namre napiemo razred, ki bo podedoval razred Tocka3D, bo uporabnik morda priakoval, da se bo pri klicu metode Izpis pognala metoda bazinega razreda, a v naem primeru se bo zagnala metoda razreda Tocka3D. Problem seveda lahko reimo tako, da metodo Izpis v izpeljanem razredu preimenujemo (npr. Izpis1), e bolja reitev pa je ta, da v izpeljanem razredu eksplicitno povemo, da gre za NOVO metodo to storimo z uporabo operatorja new.
class Tocka //bazni razred { private int x, y; //polji razreda Tocka public void Izpis() //metoda za izpis koordinat razreda Tocka { Console.WriteLine("Koordinate toke:\nx = " + x + "\ny = " + y); } } class Tocka3D : Tocka { private int z; //razred Tocka3D je izpeljan iz razreda Tocka //dodatno polje razreda Tocka3D

//Z operatorjem new napovemo, da ima razred Tocka3D SVOJO LASTNO

metodo Izpis

new public void Izpis()


{ Console.Write("z = " + z + "\n"); } }

Vaja:

Programiranje 1 VS Informatika

C# . NET

142

/*Napii razred krog z zasebnim poljem polmer in lastnostmi Premer, Obseg in Kvadratura. Iz razreda nato izpelji razred Krogla, dodaj razredu lastno metodo Kvadratura in novo metodo Volumen*/ class Krog //Bazini razred { private double polmer;//zasebno polje razreda Krog public double Polmer //lastnost za dostop do polja polmer { get { if (polmer < 0) return 0.00; else return polmer; } set { polmer = value;} } public double Premer //lastnost, ki vrne premer kroga { get { return Polmer * 2; } } public double Obseg //lastnost, ki vrne obseg kroga { get { return Premer * Math.PI; } } public double Kvadratura //lastnost, ki vrne ploino kroga { get { return Math.PI*Math.Pow(Polmer,2); } } } /*Kreirajmo razred Krogla ki naj podeduje razred Krog. Razred Krogla bo podedoval polje polmer, podedoval bo lastnosti Premer in Obseg, imel bo SVOJO lastnost za izraun kvadrature, poleg tega pa e novo lastnost za izraun prostornine krogle */ class Krogla : Krog { new public double Kvadratura //z operatorjem new smo oznaili, da ima razred krog SVOJO //lastno lastnost kvadratuta { get { return 4 * Math.PI*Math.Pow(Polmer,2); } } public double Volumen //nova lastnost razreda Krogla { get { return 4 * Math.PI * Math.Pow(Polmer,2) / 3; } } } //glavni program static void Main() { Krog c = new Krog();//nov objekt razreda Krog c.Polmer = 25.55; Console.WriteLine("Karakteristike kroga"); Console.WriteLine("Polmer : {0}", c.Polmer); Console.WriteLine("Premer : {0}", c.Premer); Console.WriteLine("Obseg : {0,-10:F2}", c.Obseg); Console.WriteLine("Ploina: {0,-10:F2}", c.Kvadratura); Krogla s = new Krogla();//nov objekt razreda Krogla s.Polmer = 25.55; Console.WriteLine("\nKarakteristike krogle"); Console.WriteLine("Polmer : {0}", s.Polmer); Console.WriteLine("Premer : {0}", s.Premer); Console.WriteLine("Obseg : {0,-10:F2}", s.Obseg); Console.WriteLine("Povrina : {0,-10:F2}", s.Kvadratura); Console.WriteLine("Prostornina: {0,-10:F2}\n", s.Volumen); }

Programiranje 1 VS Informatika

C# . NET

143

Virtualne metode
Pogosto elimo metodo, ki smo je napisali v bazinem razredu, v vijih (izpeljanih) razredih skriti in napisati novo metodo, ki pa bo imela enako ime in enake parametre. Eden izmed nainov je uporaba operatorja new za tako metodo, drug nain pa je z uporabo rezervirane besede virtual. Metodo, za katero elimo e v bazinem razredu oznaiti, da jo bomo lahko v nadrejenih razredih nadomestili z novo metodo (jo prekriti), oznaimo kot virtualno (virtual), npr.:
//virtualna metoda v bazinem razredu v izpeljanih razredih bo lahko prekrita(override) public virtual void Koordinate() {...}

V nadrejenem razredu moramo v takem primeru pri metodi z enakim imenom uporabiti rezervirano besedico override, s katero povemo, da bo ta metoda prekrila/prepisala bazino metodo z enakim imenom in enakimi parametri.
//izpeljani razred besedica override pomeni, da smo s to metodo prekrili bazino metodo public override void Koordinate() { ...}

Loiti pa moramo razliko med tem, ali neka metoda prepie bazino metodo (override) ali pa jo skrije. Prepisovanje metode (overriding) je mehanizem, kako izvesti drugo, novo implementacijo iste metode virtualne in override metode so si v tem primeru sorodne, saj se priakuje, da bodo opravljale enako nalogo, a nad razlinimi objekti (izpeljanimi iz bazinih razredov, ali pa iz podedovanih razredov). Skrivanje metode (hiding) pa pomeni, da elimo neko metodo nadomestiti z drugo metode v tem primeru niso povezane in lahko opravljajo povsem razline naloge.

Primer: Naslednji primer prikazuje zapis virtualne metode Koordinate() v bazinem razredu in override metode Koordinate() v izpeljanem razredu.
class Tocka //bazini razred { private int x, y; //polji razreda Tocka //metoda Koordinate je virtualna, kar pomeni, da jo lahko prepiemo (override) public virtual void Koordinate() //metoda za izpis koordinat razreda Tocka { Console.WriteLine( "Koordinate toke:\nx = "+x + "\ny = " + y); } } class Tocka3D : Tocka { private int z; //razred Tocka3D je izpeljan iz razreda Tocka //dodatno polje razreda Tocka3D

//Metoda Koordinate je oznaena kot override - prepie istoimensko metodo razreda Tocka public override void Koordinate() { base.Koordinate(); //klic bazine metode Koordinate razreda Tocka Console.Write("z = "+z+"\n"); } }

Prekrivne (Override) metode


Kadar je bazinem razredu neka metoda oznaena kot virtualna (virtual), jo torej lahko v nadrejenih razredih prekrijemo/povozimo (override). Pri deklaraciji takih metod (pravimo jim polimorfne metode) z uporabo rezerviranih besed virtual in override, pa se moramo drati nekaterih pomembnih pravil: Metoda tipa virtual oz. override NE more biti zasebna (ne mre biti private); Obe metodi, tako virtualna kot override morata biti identini: imeti morata enako ime, enako tevilo in tip parametrov in enak tip vrednosti, ki jo vraata;

Programiranje 1 VS Informatika

C# . NET

144

Obe metodi morata imeti enak dostop. e je npr. virtualna metoda oznaena kot javna (public), mora biti javna tudi metoda override; Prepiemo (prekrijemo/povozimo) lahko le virtualno metodo. e metoda ni oznaena kot virtualna in bomo v nadrejenem razredu skuali narediti override, bomo dobili obvestilo o napaki; e v nadrejenem razredu ne bomo uporabili besedice override, bazina metoda ne bo prekrita. To pa hkrati pomeni, da se bo tudi v izpeljanem razredu izvajala metoda bazinega razreda in ne tista, ki smo napisali v izpeljanem razredu; e neko metodo oznaimo kot override, jo lahko v nadrejenih razredih ponovno prekrijemo z novo metodo.

Vaja: Razred Tocka in razred Tocka3D, ki je izpeljan iz razreda Tocka sta implementirana v naslednjem primeru:
class Tocka //bazni razred { private int x, y;

//polji razreda Tocka

public Tocka(int x,int y) //konstruktor { this.x = x; this.y = y; } //metoda Koordinate je virtualna, kar pomeni, da jo lahko preobloimo (naredimo override) public virtual void Koordinate() //metoda za izpis koordinat razreda Tocka { Console.WriteLine( "Koordinate toke:\nx = "+x + "\ny = " + y); } } class Tocka3D : Tocka { private int z; //razred Tocka3D je izpeljan iz razreda Tocka //dodatno polje razreda Tocka3D

public Tocka3D(int x,int y,int z) //konstruktor - parametra x in y potrebujemo za : base(x,y) //dedovanje bazinega konstruktorja razreda Tocka { this.z = z; } //Metoda Koordinate prepie istoimensko metodo razreda Tocka public override void Koordinate() { base.Koordinate(); //klic bazine metode Koordinate razreda Tocka Console.Write("z = "+z+"\n"); } } static void Main(string[] args) { Tocka A = new Tocka(1,1); //Nov objekt razreda Tocka A.Koordinate(); //klic metode Koordinate razreda Tocka Tocka3D A3D = new Tocka3D(1, 2, 3); //Nov objekt razerda Tocka3D A3D.Koordinate(); //klic preobloene metode Koordinate razreda Tocka3D }

Vaja:
/*Napiimo razred krog z zasebnim poljem polmer in virtualno metodo ploscina, nato pa e razred kolobar. Razred kolobar naj deduje razred krog, dodano naj ima e eno zasebno polje notranjiPolmer in svojo lastno(override) metodo polina*/ class krog //bazni razred { private int polmer; //polje razreda krog //metoda ploscina je virtualna, kar pomeni, da jo lahko preobloimo (override) public virtual double ploscina() { return Math.PI * polmer * polmer;

Programiranje 1 VS Informatika

C# . NET

145

} public int Polmer //lastnost(property) razreda krog, za dostop in inic. polja polmer { get { return polmer; } set { polmer = value; } } } class kolobar : krog //razred kolobar podeduje razred krog { //ker kolobar deduje krog, e pozna polje polmer private int notranjiPolmer; //dodatno polje razreda kolobar //metoda ploscina prepie istoimensko metodo bazinega razreda krog public override double ploscina() { return Math.PI * (Polmer * Polmer - notranjiPolmer*notranjiPolmer); } //ker kolobar deduje krog, e pozna njegovo lastnost Polmer //dodatna lastnost (property) razreda kolobar, za dostop in inic. polja notranjiPolmer public int NotranjiPolmer { get { return notranjiPolmer; } set { notranjiPolmer = value; } } } static void Main(string[] args) { Random naklj = new Random(); krog k=new krog(); k.Polmer = naklj.Next(1, 10);

//nov objekt razreda krog //polje polmer inicializiramo preko lastnosti Polmer

kolobar kol = new kolobar(); //nov objekt razreda kolobar //tudi polje polmer objekta kol inicializiramo preko lastnosti Polmer kol.Polmer = naklj.Next(1, 10); //polje notranjiPolmer inicializiramo preko lastnosti notranjiPolmer kol.NotranjiPolmer = naklj.Next(1, 10); //izpis ploine kroga na 4 decimalke Console.WriteLine("Ploina kroga: {0:F4}",k.ploscina()); //izpis ploine kolobarja na 4 decimalke Console.WriteLine("Ploina kolobarja: {0:F4}", kol.ploscina()); }

Vaja:
//Deklarirajmo razred Oseba, nato pa razred Kmetovalec, ki naj podeduje razred Oseba. Razred Oseba naj ima polje ime, razred Kmetovalec pa e dodatno polje velikostPosesti. Za oba razreda napiimo tudi konstruktor in virtualno metodo Tostring za izpis podatkov o posameznem objektu!*/ //glavni program static void Main(string[] args) { ArrayList osebe = new ArrayList(); Oseba mike = new Oseba("mike"); osebe.Add(mike); Console.WriteLine("Osebe:");

//zbirka oseb

Programiranje 1 VS Informatika

C# . NET

146

//izpiemo seznam vseh oseb foreach (Oseba p in osebe) Console.WriteLine(p.Tostring()); ArrayList kmetovalci = new ArrayList(); //zbirka kmetovalcev Kmetovalec john = new Kmetovalec("john", 10); Kmetovalec bob = new Kmetovalec("bob", 20); kmetovalci.Add(john); kmetovalci.Add(bob); Console.WriteLine(); Console.WriteLine("Kmetovalci:"); //izpiemo seznam vseh kmetovalcev foreach (Kmetovalec f in kmetovalci) Console.WriteLine(f.Tostring()); ArrayList vsiSkupaj = new ArrayList(); //napolnimo skupno zbirko vseh oseb foreach (Oseba o in osebe) vsiSkupaj.Add(o); foreach (Kmetovalec f in kmetovalci) vsiSkupaj.Add(f); Console.WriteLine(); Console.WriteLine("Vsi skupaj:"); //izpiemo seznam vseh oseb foreach (Oseba p in vsiSkupaj) Console.WriteLine(p.Tostring()); } public class Oseba { public string ime; public Oseba(string ime) { this.ime = ime; } //bazini razred //bazino polje //bazini konstruktor //zbirka vseh skupaj

public virtual string Tostring() { return "Ime=" + ime; } }

//virtualna metoda bazinega polja

public class Kmetovalec : Oseba //razred Kmetovalec deduje razred Oseba { int velikostPosesti; //dodatno polje razreda Kmetovalec public Kmetovalec(string ime, int velikostPosesti) //konstruktor razreda Kmetovalec : base(ime) //podeduje bazino polje ime { this.velikostPosesti = velikostPosesti; } public override string Tostring() //metoda Tostring prekrije bazino metodo Tostring { return base.Tostring() + "; Kvadratnih metorv = " + velikostPosesti.Tostring(); } }

Naloge: Napii razred Kocka tako, da bo izpeljan iz razreda Kvadrat. Razreda naj poleg svojih podatkov vsebujeta e privzeti konstruktor, metode za postavitev vrednosti podatkov in metode za izraun povrine, obsega in volumna.

Polimorfizem - mnogolinost

Programiranje 1 VS Informatika

C# . NET

147

V izpeljanih razredih se sreamo e z enim temeljnim pojmom objektno orientiranega programiranja to je pojem polimorfizem oz. mnogolinost. Pojem polimorfizem oznauje princip, da lahko razlini objekti razumejo isto sporoilo in se nanj odzovejo vsak na svoj nain. Pomeni tudi, da je ista operacija lahko implementirana na ve razlinih nainov oz. zanjo obstaja ve metod. Dedovanje in polimorfizem sta lastnosti, ki predstavljata osnovo objektnega programiranja in omogoata hitreji razvoj in laje vzdrevanje programske kode. Kot primer za prikaz polimorfizma deklarirajmo razred OsnovniRazred, ki ima eno samo metodo z imenom Slika. Ker elimo, da bo vsak objekt, ki bo izpeljan iz tega razreda (tudi tisti v podedovanih izpeljanih razredih) ohranil sebi lastno obnaanje ob klicu metode Slika, moramo uporabiti polimorfno redefinicijo. Polimorfno redefinicijo omogoimo z e znano definicijo virtualne metode. V telesu te metode bomo za vajo in zaradi enostavnosti prikazali le neko sporoilno okno!
public class OsnovniRazred //temeljni razred { public virtual void Slika() //polimorfna redefinicija omogoimo jo z { Console.WriteLine("Osnovni objekt!"); } }

virtualno metodo

Ker smo metodo Slika definirali kot virtualno, smo s tem napovedali, da bodo izpeljani objekti lahko uporabljali svojo (prekrivno oz. override) metodo Slika, ki pa bo imela enako ime. Razred OsnovniRazred bo na temeljni razred, iz katerega bomo tvorili izpeljane razrede in v njih tvorili nove objekte. Ker je metoda Slika virtualna to pomeni, da lahko v izpeljanih razredih to metodo prekrijemo (override) z metodo, ki bo imela enako ime a drugaen pomen (drugano vsebino). Napiimo sedaj e tri razrede, ki naj bodo izpeljani iz razreda OsnovniRazred in ki imajo svojo metodo Slika. Pred tipom takih metod mora stati besedice override, ki oznauje, da se bodo objekti izpeljani iz teh razredov na to metodo odzivali vsak na svoj nain. Osnovni pogoj pa je, da imajo take override metode enako raven zaite (npr. vse so public) , enako ime in enake parametre kot jih ima osnovna virtualna metoda v bazinem razredu.
public class Crta : OsnovniRazred //Crta je razred, ki podeduje razred OsnovniRazred { public override void Slika() //preobloena metoda razreda Crta { Console.WriteLine("rta."); //Telo override metode je seveda lahko drugano!!! } } public class Krog : OsnovniRazred //Tudi Krog je razred, ki podeduje razred OsnovniRazred { public override void Slika() { Console.WriteLine ("Krog."); //Telo override metode je seveda lahko drugano!!! } } public class Kvadrat: OsnovniRazred //Tudi Kvadrat je razred, ki podeduje razred OsnovniRazred { public override void Slika() //Telo override metode je seveda lahko drugano!!! { Console.WriteLine ("Kvadrat."); } }

Poglejmo sedaj, kako bi te tiri razrede sedaj uporabili in na primeru izpeljanih objektov prikazali princip polimorfizma. V ta namen kreirajmo tabelo objektov. Ime tabele je dObj, tabela pa naj bo inicializirana tako, da so v njej lahko tiri objekti tipa OsnovniRazred.

Programiranje 1 VS Informatika

C# . NET

148

OsnovniRazred[] dObj = new OsnovniRazred[4];//tabela objektov

Ker so razredi Crta, Krog in Kvadrat izpeljani iz bazinega razreda OsnovniRazred, jih lahko priredimo isti tabeli dObj. e te zmonosti ne bi bilo, bi morali za vsak nov objekt, izpeljan iz kateregakoli od teh tirih razredov, kreirati svojo tabelo. Dedovanje pa nam omogoa, da se vsak od izpeljanih objektov obnaa tako kot njegov bazini razred. Naslednjo kodo lahko zapiemo npr. v dogodek Click nekega gumba, ali pa neko opcijo menija.
dObj[0] dObj[1] dObj[2] dObj[3] = = = = new new new new Crta(); //konstruktor Krog(); //konstruktor Kvadrat(); //konstruktor OsnovniRazred();//konstruktor objekta objekta objekta objekta dObj[0] dObj[1] dObj[2] dObj[3]

foreach (OsnovniRazred objektZaRisanje in dObj) { objektZaRisanje.Slika(); //klic metode Slika ustreznega objekta }

Ko je tabela inicializirana, lahko npr. s foreach zanko pregledamo vsakega od objektov v tabeli. Zaradi naela polimorfizma se v zagnanem programu vsak objekt obnaa po svoje, pa odvisno od tega, iz katerega razreda je bil izpeljan. Ker smo v izpeljanih razredih prepisali virtualno metodo Slika , se ta metoda v izpeljanih objektih izvaja razlino, pa glede na njeno definicijo v izpeljanih razredih. Pri vsakem prehodu zanke bomo tako dobili drugano sporoilno okno.

Uporaba oznaevalca protected


Uporaba oznaevalcev private in public predstavlja obe skrajni monosti dostopa do lanov razreda (oz. objekta). Javna polja in metode so dostopne vsem, zasebna polja in metode pa so dostopne le znotraj razreda. Pogosto pa je koristno, da bazini razred dovoljuje izpeljanim razredom, da le-ti dostopajo do nekaterih bazinih lanov, obenem pa ne dovoljujejo dostopa razredom, ki niso del iste hierarhije. V takem primeru uporabimo za dostop oznaevalec protected. Nadrejeni razred torej lahko dostopa do lana bazinega razreda, ki je oznaen kot protected, kar praktino pomeni, da bazini lan, ki je oznaen kot protected, v izpeljanem razredu postane javen (public). Javen je tudi v vseh vijih razredih. V primeru, ko pa nek razred ni izpeljani razred, pa nima dostopa do lanov razreda, ki so oznaeni kot protected znotraj razreda, ki ni izpeljani razred, je torej lan razreda, ki je oznaen kot protected enak zasebenemu lanu (private).

Programiranje 1 VS Informatika

C# . NET

149

Prosojnice M. Lokar 2009

Objektno programiranje Objekti



Objekt je skupek podatkov, s katerim elimo upravljati kot s celoto. Ima

Podatke

Kakno je stanje (state) objekta kaj o objektu vemo/hranimo

stalni podatki / spremenljivi podatki

Metode
Kakno je obnaanje (behaviour) objekta Kaj objekt "zna" Kakne metode lahko izvajamo nad njem

Vsak objekt pripada nekemu razredu. e pripada objekt x razredu R, potem pravimo tudi da je x objekt tipa R.

Znani objekti

Nekaj primerov objektov iz standardnih knjinic jezika C# :

Objekt tipa StreamReader predstavlja vhodni kanal. Kadar elimo brati s tipkovnice ali z datoteke, naredimo tak objekt in kliemo njegovo metodo ReadLine za branje ene vrstice. Objekt System.Console predstavlja standardni izhod. Kadar elimo kaj izpisati na zaslon, pokliemo metodo WriteLine na objektu System.Console. Objekt tipa Random predstavlja generator nakljunih tevil.

Seveda pa so objekti uporabni predvsem zato, ker lahko programer definira nove razrede in objekte.

Objekti

stanja:
Programiranje 1 VS Informatika

C# . NET

150

Lastnosti, podatki, komponente znanje Odzivanje na dogodke Zdrueno v celoto Podatki in metode, ki opisujejo neko stvar/objekt oga:
Ulomek:

Podatki: velikost, barva, poloaj v prostoru, Metode: sprememba velikosti, sprememba poloaja, Podatki: tevec, imenovalec Metode: spremeni tevec, spremeni imenovalec, setej, obratna vrednost, lepo
izpii, ...

Primeri objektov

Datum

V objektih tipa datum bi npr. hranili datume

Podatki (stanje objekta)


Dan, mesec, leto

Metode (obnaanje / znanje)


Vrni mesec Vrni tevilo dni med dvema datumoma Naslednji dan Prejnji dan Lepo izpii Je leto prestopno Dan v tednu na doloen datum ...

Avto

Podatki

tehnine znailnosti:

Programiranje 1 VS Informatika

C# . NET

151

najvecjaHitrost (v km/h), velikostRezervoarja (v litrih) povprenaPoraba (v litrih/100 km).

trenutno stanje avtomobila

Je avto vgan (da/ne) Koliko je na tevcu km (npr. 234.142 km), Trenutna hitrost (npr. 56.12 km/h) Koliina Goriva (npr. 14.325 litrov).

"Obnaanje"

Vgi avto (spremeni stanje "vganosti") Ugasni avto (spremeni stanje "vganosti") "dej gas" (spremeni stanje hitrost) "bremzej" Natankaj gorivo Povej, za koliko km e zadoa gorivo ...

Primer problema

Napisati morate program, ki bo nadzoroval delovanje dvigal Objekt Dvigalo Podatki (stanje) objekta:

V katerem nadstropju je, koliko oseb je v njemu kakna je masa teh oseb.

Delovanje dvigala ("znanje", "obnaanje")


vstop oseb v dvigalo, izstop premik gor ali dol

Primer problema

Vodimo skladie kontejnerjev


Programiranje 1 VS Informatika

C# . NET

152

Radi bi napisali program, ki bi znal odgovoriti na doloena vpraanja

Izpis vsebine vseh polnih kontejnerjev Koliko je povsem praznih kontejnerjev Vsebina najvejega kontejnerja

Razred Kontejner

Tabela kontejnerjev Posamezni kontejner

Nov razred

Za vsak kontejner poznamo


Mere Zapolnjenost (v %) Vsebino

Kaj ponemo s posameznim kontejnerjem


Napolni z doloeno vsebino Poizvedi, koliko je zaseden Dodaj vsebino Izpii vsebino Poizvedi po merah

Programiranje v C#

Sestavljanje razredov

Opis lastnosti objektov Opis metod (znanja objektov)

Ustvarjanje objektov in njihova uporaba "Ukazovanje" objektom, kaj naj ponejo

Programiranje 1 VS Informatika

C# . NET

153

Objekt za izpolnitev doloene naloge potrebuje druge objekte in njihove metode

Zaetek

Glavni razred (ki ima metodo Main) Izvajanje metode Main ustvarjanje objektov, proenje dogodkov, odzivanje na dogodke,

Objekti
Objekt je kakrenkoli skupek podatkov, s katerimi elimo upravljati. Osnovni pristop objektnega programiranja

objekt = podatki + metode za delo s podatki.

Ko elimo kak podatek (objekt) obdelati, objektu (podatku) signaliziramo, kaj naj se zgodi.
Pokliemo ustrezno metodo v objektu.

Objekt je "rna katla, ki sprejema in poilja sporoila. Jedro objekta sestavljajo njegove spremenljivke, okrog katerih se nahajajo njegove metode.

Princip rne katle



Imamo objekt obj, ki hrani podatke o neki osebi. Zanima nas inteligenni kolinik te osebe.

obj.KolikoJeIQ()

Objekt se odzove z odgovorom Uporabnika ne zanima, kako je objekt priel do odgovora, le kaj ga lahko vpraa in v kakni obliki bo dobil odgovor! Ni vano, kako je objekt odgovoril kako je priel do IQ (je to podatek, ki je zapisan nekje v objektu, je to rezultat nekega preraunavanja

Programiranje 1 VS Informatika

C# . NET

154

Prednosti "rne katle"



e kasneje spremenimo notranjost "rne katle" (razreda) Spremembe v programih, ki razred uporabljajo, niso potrebne


Npr.:

Seveda, e je nain spraevanja in odgovarjanja ostal nespremenjen e so metode ostale enake (imajo enaka imena, nabor parametrov in tip rezultata)

ef ugotovi, da bi bilo smiselno, da v vaih programih pri datumu hranite e as. Ampak stvari naj bi naredili tako, da obstojei programi ne bi bili prizadeti (beri, da bi delali e naprej) e je razred "rna" katla, lahko naredimo spremembe tako, da ne bo "staro" prizadeto

Pomislite samo na "obiajno ivljenje"

Verjetno je zgradba menjalnika danes bistveno drugana, kot je bila pred 30 leti A kar se oferja (starega ;-) ) tie, se ni ni spremenilo s to rno katlo (menjalnikom) upravlja e vedno na enak nain kot pred 30 leti

e se bodo v C# 2013 odloili, da razred Random spemenijo (spremenijo notranjost "rne katle"), a bomo e vedno imeli metodo Next(a, b), se za programerja ne bo ni spremenilo, eprav bo metoda Next morda "znotraj" delala drugae!

Od kje razredi?

Veliko vgrajenih (oziroma v standardnih knjinicah) v C#

.NET Framework C# je .NET jezik ima dostop do vseh razredov, definiranih v knjinicah (zbirkah razredov) okolja .NET

Glej npr. http://msdn2.microsoft.com/sl-si/library/ms229335(enus).aspx


Drugi viri

Razporejeni v imenske prostore

System, System.IO

Nai stari razredi Drugi programerji

Potrebujemo dostop do ustrezne datoteke (dll, exe)

Programiranje 1 VS Informatika

C# . NET

155

Moj prvi razred


Oglejmo si naslednji program: using System;

public class MojR{ private string mojNiz;

public MojR(string nekNiz) { mojNiz = nekNiz; }

public void Izpisi() { Console.WriteLine(mojNiz); } }

public class Pozdrav { public static void Main(string[] arg) MojR prvi; {

prvi = new MojR("Pozdravljen, moj prvi objekt v C#!"); prvi.Izpisi(); } }

Objekt in ime spremenljivke



NekiObjekt a;

a je naslov, kjer bo objekt (referenca na objekt)


V pomnilniku se je naredil objekt tipa NekiObjekt() / po pravilih, ki so doloena z opisom razreda NekiObjekt

new NekiObjekt();

a = new NekiObjekt();
V pomnilniku se je naredil objekt tipa NekiObjekt() in a kae na ta novo ustvarjeni objekt
Programiranje 1 VS Informatika

C# . NET

156

Ustvarjanje objektov

Razred je ablona, ki definira spremenljivke in metode skupne vsem objektom iste vrste. class

Nart objekta, ablona Ustvarimo ga z new Brez tega objekta NE MOREMO uporabiti NekiObjekt a;

Primerek razreda (instanca) konkretni objekt

Objekt NE obstaja a je IME objekta natanneje

a je ime spremenljivke, kjer hranimo NASLOV objekta vrste NekiObjekt

C#in objekti

Razred (class) je opis vrste objekta (nart, kako naj bo objekt videti) opis ideje objekta Primerek razreda (instanca) konkretni objekt

Ustvarjanje objektov

Ulomek ime = new Ulomek(3, 4); Reemo:

V objektu ime je shranjen ulomek

Toneje
V spremenljivki ime je naslov nekega objekta tipa Ulomek, ki predstavlja ulomek Spremenljivka ime kae na objekt tipa Ulomek, ki

Prvi ukaz je dejansko spoj dveh stavkov:


deklaracija prireditev

Ulomek ime; ime = new Ulomek(3, 4);

Programiranje 1 VS Informatika

C# . NET

157

Ustvarjanje objektov

Ulomek ime; ime = new Ulomek(3, 4);

e en zgled

Poglejmo si e en zgled. Denimo, da bi radi napisali program, ki bo prebral nek ulomek in mu pritel 1/2. "klasino" se bomo tega lotili takole

Programiranje 1 VS Informatika

C# . NET

158

Poveaj ulomek "klasino"


using System; namespace UlomkiKlasika { class Program { public static void Main(string[] args) { // vnos podatkov Console.Write("tevec ulomka: "); string beri = Console.ReadLine(); int stevec = int.Parse(beri); Console.Write("Imenovalec ulomka: "); beri = Console.ReadLine(); int imenovalec = int.Parse(beri); // "delo" stevec = stevec + 1; imenovalec = imenovalec + 2; // izpis Console.WriteLine("Nov ulomek je: " + stevec + " / " + imenovalec); Console.Write("Press any key to continue . . . "); Console.ReadKey(true); } } }

Poveaj ulomek - objektno



Razred Ulomek Hrani podatke o svojem tevcu in imenovalcu "se zna" poveati za drug ulomek

Vsebuje metodo, ki ta ulomek povea za drug ulomek

Programiranje 1 VS Informatika

C# . NET

159

"Objektni" program Ulomki - objektno


using System; namespace UlomkiObjektno { class Ulomek { public int stevec; public int imenovalec;

public Ulomek(int st, int im) { this.stevec = st; this.imenovalec = im; }

public void Pristej(Ulomek a) { this.stevec = this.stevec + a.stevec; this.imenovalec = this.imenovalec + a.imenovalec; } } class Program { public static void Main(string[] args) { // vnos podatkov

Ulomki - objektno
Console.Write("tevec ulomka: "); string beri = Console.ReadLine(); int stevec = int.Parse(beri); Console.Write("Imenovalec ulomka: "); beri = Console.ReadLine(); int imenovalec = int.Parse(beri);

Programiranje 1 VS Informatika

C# . NET

160

Ulomek moj = new Ulomek(stevec, imenovalec);

// "delo"

Ulomek polovica = new Ulomek(1, 2);

moj.Pristej(polovica); // izpis Console.WriteLine("Nov ulomek je: " + moj.stevec + " / " + moj.imenovalec);

Primerjava

"klasino" // "delo" stevec = stevec + 1; imenovalec = imenovalec + 2;

objektno

Ulomek polovica = new Ulomek(1, 2); moj.Pristej(polovica);

Ulomek

Ampak ulomke smo setevali narobe, po "Janezkovo"!

Saj veste ... Inpektor ree ... Saj se ulomki ne setevajo tako, da se posebej setejeta tevec in imenovalec ... Uitelj Janezek pa ... Saj vem, ampak tako si laje zapomnijo ...

Napisali pa smo e nekaj 10 programov z "janezkovim setevanjem"

Programiranje 1 VS Informatika

C# . NET

161

Klasino: preko kode vseh 10 programov in "iemo", kje smo pravzaprav setevali Objektno: le spremenimo metodo Pristej v razredu Ulomek, nato pa

Ni, to je vse ...

Objektno programiranje

Problem

Z analizo ugotovimo, kakne objekte potrebujemo za reevanje Pregledamo, ali e imamo na voljo ustrezne razrede

Standardna knjinica Druge knjinice Nai stari razredi

Sestavimo ustrezne manjkajoe razrede Sestavimo glavni program, kjer s pomojo objektov reimo problem

Objekti, razredi, ...


Od kje in zakaj

Zdruevanje podatkov

Denimo, da piemo program, ki bo pomagal upravljati farmo zajcev Za vsakega zajca poznamo:

serijsko tevilko spol teo Tabela ni ustrezna

Kako dosei, da se podatki drijo skupaj

Tabela je zbirka istovrstnih podatkov


Sestavimo razred Zajec Opis podatkov, ki sestavljajo poljubnega zajca

Programiranje 1 VS Informatika

C# . NET

162

Moj prvi razred

Razredi za uporabo znotraj nekega programa

"lokalni" razredi Kot prej (Console Application ...)

namespace PrviOOP { public class MojR { private string mojNiz; public MojR(string nekNiz) { mojNiz = nekNiz; } public void Izpisi(){ Console.WriteLine(mojNiz); } } public class Pozdrav { public static void Main(string[] arg) { MojR prvi; prvi = new MojR("Pozdravljen, moj prvi objekt v C#!"); prvi.Izpisi(); } } }

Knjinica razredov

Knjinice razredov Programiranje 1 VS Informatika

C# . NET

163

Komentarji

// - vrstini komentar /* ... */ : sploen komentar /// dokumentacijski komentar

Glej npr: http://www.softsteel.co.uk/tutorials/cSharp/lesson19.html http://www.winnershtriangle.com/w/Articles.XMLComments InCSharp.asp http://www.csharphelp.com/archives3/archive598.html

Razred Zajec
public class Zajec { public string serijska; public bool spol; public double masa; }

S tem imamo napisan opis, kako je doloen poljuben zajec

Nart, kakni so zajci Ni to konkreten zajec

Ni metode Main, dejansko se NI ne izvede, ... Ni namenjeno poganjanju kot program Hisa.cs

Nart, kako je videti hia Kot ga je pripravil projektant

Prevedemo
Hisa.dll (na zgled: MojiRazredi.dll)

e vedno nart, kakna naj bo hia V obliki, kot ga lahko uporabijo tisti, ki bodo po tem nartu izdelali konkretno hio

Programiranje 1 VS Informatika

C# . NET

164

Uporaba razreda Zajec

Program, kjer delamo z zajci:

Potrebuje datoteko MojiRazredi.dll (ker vsebuje definicijo razreda Zajec) Napovemo uporabo te datoteke Project / Add reference

Uporaba razreda Zajec

Program, kjer delamo z zajci:

Potrebuje datoteko ClassLibrary1.dll (ker vsebuje definicijo razreda Zajec) Napovemo uporabo te datoteke Okolje: Project / Add reference

Uporaba razreda Zajec



Program, kjer delamo z zajci: using MojiRazredi; oziroma using ClassLibrary1; ... e v programu potrebujemo konkretnega zajca, ga napovemo

Zajec rjavko

ustvarimo z new new Zajec() Ustvaril se je konkreten zajec po navodilih za razred Zajec (ta zajec ima torej tri
podatke / lastnosti / komponente)

Metoda je vrnila naslov, kje ta konkretni zajec je


Programiranje 1 VS Informatika

C# . NET

165

Zajec rjavko = new Zajec();

V spremenljivki rjavko je naslov, kje je novo ustvarjeni zajec (objekt)

Dostop do podatkov v objektu



rjavko.spol = true; rjavko.serijska = BRGH_17_A; rjavko.masa = 3.2;

Razred Zajec e konni pogled na naslove



Potem bomo malek "popustili" ;-) Zajec[] tabZ; Ustvarili smo spremenljivko tabZ. V spremenljivki tabZ lahko shranimo naslov tabele, v katero bomo
lahko shranjevali naslove objektov tipa Zajec. Trenutno v tej spremenljivki ni nobenega naslova.

tabZ = new Zajec[200]; Operator new je nekje ustvaril tabelo, v kateri je prostor za 200 naslovov objektov, v katerih lahko
shranimo podatke o posameznem zajcu. Naslov tega prostora za tabelo smo shranili v spremenljivko tabZ. V tem trenutku ne obstaja e noben objekt tipa Zajec. Operator new je nekje ustvaril prostor za objekt tipa Zajec. Naslov tega objekta se je shranil v 0-to celico tabele, katere naslov je shranjen v spremenljivki tabZ.

tabZ[0] = new Zajec();

Seveda pa bomo govorili ... V tabeli tabZ je na mestu 0 zajec ...

Programiranje 1 VS Informatika

C# . NET

166

Razred shramba podatkov

public class Ulomek { public int stevec; public int imenovalec; } Prevedemo in dobimo Ulomek.class Kaj sedaj?

Uporabljamo v drugih programih (razredih) Ulomek x = new Ulomek(); x.stevec : spremenljivka tipa int! x.imenovalec : enako x.stevec = 1; x.imenovalec = x.stevec + 1;

Kako napolniti stevec in imenovalec?

Povzetek

Definicija razreda

Obiajno v knjinici!

Programiranje 1 VS Informatika

C# . NET

167

public class ImeRazreda { public podatkovni tip element1; public podatkovni tip element2; public podatkovni tip elementn; }

Povzetek

Uporaba razreda

e potrebujemo primerek razreda new ImeRazreda()

Ustvari prostor in pove, kje ta prostor je

Naslov prostora shranimo v neko spremenljivko (tipa


ImeRazreda), denimo mojaSpTipaImeRazreda

Dostop do prostorov za hranjenje

Operator .

imeObjekta.elementi imeObjekta.imeKomponente mojaSpTipaImeRazreda.starost

Konstruktorji
Ob tvorbi objekta bi radi nastavili zaetno stanje
spremenljivk in morda opravili e kaj o tem kasneje Konstruktor metoda, ki jo pokliemo ob tvorbi objekta z new Brez tipa rezultata!
Programiranje 1 VS Informatika

C# . NET

168

Ime kot je ime razreda Kliemo jo skupaj z new

Klic: new Zajec();

Razred Zajec
public class Zajec { public String serijska; public boolean spol; public double masa; // konstruktor public Zajec() { this.spol = true; // vsem zajcem na this.masa = 1.0; // in tehtajo 1kg this.serijska = NEDOLOENO; } }

zaetku doloimo m. spol

Zajca ustvarimo z new



new Zajec() Ustvaril se je konkreten zajec po navodilih iz konstruktorja Zajec() (ta zajec ima torej tri podatke z vrednostmi, kot je predpisano v konstruktorju) Kaj je this?

this

this

Pomeni objekt, ki ga "obdelujemo" V konstruktorju objekt, ki ga ustvarjamo


Programiranje 1 VS Informatika

C# . NET

169

this.spol Lastnost/komponenta spol objekta, ki se ustvarja

Zajec rjavko = new Zajec(); Zajec belko= new Zajec(); Pri prvem klicu se je v konstruktorju this nanaal
na rjavko, pri drugem na belko.

this v ostalih metodah

Kasneje pisali bomo metode, ki se bodo uporabljale nad razredi Random ng = new Random(); Random g2 = new Random(); Console.WriteLine(ng.Next(1,10)); Kako so napisali kodo metode, da se je vedelo, da pri metodi Next mislimo na
uporabo generatorja ng in ne na g2?

Kako se v metodah razreda sklicati na ta objekt (objekt, nad katerim je izvajana metoda)? Razred MojRazred in v njem komponenta starost. Napiimo metodo
MetodaNeka(), ki izpie starost objekta, nad katerim izvajamo metodo.

Klici bodo npr.: objA.MetodaNeka(), objC.MetodaNeka() Kako v postopku za MetodaNeka povedati, da gre

Prvi za objekt z imenom objA drugi za objekt z imenom objC

Programiranje 1 VS Informatika

C# . NET

170

this v ostalih metodah

Kako povedati, da naj se ob klicu objA.MetodaNeka() uporabi starost objekta objA, ob klicu objC.MetodaNeka() pa starost objekta objC?

Console.WriteLine("Starost je: " + ?????.starost);

Ob prvem klicu je ???? objA, ob drugem pa objC. To "zamenjavo" doseemo z this. Napiemo

Console.WriteLine("Starost je: " + this.starost);

Ob prvem klicu this pomeni objA, ob drugem pa objC.

Konstruktorji e konstruktorja ne napiemo (kot ga


nismo prej), ga naredi prevajalnik sam (a metoda ne naredi ni)

public Zajec() { }

Lahko imamo ve konstruktorjev Konstruktorjev ne moremo klicati posebej (kot


ostale metode) Le ko tvorimo objekt new Za vzpostavitev zaetnega stanja Enako ime kot razred Nimajo tipa rezultata (tudi void ne!) Ni stavka return
Programiranje 1 VS Informatika

C# . NET

171

Ve konstruktorjev

Uporabniki bi poleg privzetega zajca, radi e monost, da bi takoj, ko zajca naredijo, temu doloili e serijsko tevilko. Radi bi torej konstruktor public Zajec(string serijskaSt) Poleg tega pa vasih na farmo dobijo tudi poiljko samic. Torej potrebujejo e konstruktor

public Zajec(bool spol) public Zajec(string serijskaSt, bool spol, double teza)

Vasih pa so zajci "nestandardni"

Potrebujemo ve nainov nastavljanja zaetnega stanja objekta Ve konstruktorjev:

Ve metod z enakim imenom Je to mono?

Preobteevanje
Ve metod z enakim imenom

Je to mono? Overloading Velja tudi splono, za vse metode

Preobteevanje

Metode se morajo razlikovati ne v imenu, ampak podpisu Podpis metode

Podpis: ime + tevilo in tipi parametrov!

public static int NekaMetoda(double Podpis (poenostavljeno): NekaMetoda_double

x)

Tip rezultata (return tip) NI del podpisa! public static int NekaMetoda(double x)

Programiranje 1 VS Informatika

C# . NET

172

Podpisi metod

Podpis metode: public static int NekaMetoda(double Podpis: NekaMetoda_double interno ime public Zajec(string serijskaStev,
bool spol, double masa) x)

Podpis:

Zajec_String_bool_double

Kaj je lahko soasno: public static int NekaMetoda() public static int NekaMetoda(double y) public static int NekaMetoda(double x) public static double NekaMetoda(double x) public static int NekaDrugaMetoda(double y)

Konstruktorji razreda Zajec


public Zajec() { this.spol = true; // vsem zajcem na this.masa = 1.0; // in tehtajo 1kg this.serijska = NEDOLOENO; }
zaetku doloimo m. spol

public Zajec(string serijskaStev):this() { this.serijska = serijskaStev; }

: this() klic konstruktorja Zajec() Izvede se pred vsemi ukazi v konstruktorju

Programiranje 1 VS Informatika

C# . NET

173

Sklicevanje na konstruktorje
public Zajec(string ser, bool sp, double t) : this(ser) { this.spol = sp; this.masa = t; }

this

this(

Za klic konstruktorja pred zaetkom drugega konstruktorja

this() this(<parametri>)
Uporabimo lahko le kot PRVI stavek v konstruktorju Za dostop do lastnosti this.serijska e ni monosti zamenjave, lahko izpustimo serijska this.spol = spol; Obstajala je e DRUGO ime spol Loiti med spremenljivko spol, ki je parameter in lastnostjo objekta z imenom spol

this.

"Prednost" ima bolj "lokalna" stvar torej parameter

spol

= spol;

Zgled lani portnega kluba


Denimo, da bi radi napisali program, ki vodi
evidenco o lanih portnega kluba. Podatki o lanu
Programiranje 1 VS Informatika

C# . NET

174

obsegajo ime, priimek, letnico vpisa v klub in vpisno tevilke (seveda je to poenostavljen primer). Torej objekt, ki predstavlja lana kluba, vsebuje tiri podatke:

Programiranje 1 VS Informatika

C# . NET

175

public class Clan { public string ime; public string priimek; public int letoVpisa; public string vpisnaStevilka; }

Klub - uporaba
using MojaKnjiznica; public class TestKlub { public static void Main(string[] args) {

Clan a = new Clan(); a.ime = "Janez"; a.priimek = "Starina"; a.letoVpisa = 2000; a.vpisnaStevilka = "2304";

Clan b = new Clan(); b.ime = "Mojca"; b.priimek = "Mavko"; b.letoVpisa = 2001; b.vpisnaStevilka = "4377";

Clan c = b; c.ime = "Andreja";

Console.WriteLine("Clan a:\n" + a.ime + " " + a.priimek + " " + a.letoVpisa + " (" + a.vpisnaStevilka + ")\n");

Programiranje 1 VS Informatika

C# . NET

176

Console.WriteLine("Clan b:\n" + b.ime + " " + b.priimek + " " + b.letoVpisa + " (" + b.vpisnaStevilka + ")\n"); Console.WriteLine("Clan c:\n" + c.ime + " " + c.priimek + " " + c.letoVpisa + " (" + c.vpisnaStevilka + ")\n"); Console.ReadLine(); } }

Zakaj
public class TestKlub { public static void Main(string[] args) {

Clan a; a = new Clan(); a.ime = "Janez"; a.priimek = "Starina"; a.letoVpisa = 2000; a.vpisnaStevilka = "2304";

Clan b = new Clan(); b.ime = "Mojca"; b.priimek = "Mavko"; b.letoVpisa = 2001; b.vpisnaStevilka = "4377";

Clan c; c = b; c.ime = "Andreja";

Console.WriteLine("Clan a:\n" + a.ime + " " + a.priimek + " " + a.letoVpisa + " (" + a.vpisnaStevilka + ")\n");

Console.WriteLine("Clan b:\n" + b.ime + " " + b.priimek +

Programiranje 1 VS Informatika

C# . NET

177

" " + b.letoVpisa + " (" + b.vpisnaStevilka + ")\n"); Console.WriteLine("Clan c:\n" + c.ime + " " + c.priimek + " " + c.letoVpisa + " (" + c.vpisnaStevilka + ")\n"); Console.ReadLine(); } }

Zgled portni klub, nadaljevanje


Spremenimo sedaj na razred Clan tako, da bomo
uporabili konstruktor

Programiranje 1 VS Informatika

C# . NET

178

public class Clan { public string ime; public string priimek; public int letoVpisa; public string vpisnaStevilka;

public Clan(string i, string p, int l, string v) { this.ime = i; this.priimek = p; this.letoVpisa = l; this.vpisnaStevilka = v; } }

prtni klub - test

Bo na testni program OK? Poenimo Napake!


Kako, rekli smo, da spreminjanje
razreda ne vpliva na uporabnike programe Spremenili smo nain uporabe V testnem programu: Clan()
Programiranje 1 VS Informatika

C# . NET

179

Tega sedaj ni

C# ga naredi sam le, e nismo napisali nobenega konstruktorja

Popravljeni zgled
public class Clan { public string ime; public string priimek; public int letoVpisa; public string vpisnaStevilka;

public Clan() { this.ime = "Ne vem"; this.priimek = "Ne vem"; this.letoVpisa = 0; this.vpisnaStevilka = "Ne vem"; }

public Clan(string i, string p, int l, string v) { this.ime = i; this.priimek = p; this.letoVpisa = l; this.vpisnaStevilka = v; } }

Poskus testa Ni teav!


Programiranje 1 VS Informatika

C# . NET

180

Zakaj ves ta napor, e pa je na koncu le


isto ... Preglednost! In priprava za naprej

Programiranje 1 VS Informatika

C# . NET

181

Primerjava: brez / s konstruktiorjem


public class TestKlub { public static void Main(string[] args) { Clan a = new Clan(); a.ime = "Janez"; a.priimek = "Starina"; a.letoVpisa = 2000; a.vpisnaStevilka = "2304";

Clan b = new Clan(); b.ime = "Mojca"; b.priimek = "Mavko"; b.letoVpisa = 2001; b.vpisnaStevilka = "4377";

Clan c = b; c.ime = "Andreja"; ...

public class TestClan{ public static void Main(string[] args) { Clan a = new Clan("Janez", "Starina", 2000, "2304"); Clan b = new Clan("Mojca", "Mavko", 2001, "4377"); Clan c = b;

Programiranje 1 VS Informatika

C# . NET

182

c.ime = "Andreja"; ...

Objektne metode V definicijo razreda obiajno spadajo tudi


metode Klic objektnih metod:
imeObjekta.imeMetode(parametri) System.Console.WriteLine("To naj se
izpie"); besedilo.Equals(primerjava)

Metoda v razredu Clan

Programiranje 1 VS Informatika

C# . NET

183

public string Inicialke() { return this.ime[0] + "." + this.priimek[0] + "."; }

Uporaba metode
using MojiRazredi; // knjinica z razredom Clan public class TestClan{ public static void Main(string[] args) { Clan a = new Clan("Janez", "Starina", 2000, "2304"); String inicialkeClanaA = a.Inicialke(); Console.Write("Clan a:\n" + a.ime + " " + a.priimek + " " + a.letoVpisa + " (" + a.vpisnaStevilka + ") "); Console.WriteLine("ima inicialke: " + inicialkeClanaA); } }

Sprememba metode
public class Clan { public string ime;

Programiranje 1 VS Informatika

C# . NET

184

public string priimek; public int letoVpisa; public string vpisnaStevilka;

public Clan() { ime = "Ne vem"; priimek = "Ne vem"; letoVpisa = 0; vpisnaStevilka = "Ne vem"; } public Clan(string i, string p, int l, string v) : this() { ime = i; priimek = p; letoVpisa = l; vpisnaStevilka = v; } public string Inicialke() { return this.ime[0] + " " + this.priimek[0]; } }

Metoda, ki vraa objekt iz Razreda Vemo, da z


a = b; kjer sta a in b obe spremenljivki tipa Clan, v a ne shranimo kopije objekta b, ampak sedaj a in b oznaujeta isti objekt. Metoda, ki naredi kopijo objekta.
Programiranje 1 VS Informatika

C# . NET

185

a = b.Kopija();

V a je nov objekt, ki pa ima iste podatke kot b.

Programiranje 1 VS Informatika

C# . NET

186

Kopija
public Clan Kopija() { Clan nov = new Clan(); nov.ime = this.ime; nov.priimek = this.priimek; nov.letoVpisa = this.letoVpisa; nov.vpisnaStevilka = this.vpisnaStevilka; return nov; }

e metoda za izpis
public void Izpis() { Console.WriteLine("Clan:\n" + this.ime + " " + this.priimek + " " + this.letoVpisa + " (" + this.vpisnaStevilka + ")\n"); }

ali pa e
Programiranje 1 VS Informatika

C# . NET

187

public string Opis() { return this.ime + " " + this.priimek + " " + this.letoVpisa + " (" + this.vpisnaStevilka + "); }

Uporaba
public class TestKlub { public static void Main(string[] args) {

Clan a = new Clan("Janez", "Starina", 2000, "2304"); Clan b = new Clan("Mojca", "Mavko", 2001, "4377"); Clan c = b; c.ime = "Andreja"; Clan d = b.Kopija(); d.ime = "Tadeja";

Console.WriteLine("Clan a"); a.Izpis(); Console.WriteLine("Clan b:\n" + b.Opis()); Console.WriteLine("Clan c:\n" + c); Console.WriteLine("Clan d"); d.Izpis(); Console.ReadLine(); } }

Programiranje 1 VS Informatika

C# . NET

188

Razred Datum

Denimo, da v naih programih pogosto delamo z datumi. Zato bomo sestavili ustrezni razred Nart razreda: Podatki
dan (tevilo) mesec (izbira: tevilo ali pa niz) Leto (tevilo)

Metode

Konstruktorji Izpii Poveaj za 1 dan Je datum smiselen Je leto prestopno Nov datum za toliko in toliko dni pred/za danim datumom Dan v tednu ...

Programiranje 1 VS Informatika

C# . NET

189

Datum podatki in konstruktor


public class Datum { public int dan; public string mesec; public int leto; public Datum() { dan = 1; mesec = "januar" leto = 2000; } // privzeti datum je torej 1.1.2000

Dodatni konstruktorji
public Datum(int leto) : this() { this.leto = leto; // this je nujen } // datum je torej 1.1.leto public Datum(int d, string m, int l) : this(l) { // leto smo e nastavili this.mesec = m; // this ni nujen this.dan = d; } // datum je torej d.m.l (na primer 12.3.2006 ali
Programiranje 1 VS Informatika

C# . NET

190

// 12. marec 2006)

Prestopno
Zanima nas, ali je leto prestopno

Programiranje 1 VS Informatika

C# . NET

191

public bool JePrestopno() { int leto = this.leto; if (leto % 4 != 0) return false; if (leto % 400 == 0) return true; if (leto % 100 == 0) return false; return true; }

Dodaj en dan
public void PovecajZaEnDan() { dan = dan + 1; if (dan < 29) return; if (dan == 29 && mesec != "februar") return; if (dan == 29 && mesec == "februar" && this.JePrestopno()) return; // lahko nehamo, mesec in leto sta ok string[] meseciPo30 = {"april","junij","september", "november"}; if (dan == 31) { if (meseciPo30.IndexOf(mesec) > 0){ mesec = mesec + 1; if (mesec == 13) { mesec = 1; leto++; }
Programiranje 1 VS Informatika

C# . NET

192

return; } // e je 32 dni, je zagotovo

Uporaba razreda
Ugotovi, e je letonje leto prestopno!

Programiranje 1 VS Informatika

C# . NET

193

using MojiRazredi; public class JeLetosPrestopnoLeto { Datum danes = new Datum(5, 3, 2009); if (danes.jePrestopno()) { Console.WriteLine("Je prestopno leto"); } else { Console.WriteLine("Ni prestopno leto"); } }

Sprememba razreda Imamo


if (enClan.letoVpisa > drugClan.letoVpisa) {

Spremenimo razred Clan, tako, da vodimo


datum vpisa

Programiranje 1 VS Informatika

C# . NET

194

public class Clan { public string ime; public string priimek; public Datum datumVpisa; public string vpisnaStevilka;

public Clan() { ime = "Ne vem"; priimek = "Ne vem"; datumVpisa = new Datum(); vpisnaStevilka = "Ne vem"; }

Sprememba razreda
public Clan(string i, string p, Datum d, string v) : this() { ime = i; priimek = p; datumVpisa = d; vpisnaStevilka = v; }

public string Inicialke() { return this.ime[0] + "." + this.priimek[0] + "."; }

public Clan Kopija() { Clan nov = new Clan(); nov.ime = this.ime; nov.priimek = this.priimek; nov.datumVpisa = this.datumVpisa.Kopija(); nov.vpisnaStevilka = this.vpisnaStevilka;

Programiranje 1 VS Informatika

C# . NET

195

return nov; }

public void Izpis() { Console.WriteLine("Clan:\n" + this.ime + " " + this.priimek + " " +

this.datumVpisa.OpisDat() + " (" + this.vpisnaStevilka + ")\n"); }

Sprememba razreda
public string Opis() { return this.ime + " " + this.priimek + " " + this.datumVpisa.OpisDat() + " (" + this.vpisnaStevilka + "); }

public string ToString() { return this.Opis(); }

public bool SpremeniLetoVpisa(int l) { if ((2000 <= leto) && (leto <= 2020)) { this.datumVpisa.leto = l; return true; //leto je smiselno, popravimo stanje objekta in
vrnemo true

} return false; // leto ni smsielno, ne spremnimo in in vrnemo false } }

Programiranje 1 VS Informatika

C# . NET

196

Sprememba razreda
public Clan(string i, string p, Datum d, string v) : this() { ime = i; priimek = p; datumVpisa = d; vpisnaStevilka = v; }

public string Inicialke() { return this.ime[0] + "." + this.priimek[0] + "."; } public Clan Kopija() { Clan nov = new Clan(); nov.ime = this.ime; nov.priimek = this.priimek; nov.datumVpisa = this.datumVpisa.Kopija(); nov.vpisnaStevilkaevilka = this.vpisnaStevilka; return nov; }

Sprememba razreda
public void Izpis() { Console.WriteLine("Clan:\n" + this.ime + " " + this.priimek + " " + this.datumVpisa.OpisDat() + this.vpisnaStevilka + ")\n"); } public string Opis() {
Programiranje 1 VS Informatika

" (" +

C# . NET

197

return this.ime + " " + this.priimek + " " + this.datumVpisa.OpisDat() + " (" + this.vpisnaStevilka + "); } public bool SpremeniLetoVpisa(int l) { if ((2000 <= leto) && (leto <= 2020)) { this.datumVpisa.leto = l; return true; } return false; // leto ni smiselno, ne spremenimo ni in vrnemo false } }
//leto je smiselno, popravimo stanje objekta in vrnemo true

Nain programiranja Seveda zaradi spremembe


if (enClan.letoVpisa > drugClan.letoVpisa) { ne deluje ve! Kako popraviti?

Programiranje 1 VS Informatika

C# . NET

198

e v prvotnem razredu
public class Clan { public string ime; public string priimek; public int letoVpisa; public string vpisnaStevilka;

public bool SpremeniLetoVpisa(int leto) { if ((2000 <= leto) && (leto <= 2020)) { this.letoVpisa = leto; return true; } return false; // leto ni smiselno, ne spremnimo ni in vrnemo false } public int VrniLetoVpisa() { return this.letoVpisa; } }

Ob spremembi razreda Clan


Le metodo

Programiranje 1 VS Informatika

C# . NET

199

public int VrniLetoVpisa() { return this.letoVpisa; }

zamenjamo z
public int VrniLetoVpisa() { return this.datumVpisa.leto; }

Dostop do stanj objekta



Monost, da neposredno dostopamo do stanj/lastnosti objekta NI NAJBOLJI!

Ne le, da ni najbolji, je == CENZURA == rjavko.masa = -3.2; Ker ne moremo vedeti, ali so podatki pravilni -vsi postopki po nepotrebnem bolj zapleteni Objekt naj sam poskrbi, da bo v pravilnem stanju

Nobene kontrole nad pravilnostjo podatkov o objektu!

Teave, e moramo kasneje spremeniti nain predstavitve podatkov o objektu

Programiranje 1 VS Informatika

C# . NET

200

Zgled
public class TestClan{ public static void Main(string[] args) { Clan novClan = new Clan(); novClan.ime = "Katarina"; novClan.letoVpisa = 208;

Dodajmo metodo Ni problem, napisali bomo metodo, ki bo


vnos preverjala

Programiranje 1 VS Informatika

C# . NET

201

public class Clan { public string ime; public string priimek; public int letoVpisa; public string vpisnaStevilka;

// konstruktorji in metode kot prej! public bool SpremeniLetoVpisa(int leto) { if ((2000 <= leto) && (leto <= 2020)) { this.letoVpisa = leto; return true; //leto je smiselno, popravimo stanje objekta in vrnemo true } return false; // leto ni smiselno, ne spremenimo ni in vrnemo false } }

Uporaba metode
public class TestKlub { public static void Main(string[] args) { Clan novClan = new Clan(); novClan.ime = "Katarina"; novClan.letoVpisa = 2007; novClan.SpremeniLetoVpisa(208);
Programiranje 1 VS Informatika

C# . NET

202

novClan.SpremeniLetoVpisa(2008);

Dostopi do stanj

ime_objekta.stanje Zakaj je to lahko problem?

zunanji uporabnik nastavi napano vrednost

z1.masa = -100.10; Kasneje je ni mogoe spremeniti

Uporabnik pozna predstavitev

Naini dostopa

internal public string serijska; private Datum datumRojstva; private double masa; public int[] tab;

public private protected

bool spol;

public
Znotraj razreda NI omejitev, vedno (ne glede na
nain dostopa) je moen dostop do komponent. public Do lastnosti lahko dostopajo vsi, od kjerkoli (iz katerihkoli
datotek (razredov))

imeObjekta.lastnost

public int javnaLastnost; // v razredu


MojObjekt

Kdorkoli naredi objekt vrste MojObjekt


Programiranje 1 VS Informatika

C# . NET

203

MojObjekt

x = new MojObjekt();

lahko dostopa do javnaLastnost

x.javnaLastnost

private private
Do lastnosti ne more dostopati nihe, razen
metod znotraj razreda Ko piemo nart razreda this.lastnost lastnost private int privatnaLastnost;
razredu MojObjekt

// v

e kdo naredi objekt vrste MojObjekt


MojObjekt x = new MojObjekt(); Pri poskusu dostopa do privatnaLastnost x.privatnaLastnost Prevajalnik javi napako

Programiranje 1 VS Informatika

C# . NET

204

Razred Zajec
public class Zajec { public string serijska; // serijska stevilka zajca public bool spol; // true = moski, false = zenska

private double masa; // masa zajca ob zadnjem pregledu

Razred Zajec2
public class Zajec2 { public string serijska; // serijska stevilka zajca public bool spol; // true = moski, false = zenska

private

double masa; // masa zajca ob zadnjem pregledu

public SpremeniTezo(double x) { this.masa = x; }

Dostop do stanj/lastnost
Kako uporabiti:

Metode za dostop do stanj "get" metode Metode za nastavljanje stanj "set" metode

Zakaj je bolji dostop preko metod kot neposredno



Monost kontrole pravilnosti! Monost kasneje spremembe naina predstavitve (hranjenja podatkov)

Programiranje 1 VS Informatika

C# . NET

205

Dostop do stanj/lastnost
Zakaj je bolji dostop preko metod kot neposredno

Monost oblikovanja pogleda na podatke Podatke uporabniku posredujemo drugae, kot jih hranimo (datum interno je mesec tevilo (1, 2, ...), "navzven" kot ime ("januar", "februar" ...) Dostop do doloenih lastnosti lahko omejimo Npr. spol lahko nastavimo le, ko naredimo objekt (kasneje ne, saj se ne spreminja ... e odmislimo kakne operacije, doloene vrste ivali ... seveda.) Hranimo lahko tudi doloene podatke, ki jih uporabnik sploh ne potrebuje ..

Nastavitve stanj/podatkov

Nastavitve stanj prireditveni stavek zajcek.SpremeniTezo(2.5); V bistvu isto kot zajcek.masa = 2.5; A metoda spremeniTezo lahko PREVERI, e je taka sprememba tee
smiselna!

zajcek.SpremeniTezo(-12.5); V bistvu isto kot zajcek.masa = -12.5; A tu bomo lahko PREPREILI postavitev lastnosti objekta v napano stanje!

Programiranje 1 VS Informatika

C# . NET

206

Razred Zajec - SpremeniTezo


public void SpremeniTezo(double novaTeza) { // smislena nova teza je le med 0 in 10 kg if ((0 < novaTeza) && (novaTeza <= 10)) this.masa = novaTeza; // v nasprotnem primeru NE spremenimo tee }

public bool SpremeniTezo(double novaTeza) { // smislena nova teza je le med 0 in 10 kg if ((0 < novaTeza) && (novaTeza <= 10)){ this.masa = novaTeza; return true; // sprememba uspela } // v nasprotnem primeru NE spremenimo tee // in javimo, da spremembe nismo naredili return false; }

SpremeniTezo

Imamo lahko OBE metodi?

NE Imata enak podpis (ime + tipi parametrov) Tip rezultata NI del podpisa!

Metoda je seveda lahko bolj kompleksna denimo vemo, da se tea ne more spremeniti bolj kot za 15%

Programiranje 1 VS Informatika

C# . NET

207

public bool SpremeniTezo(double novaTeza) { // smislena nova teza je le med 0 in 10 kg // in e ni ve kot 15% spremembe od zadnji int sprememba = (int)(0.5 + (100 * Math.abs(this.masa novaTeza) / this.masa);

if ((0 < novaTeza) && (novaTeza <= 10) && (sprememba <= 15) ){ masa = novaTeza; // this.masa ... Lahko pa this spustimo! return true; // sprememba uspela } // v nasprotnem primeru NE spremenimo tee // in javimo, da spremembe nismo naredili return false; }

Tea in konstruktor

Seveda je smiselno, da zagotovimo, da je tea ustrezna e ves as! Pozor na zaetno stanje: konstruktor!

Tudi v konstruktorju preverimo, e se uporabnik "obnaa lepo" Zajec neki = new Zajec("X532", true, 105); 105 kilogramskega zajca verjetno ni, a uporabnik je pozabil na decimalno piko v 1.05 Zato je kontrola smiselnosti podatkov potrebna tudi v konstruktorjih!

Pogosto na to pozabimo

Programiranje 1 VS Informatika

C# . NET

208

SpremeniSpol, SpremeniSerijsko
Kaj pa SpremeniSpol

e niste v kakni udni industriji ali razvoju, je ta metoda odve ;-))

Morda tudi metoda

SpremeniSerijsko

Pozor na konstruktor brez parametrov Serijska je "NEDOLOENO"

Metoda SpremeniSerijsko naj pusti spreminjati le take serijske tevilke!

public bool SpremeniSerijsko(string seStev) { // sprememba dopustna le, e serijske tev. ni if (this.serijska.Equals("NEDLOENO")) { this.serijska = seStev; return true; } return false; // ne smemo spremniti e obstojee! }

Dostop do stanj Poizvedba



spremenljivka v izrazu

zajcek.PovejTezo()
Da bomo lahko izvedeli teo zajca Najenostavneje v telesu metode le return this.masa; Lahko stvar "oblikujemo" recimo, da bomo uporabniku vedno povedali le teo na pol kilograma, mi pa bomo interno stvar vodili natanneje

Programiranje 1 VS Informatika

C# . NET

209

Razred Zajec - povejTezo


public double PovejTezo() { return this.masa; // ali return masa }

Ali pa prilagodimo podatke

Teo povemo na 0.5 kg natanno 2.721 2.5, 2.905 2.502 ... 3, 2.5, Vzamemo teo v celih kg in pogledamo prvo decimalko decimalnega dela e je med 3 in 7, pritejemo k celim kg 0.5 e je ve kot 7, pritejemo k celim kg 1.0

Programiranje 1 VS Informatika

C# . NET

210

public double PovejTezo() { // teo bomo povedali le na 0.5 kg natanno int tezaKg = (int)this.masa; int decim = (int)((this.masa tezaKg) * 10); if (decim < 3) return tezaKg + 0.0; if (decim < 8) return tezaKg + 0.5; return tezaKg + 1.0; }

Celotni razred Zajec - 1


public class Zajec { private string serijska; private bool spol; private double masa;

// konstruktor public Zajec() { this.spol = true; // vsem zajcem na zaetku doloimo m. spol this.masa = 1.0; // in tehtajo 1kg this.serijska = "NEDOLOENO"; } public Zajec(string serijskaStev):this() { this.serijska = serijskaStev; } public Zajec(string serijskaStev, bool spol, double masa):this() { this.serijska = serijskaStev; this.SpremeniTezo(masa);
// uporabimo metodo za sprem.

Programiranje 1 VS Informatika

C# . NET

211

this.spol = spol; }

Celotni razred Zajec - 2


public double PovejTezo() { // teo bomo povedali le na 0.5 kg natanno int tezaKg = (int)this.masa; int decim = (int)((this.masa tezaKg) * 10); if (decim < 3) return tezaKg + 0.0; if (decim < 8) return tezaKg + 0.5; return tezaKg + 1.0; }

public bool SpremeniTezo(double novaTeza) { // smislena nova teza je le med 0 in 10 kg if ((0 < novaTeza) && (novaTeza <= 10)){ masa = novaTeza; // this.masa ... Lahko pa this spustimo! return true; // sprememba uspela } // v nasprotnem primeru NE spremenimo tee // in javimo, da spremembe nismo naredili return false; }

Celotni razred Zajec - 3


public string PovejSerijsko() { return this.serijska;
Programiranje 1 VS Informatika

C# . NET

212

} public void SpremeniSerijsko(string s) { this.serijska = s; } public bool JeSamec() { return this.spol; }

// ker se spol naknadno NE spremeni, metode za // spreminjanje spola sploh ne ponudimo uporabniku!

} // Zajec

Uporaba razreda Zajec


public class ZajnikNov { public static void Main(string[] ar) { Zajec z1 = new Zajec("1238-12-0", false, 0.12); if (z1.SpremeniTezo(z1.PovejTezo() + 0.3)) Console.WriteLine("Tea je spremenjena na " + z1.PovejTezo()); else Console.WriteLine("Tea je nespremenjena!" + " Prirastek je prevelik! Preveri!"); Console.WriteLine("Zajec ima ser. t.:" + z1.PovejSerijsko()); } }

Ostale metode

Poleg get/set metod in konstruktorjev Metode Programiranje 1 VS Informatika

C# . NET

213

Odzivi objektov "znanje objektov" Znajo povedati, kje se v njih zane nek podniz:

Objekti tipa string

"niz".IndexOf("i") nekNiz.ToLower() mojPriimek.Equals("Lokar")

Znajo vrniti spremeniti rke v male in vrniti nov niz: Znajo povedati, e so enaki nekemu drugemu nizu:

"nai" razredi

Sprogramiramo znanje ustrezne metode

Zajec bo znal povedati svojo vrednost, e mu povemo ceno za kg ive tee

Programiranje 1 VS Informatika

C# . NET

214

Razred Zajec dodatne metode


public double Vrednost(double cenaZaKg) {
// pove vrednost zajca // zajce tehtamo na dogovorjeno natannost

return cenaZaKg * this.PovejTezo(); } public bool MeNapojiti() {


// ugotovimo, e ga je smiselno // napojiti, da bomo "ujeli" naslednjih pol kg // dejanska tea je veja od "izmerjene" return (this.masa this.PovejTezo() > 0); }

Metoda ToString
Poglejmo si naslednji program:
using System; using MojaKniznica;

namespace Izpis { class Program { public static void Main(string[] args) { Zajec zeko = new Zajec(); Console.WriteLine("To je zajec: " + zeko);

Programiranje 1 VS Informatika

C# . NET

215

Console.Write("Press any key to continue . . . "); Console.ReadKey(true); } } }

ToString

Oitno objekte lahko tudi izpiemo Gre seveda tudi takole string niz = "Zajec " + zeko + "!"; Torej se tudi objekti "obnaajo" tako kot int, double ... (se torej pretvorijo v niz) A s pretvorbo nismo ravno zadovoljni, radi bi kakne bolj smiselne informacije V razredu, ki ga definiramo (recimo Zajec) napiemo metodo ToString e na doloenem mestu potrebujemo niz, a naletimo na objekt, se ta metoda poklie avtomatino

string niz = "Zajec " + zeko.ToString() + "!";

Programiranje 1 VS Informatika

C# . NET

216

Metoda ToString
Isti program, a tako, da je v razredu Zajec metoda ToString:
using System; using MojaKniznica;

namespace Izpis { class Program { public static void Main(string[] args) { Zajec zeko = new Zajec(); Console.WriteLine("To je zajec: " + zeko);

Console.Write("Press any key to continue . . . "); Console.ReadKey(true); } } }

ToString

V razred Zajec smo napisali


public override string ToString() { return "Zajec: " + this.PovejSerijsko(); }

Posebnost - override
Programiranje 1 VS Informatika

C# . NET

217

Zaradi "dedovanja"

O tem kasneje Z dedovanjem smo avtomatino pridobili metodo ToString (zato je vedno na voljo) Zato override, da "povozimo " podedovano metodo

ToString in Opis

Razlika med
public override string ToString() { return "Zajec: " + this.PovejSerijsko() ; }

in
public string Opis() { return "Zajec: " + this.PovejSerijsko() ; }

Metodo Opis moramo poklicati sami, metoda ToString se klie avtomatsko (e je potrebno)

string niz1 = "Zajec " + zeko.ToString() + "!"; string niz2 = "Zajec " + zeko + "!"; string niz3 = "Zajec " + zeko.Opis() + "!";

Vsi trije niz enaki! ToString obstaja, tudi, e jo ne napiemo (a verjetno z vrnjenim nizom nismo najbolj zadovoljni)

Tudi objekti so lahko del razreda



Ko sestavljamo razred, kot objektne spremenljivke lahko uporabimo tudi spremenljivke istega razreda Npr.: starsi Zajca
Programiranje 1 VS Informatika

C# . NET

218

Razred Clan

public class Clan {

private string ime; private Clan gaJePriporocil; ...

e malo o zajcih

Preden nadaljujemo

elimo hraniti tudi stare zajca

public class Zajec { private double masa; private string serijska; private bool spol; private Zajec oce; private zajec mati;

e konstruktor

Problemi s konstruktorjem

Sestavimo privzeti konstruktor

Programiranje 1 VS Informatika

C# . NET

219

public Zajec() { this.spol = true; this.masa = 1.0; this.serijska = "NEDOLOENO"; this.oce = new Zajec(); this.mama = new Zajec(); }

Ko stvar prevedemo, je vse v redu. A ob poskusu

Zajec rjavko = new Zajec();

Problemi s konstruktorjem

Rekurzija brez ustavitve Tudi konstruktor je metoda

Ustavitveni pogoj A pri konstruktorju brez parametrov ni parametrov, ki bi lahko doloili ustavitveni pogoj

Kaj storiti

"Privzeti" zajec ne pozna starev oce = null; mama = null; e malo pomislimo ko zajca "naredimo", morata stara e
Programiranje 1 VS Informatika

C# . NET

220

obstajati

Ju nima smisla ustvarjati na novo

Razred Avto
Sprogramirajte razred Avto, ki predstavlja avtomobil z njegovimi tehninimi znailnostmi in trenutnim stanjem. Razred naj vsebuje sledee attribute: Poleg atributa stevilka, ki omogoa loevanje posameznih avtomobilov, so tehnine znailnosti opisane z atributi najvecjaHitrost (v km/h), velikostRezervoarja (v litrih) in povprenaPoraba (v litrih/100 km). Trenutno stanje avtomobila predstavljajo atributi avtoVzgan (tipa boolean), stevecKm (npr. 234.142 km), trenutnaHitrost (npr. 56.12 km/h) in kolicinaGoriva (npr. 14.325 litrov). Razred naj vsebuje naslednje metode: NastaviStevilko(s): nastavi atribut stevilka na s (recimo 1), NastaviNajvecjoHitrost(h): nastavi atribut najvecjaHitrost na h km/h (recimo 180), NastaviVelRezervoar(l): nastavi atribut velikostRezervoarja na l litrov (recimo 48.0), NastaviPovPorabo(l): nastavi atribut povprecnaPoraba na l litrov/100 km (recimo 7.5), NapolniGorivo(): nastavi atribut kolicinaGoriva na vrednost velikostRezervoarja, VzgiAvto(): nastavi atribut avtoVzgan na true, pri emer se porabi 0.05 litra goriva (e ni zadosti goriva se avto ne vge) UgasniAvto(): nastavi atribut avtoVzgan na false, pri emer se lahko avto ugasne le, ko je njegova hitrost enaka 0. Vozi(t): vozi t minut s trenutno hitrostjo in vrne koliko poti je v tem asu prevozil. Metoda povzroi spremembo atributov stevecKm in kolicinaGoriva. e je goriva premalo, naj vonja poteka tako dolgo, dokler ne zmanjka goriva. Avto lahko vozi le v primeru, da je vgan (atribut avtoVzgan nastavljen na true) in ima trenutno hitrost vejo kot 0. SpremeniHitrost(h): spremeni trenutnaHitrost na vrednost h km/h. Hitrost avtomobila je med 0 in najvecjaHitrost. Ustavi(): spremeni trenutnaHitrost na vrednost 0 km/h. NajvecjiCas(): metoda vrne podatek, koliko minut in sekund lahko e vozimo glede na trenutno koliino goriva. Trenutno stanje avtomobila se ne spremeni.

Programiranje 1 VS Informatika

C# . NET

221

Doseg(l): metoda vrne podatek, koliko kilometrov lahko prevozimo z najvejo hitrostjo, e je v rezervoarju e l litrov goriva. Trenutno stanje avtomobila se ne spremeni.

CasVoznje(d): metoda nam pove vrne koliko asa (v minutah in sekundah) potrebujemo, da prevozimo d kilometrov, e vozimo z nespremenjeno hitrostjo, v rezervoarju pa imamo trenutno koliino goriva. Pri tem je treba upotevati, da koliina goriva lahko tudi ne zadoa; v tem primeru bo treba ustaviti, ugasniti avtomobil, napolniti rezervoar, ga znova prigati in odpeljati naprej, kar nam vzame dodatnih 15 minut. Trenutno stanje avtomobila naj se sicer ne spremeni.

PotovalnaHitrost(d,t): metoda vrne hitrost, s katero naj avto vozi, da bi d km oddaljen kraj dosegel v t minutah. Pri tem naj upoteva tudi eventuelna polnjenja rezervoarja, ki vzamejo dodatnih 15 minut. Trenutno stanje avtomobila se ne spremeni.

Boljsi(a): primerja trenutni avtomobil z avtomobilom a in izpie stevilko boljega avtomobila. Bolji je tisti avtomobil, ki v krajem asu prevozi 1000 km, pri emer upotevajte tudi as polnjenja goriva.

Izpis(): izpie vse atribute avtomobila.

Pri vseh metodah predpostavljamo, da avto pri vseh hitrostih porabi enako koliino goriva. Za generiranje avtomobilov sprogramirajte tri konstruktorje: prvi naj bo brez parametrov in zgenerira avtomobil, ki ima vse atribute prazne (vrednost 0 ali false) drugi naj ima le parameter s in naj zgenerira avtomobil s tevilko s, ostale vrednosti pa naj bodo prazne. tretji naj ima parametre s, h, v in p, zgenerira pa naj avtomobil tevilke s, z najvejo hitrostjo h, velikostjo rezervoarja v in povpreno porabo p. Atributi stevecKm, trenutnaHitrost in kolicinaGoriva naj imajo vrednost 0, avtoVzgan pa na false.

Testiranje razreda
Za testiranje razreda Avto napiite razred TestAvto. Z uporabo vsakega konstruktorja definirajte po en avto. S pomojo metod za nastavljanje atributov dopolnite podatke za prva dva avtomobila, nato pa izpiite vse podatke o vseh avtomobilih. Z vsemi simulirajte polnjenje goriva, vonjo, spreminjanje hitrosti in vse informativne izpise. Ponovno izpiite vse avtomobile ter jih primerjajte med seboj.

OOP v C++ (avtor dr. M. Krana) 2. Razmiljanje "po objektno"


Zadnjih nekaj let objektno programiranje in objektno usmerjena (objected oriented) tehnologija predstavlja precejen bum. Kar je v sedemdesetih letih pomenilo strukturirano programiranje, v sedanjem asu pripada temu pristopu. al je bilo na zaetku prav tako tudi podroje mnogih napanih interpretacij. Razlini ljudje so razlino

Programiranje 1 VS Informatika

C# . NET

222

interpretirali posamezne podrobnosti tega pristopa in hitro je prilo do napanih razlag kaj je objekt, kaj razred, kaj metode, ipd. Kljuna pojma taknega pristopa v programiranju sta objekt in razred. Kako to dvoje poveemo v delujoe programe predstavlja mnogim na zaetku zaradi nekoliko druganega razmiljanja teavo. e pogledamo naokoli (pa naj bo kar raunalnika uilnica, kjer potekajo oz. so potekale vaje), lahko vidimo ve objektov. Pred vami je va delovni raunalnik, torej objekt. Raunalnik med drugim vsebuje miko in tipkovnico, torej dva objekta. Tipkovnica je sestavljena iz mnoice tipk, torej mnoice objektov. Ko ste na vajah, sedite na stolu, torej sedite na objektu. Na vsako konkretno zadevo, na vsak predmet, na vsako bitje lahko gledamo, kakor da je objekt. Skupna znailnost vsem tem objektom je, da imajo: stanje (ang. state), in obnaanje oz. vedenje (ang. behaviour). Stanje je bolj iroko gledan pojem (prevod besede v slovenino zagotovo ni najbolj primeren) in lahko za raunalnik recimo predstavlja mo njegovega procesorja, koliino RAM pomnilnika, kapaciteto diska, hitrost CD (DVD) enote, tevilo USB prikljukov, stanje ali je raunalnik prigan ali ugasnjen, seznam prikljuenih enot nanj, kot recimo ali je prikljuen tiskalnik, ipd. Obnaanje raunalnika na drugi strani je recimo formatiranje diska, zapisovanje datoteke na disk, tiskanje dokumenta, priiganje raunalnika (ali pa da ga ugasnemo), da zbriemo datoteko na disku, da mu poveamo kapaciteto pomnilnika ipd. Poenostavljeno gledano je torej, da imamo na eni strani statine lastnosti in na drugi dinamine oz. spremenljive. preprosto pravilo oz. recept: stanje je predstavljeno s spremenljivkami, obnaanje pa z metodami (funkcije in procedure). Za raunalnik bi lahko recimo imeli naslednjo tabelo stanje: - hitrost procesorja - koliina RAM pomnilnika - kapaciteta diska - hitrost CD enote - tevilo USB prikljukov - prigan ali ugasnjen raunalnik - prikljuen tiskalnik obnaanje: - zapis datoteke na disk - tiskanje dokumenta - priiganje raunalnika - ugaanje raunalnika - brisanje datoteke na disku
Programiranje 1 VS Informatika

C# . NET

223

- formatiranje diska - poveanje kapacitete RAM-a kar pretvorimo v spremenljivke in metode. Za spremenljivke izberemo smiselne tipe spremenljivk, kar bi za primer z raunalnikom recimo lahko bilo: stanje:
int HitrostProcesorja; // hitrost procesorja v megahercih int KolicinaPomnilnika; // koliina RAM pomnilnika v megabajtih int KapacitetaDiska; // kapaciteta diska v megabajtih int HitrostCDEnote; // hitrost enote v faktorjih pisanja (52x, ...) int SteviloUSBPrikljuckov; // tevilo USB prikljukov bool Prizgan; // true, e je raunalnik prigan, sicer false bool PrikljucenTiskalnik; // true, e je prikljuen tisk., sicer false

Stanje je torej smiselno zapisano s spremenljivkami. V tem preprostem primeru so sedaj le cela tevila in dvakrat logina vrednost, lahko pa je stanje opisano tudi mnogo kompleksneje (realna tevila, polja, nizi, kazalci, datoteke, ipd.), kot bo kasneje v primerih iz pisnih izpitov. Nekoliko ve dela je pri obnaanju. Za vsako postavko iz seznama obnaanja si moramo smiselno zamisliti ali bomo uporabili funkcijo ali proceduro, prav tako pa tudi ali je morda to specifino obnaanje odvisno od kaknih sekundarnih faktorjev (npr. katero datoteko bomo natisnili ali zbrisali, na kateri tiskalnik bomo natisnili dokument, ipd.), kar predstavimo s parametri metod. Dobra izbira metod je kljunega pomena, vekrat pa se izkae, da je na tej stopnji potrebno spremeniti spremenljivke, ki predstavljajo stanje, ker si stanje nismo recimo dovolj dobro zamislili. Na primeru raunalnika poglejmo, kako si lahko zamislimo metode (kar ne velja za primere, kadar vam nekdo vnaprej predpie metode, kot bo na pisnih izpitih) za enostaven primer (nekaj postavk pri obnaanju iz zgornje tabele bo namenoma izpuenih). Recimo, da bi obnaanje raunalnika ponazorili s temi metodami: obnaanje:
void ZapisiDatoteko(ImeDatoteke); // zapie datoteko na disk void NatisniDokument(ImeDokumenta); // natisni dokument na tiskalnik void PrizgiRacunalnik(); // priiganje raunalnika void UgasniRacunalnik(); // ugasni raunalnik void BrisiDatoteko(ImeDatoteke); // brisanje datoteke z diska

Zakaj na primer procedura za ugaanje raunalnika? Kaj v tej proceduri sploh naredimo? Bi bila morda funkcija bolj primerna? Potrebujemo kakno povratno informacijo, ko ugasnemo raunalnik? Kakna je stanje raunalnika pred to metodo in kakno potem oziroma kakna je razlika stanja? Na ta in podobna vpraanja moramo pomisliti, da si lahko kvalitetno zamislimo implementacijo vseh metod za obnaanje. Pri izbiri stanja smo si zamislili, da bomo s spremenljivko Prizgan oznaili ali je raunalnik prigan ali ne. Ima torej vrednost true, e je prigan in false, e je ugasnjen zaradi esar imamo pri metodi dve monosti: bodisi bomo ugasnili raunalnik, ki je prigan ali pa bomo eleli ugasniti raunalnik, ki je e ugasnjen. Ne glede na ti dve monosti pa vemo, da ko bomo to metodo izvedli, bo
Programiranje 1 VS Informatika

C# . NET

224

raunalnik ugasnjen, torej spremenljivka Prizgan bo imela vrednost false. To je hkrati tudi morebitna sprememba stanja pri tej metodi. In ker natanno vemo, da bo po tej metodi raunalnik ugasnjen, ne potrebujemo nobene povratne informacije, zaradi esar lahko to metodo implementiramo kot proceduro. Celotno obnaanje raunalnika je za ta zgornji primer zamiljeno s procedurami. Za preprosti primer je to morda dovolj dobro, za realneje primere pa je vasih zaeljeno ve informacije. Na primer, ko bomo izvedli tiskanje dokumenta (torej, ko bomo v programu poklicali metodo NatisniDokument), ne vemo ali je dokument sploh mono natisniti ali ne. Z drugimi besedami, ali je na raunalnik sploh prikljuen tiskalnik ali ne in ali je raunalnik sploh prigan? Obnaanje metode za tiskanje dokumentov bi tako lahko bilo "bolje", e bi metoda recimo vrnila true, e je bilo tiskanje mono, oziroma false, e tiskanje ni bilo mono, ker na raunalnik ni prikljuen tiskalnik ali pa ker raunalnik ni prigan. Metodo
void NatisniDokument(ImeDokumenta); // natisni dokument na tiskalnik

bi lahko torej bolj primerno zapisali kot


bool NatisniDokument(ImeDokumenta); // natisni dokument na tiskalnik

Prav tako bi recimo lahko izboljali metodo za priiganje (in tudi za ugaanje) raunalnika. Ne glede na to, da vemo da bo po izvedeni metodi raunalnik ugasnjen, bi nas morda vseeno lahko zanimalo ali smo raunalnik zares ugasnili ali pa je e bil ugasnjen. Torej, e smo ga zares ugasnili, bi vrnili za povratno infomracijo true, e pa je e bil ugasnjen, pa false. Tako bi sedaj metodo
void PrizgiRacunalnik(); // prigi raunalnik

lahko bolj primerno zapisali kot


bool PrizgiRacunalnik(); // prigi raunalnik

V splonem se lahko ravnamo po tem naelu: bolje ve povratne informacije, kakor premalo, e bomo povratno informacijo sploh uporabili, je pa stvar programerja. Preden to zapiemo v programskem jeziku C++, e na hitro razlaga pojma razred. Kar je bilo do sedaj navedeno je bilo zapisano, kako bi opisali nek konkreten objekt in to imenujemo razred - zapiemo torej splone zadeve (stanje in obnaanje), nikjer pa dejansko e ne doloimo vrednosti. Ko pa so enkrat doloene vrednosti tem spremenljivkam, na primer da imamo raunalnik s hitrostjo 2GHz, 512MB pomnilnika, 80GB disk, ipd., potem govorimo o konkretnem primerku razreda, t.j. o objektu (v slovenski literaturi najdemo tudi "primerek" in "instanca"). V C++ bi zgoraj podani primer zapisali kot sledi v nadaljevanju: definirali bomo razred, njegovo stanje in obnaanje, s tem razredom bomo pa hkrati definirali nov tip spremenljivke (enak imenu razreda). Dogovorimo se, da bomo razrede poimenovali vedno z zaetno veliko rko C kot dodatno oznako, da gre za razred (ang. class) in na razred o raunalniku torej kot CRacunalnik. Po vzoru delovanja programskega paketa iz vaj, bo definicija razreda zapisana v dveh datotekah. V datoteki Racunalnik.h je podana
Programiranje 1 VS Informatika

C# . NET

225

osnovna definicija razreda, v datoteki Racunalnik.cpp pa dejanska izvedba (koda) posameznih metod. Racunalnik.h:
class CRacunalnik { // stanje int HitrostProcesorja; // hitrost procesorja v megahercih int KolicinaPomnilnika; // koliina RAM pomnilnika v megabajtih int KapacitetaDiska; // kapaciteta diska v megabajtih int HitrostCDEnote; // hitrost enote v faktorjih pisanja (52x, ...) int SteviloUSBPrikljuckov; // tevilo USB prikljukov bool Prizgan; // true, e je raunalnik prigan, sicer false bool PrikljucenTiskalnik; // true, e je prikljuen tisk., sicer false // obnasanje void ZapisiDatoteko(char* ImeDatoteke); // zapie datoteko na disk bool NatisniDokument(char* ImeDokumenta); // natisni dokument na tiskalnik bool PrizgiRacunalnik(); // priiganje raunalnika void UgasniRacunalnik(); // ugasni raunalnik void BrisiDatoteko(char* ImeDatoteke); // brisanje datoteke z diska };

V *.h datoteki je podan seznam spremeljivk stanja in seznam metod za obnaanje, vendar brez dejanske kode kaj se v teh metodah zares zgodi. To sledi v naslednji datoteki s konnico *.cpp v kateri mora seznam metod ustrezati seznamu metod datoteki *.h. Vsaki metodi je dodan zapis kateremu razredu pripada (tukaj CRacunalnik::). Racunalnik.cpp:
void CRacunalnik::ZapisiDatoteko(char* ImeDatoteke) { // koda te metode... } bool CRacunalnik::NatisniDokument(char* ImeDokumenta) { if (PrikljucenTiskalnik == true && Prizgan == true) return(true); else return(false); } bool CRacunalnik::PrizgiRacunalnik() { if (Prizgan == false) // ce je ugasnjen, ga prizge Prizgan = true; return(true); } return(false); // sicer vrne false, Prizgan pa je ze true } void CRacunalnik::UgasniRacunalnik() { if (Prizgan == true) // ce je prizgan, ga ugasne Prizgan = false; } void CRacunalnik::BrisiDatoteko(char* ImeDatoteke) { // koda te metode... }

V metodah se lahko uporabljajo spremenljivke razreda imenovane tudi razredne spremenljivke (kot sta na primer spremenljivki PrikljucenTiskalnik in Prizgan v zgornjem primeru), lokalne spremenljivke ali pa spremenljivke, podane kot parameter metode. Podan primer obnaanja in metode pa niso vse, kar se definira v razredu oz. kar se lahko potem dejansko pone z dejanskim objektom. Med obnaanje spadajo: - akcije, - povpraevanje po stanju, - spreminjanje stanja in
Programiranje 1 VS Informatika

C# . NET

226

- konstruktor ter destruktor. Primer akcije je na primer, da smo ugasnili ali pa prigali raunalnik. Povpraevanje po stanju bi recimo predstavljal primer naslednje metode:
int CRacunalnik::DajHitrostProcesorja() { return(HitrostProcesorja); }

Podobno bi lahko bilo za spreminjanje stanja (direktno ali indirektno) na primer metoda
void CRacunalnik::NastaviHitrostProcesorja(int NovaHitrost) { HitrostProcesorja = NovaHitrost; }

ali pa poveanje kapacitete RAM pomnilnika z metodo


void PovecajKapacitetoRAMaZa(int Koliko);// poveanje RAM pomnilnika
KolicinaPomnilnika += Koliko; }

e bi bila zamiljena kot procedura, e pa bi si jo zamislili kot funkcijo, ki kot rezultat vrne novo koliino pomnilnika, bi imeli:
int PovecajKapacitetoRAMaZa(int Koliko);// poveanje RAM pomnilnika
KolicinaPomnilnika += Koliko; return(KolicinaPomnilnika); }

"Spreminjanje stanja" je lahko torej neposredno, kot v teh dveh metodah ali pa posredno v drugih metodah (kot je na primer pri priiganju raunalnika). Posebni metodi sta pa konstruktor in destruktor in imata imeni, enaki razredu. Medtem, ko je konstruktor namenjen inicializaciji objekta, je destruktor namenjen pokonanju objekta in "ienju" dinamino dodeljenega prostora v asu delovanja objekta. Konstruktor se avtomatsko poklie, ko se rezervira prostor za objekt v pomnilniku, destruktor pa ko se unii. Namen konstruktorja je tako, da doloimo vrednosti razrednim spremenljivkam (ne nujno vsem, ampak kar pa potrebujemo). Loimo osnovni konstruktor (brez kakrnih parametrov) in dodatne konstruktorje. Medtem, ko je destruktor en sam, je lahko konstruktorjev mnogo, le razlikovati se morajo med seboj v parametrih, ki jih sprejmejo. Primer osnovnega konstrukturja za raunalnik bi recimo bil naslednji:
CRacunalnik::CRacunalnik() { HitrostProcesorja = 2000; KolicinaPomnilnika = 512; Prizgan = false; TiskalnikPrikljucen = true; }

Iz zapisa je razvidno, da je ime metode, ki predstavlja konstruktor enako imenu razreda, ta konstruktor pa se poklie avtomatsko, ko kreiramo objekt brez dodatnih parametrov. V pomnilniku se takrat ustvari prostor za spremenljivko tipa CRacunalnik, ki ima e doloene vrednosti spremenljivk HitrostProcesorja (2000), KolicinaPomnilnika (512), Prizgan (false) in TiskalnikPrikljucen (true).
Programiranje 1 VS Informatika

C# . NET

227

Te vrednosti se torej doloijo avtomatsko in nanje ne moremo vplivati. Lahko pa poskrbimo, da pri kreiranju objekta vplivamo na doloene vrednosti razrednih spremenljivk in spremenljivke in tiste, na katere elimo vplivati, natejemo kot parametre konstruktorja (torej parametre metode). Dva dodatna konstruktorja bi recimo bila:
CRacunalnik::CRacunalnik(int HitProc) { // parameter konstruktorja je hitrost procesorja HitrostProcesorja = HitProc; KolicinaPomnilnika = 512; Prizgan = false; TiskalnikPrikljucen = true; } CRacunalnik::CRacunalnik(int HitProc, int KolPom) { // parameter konstruktorja je hitrost procesorja in koliina pomnilnika HitrostProcesorja = HitProc; KolicinaPomnilnika = KolPom; Prizgan = false; TiskalnikPrikljucen = true; }

Paziti moramo, da se metode med seboj razlikujejo po tipih parametrov, ki jih prejmejo. Metoda
void ime_metode(int Parameter1)

je drugana metodi
void ime_metode(double Parameter1)

medtem, ko metoda
void ime_metode(int Parameter2)

predstavlja teavo, ker prevajalnik ne bo znal loiti med njima (med prvo in tretjo metodo); obakrat namre gre za enak seznam parametrov (imena spremenljivk niso pomembna, le tipi). Temu, da lahko uporabljamo ista imena za metode, v katerih se pa razlikuje seznam parametrov imenujemo preobloene metode (ang. overloading). Po definiciji konstruktor ne vraa vrednosti. Na drugi strani se destruktor avtomatsko poklie ob sproanju prostora v pomnilniku - ob unienju objekta. Ime je enako razredu, le da pred njim zapiemo znak ~ (tilda). Destruktor nima parametrov in prav tako ne vraa nobene vrednosti. Za na primer bo tako zelo preprost, da ne bo niti vseboval kode, v kolikor bi pa imeli v razrednih spremenljivkah na primer kakna dinamina polja in bi jih tekom uporabe objekta kreirali z new, v destruktorju poskrbimo (e nismo e morda prej), da ta dinamina polja odstranimo iz pomnilnika (stavke z delete prestavite torej v destruktor).
CRacunalnik::~CRacunalnik() { }

Vsi konstruktorji in destruktorji morajo biti nateti tudi v datoteki s konnico *.h (v seznamu metod)!
Prizgan = false; TiskalnikPrikljucen = true; } CRacunalnik::CRacunalnik(int HitProc, int KolPom) { // parameter konstruktorja je hitrost procesorja in koliina pomnilnika HitrostProcesorja = HitProc; KolicinaPomnilnika = KolPom;

Programiranje 1 VS Informatika

C# . NET

228

Prizgan = false; TiskalnikPrikljucen = true; }

Paziti moramo, da se metode med seboj razlikujejo po tipih parametrov, ki jih prejmejo. Metoda
void ime_metode(int Parameter1)

je drugana metodi
void ime_metode(double Parameter1)

medtem, ko metoda
void ime_metode(int Parameter2)

predstavlja teavo, ker prevajalnik ne bo znal loiti med njima (med prvo in tretjo metodo); obakrat namre gre za enak seznam parametrov (imena spremenljivk niso pomembna, le tipi). Temu, da lahko uporabljamo ista imena za metode, v katerih se pa razlikuje seznam parametrov imenujemo preobloene metode (ang. overloading). Po definiciji konstruktor ne vraa vrednosti. Na drugi strani se destruktor avtomatsko poklie ob sproanju prostora v pomnilniku - ob unienju objekta. Ime je enako razredu, le da pred njim zapiemo znak ~ (tilda). Destruktor nima parametrov in prav tako ne vraa nobene vrednosti. Za na primer bo tako zelo preprost, da ne bo niti vseboval kode, v kolikor bi pa imeli v razrednih spremenljivkah na primer kakna dinamina polja in bi jih tekom uporabe objekta kreirali z new, v destruktorju poskrbimo (e nismo e morda prej), da ta dinamina polja odstranimo iz pomnilnika (stavke z delete prestavite torej v destruktor).
CRacunalnik::~CRacunalnik() { }

Vsi konstruktorji in destruktorji morajo biti nateti tudi v datoteki s konnico *.h (v seznamu metod)!

2.1. Javnost/privatnost (enkapsulacija)


Ko enkrat doloimo kaj so razredne spremenljivke in kaj metode, se odloamo e o temu, kakno naj bo skrivanje elementov razreda oziroma kaj je javnega in kaj privatnega znaaja. Nekatere spremenljivke ali metode namre elimo, da se lahko uporabljajo samo znotraj metod in na tono doloenih mestih, ne pa popolnoma poljubno. Recimo da bi na razred o raunalniku dodatno poglobili v metodi, kjer prigemo raunalnik in sicer, da bi metoda izgledala nekako takole:
bool CRacunalnik::PrizgiRacunalnik() { if (Prizgan == false) // ce je ugasnjen, ga prizge VklopiNapajalnik(); ResetirajMaticnoPlosco(); PreberiPodatkeIzBIOSa(); InicializirajVgrajeneKartice(); Prizgan = true; return(true); } return(false); // sicer vrne false, Prizgan pa je ze true }

V metodi bi torej, e bi zares prigali raunalnik, poklicali e tiri metode (VklopiNapajalnik, ResetirajMaticnoPlosco, PreberiPodatkeIzBIOSa in
Programiranje 1 VS Informatika

C# . NET

229

InicializirajVgrajeneKartice), ki pa imajo popolnoma privaten znaaj. Z drugimi besedami: e bodo te metode e kdaj poklicane, elimo da se to zgodi samo v tem primeru, ne pa tudi recimo, da bi nekdo poklical metodo za resetiranje matine ploe po tiskanju dokumenta. Enako velja za spremenljivke; kar ne elimo, da bi nekdo uporabljal izven metod, doloimo da je privatnega znaaja. V C++ to (javnost in privatnost) doloimo v datoteki *.h z besedama private: in public: in vse kar je napisano na desni (in zatem), ima status ali privatnosti ali pa javnosti. Dopolnjena datoteka Racunalnik.h, v kateri je nekaj spremenljivk deklariranih kot privatnih, bi tako recimo bila:
class CRacunalnik { public: // stanje int HitrostProcesorja; // hitrost procesorja v megahercih int KolicinaPomnilnika; // koliina RAM pomnilnika v megabajtih private: int KapacitetaDiska; // kapaciteta diska v megabajtih int HitrostCDEnote; // hitrost enote v faktorjih pisanja (52x, ...) int SteviloUSBPrikljuckov; // tevilo USB prikljukov public: bool Prizgan; // true, e je raunalnik prigan, sicer false bool PrikljucenTiskalnik; // true, e je prikljuen tisk., sicer false // obnasanje void ZapisiDatoteko(char* ImeDatoteke); // zapie datoteko na disk bool NatisniDokument(char* ImeDokumenta); // natisni dokument na tiskalnik bool PrizgiRacunalnik(); // priiganje raunalnika void UgasniRacunalnik(); // ugasni raunalnik void BrisiDatoteko(char* ImeDatoteke); // brisanje datoteke z diska CRacunalnik(); // osnovni konstruktor CRacunalnik(int HitPro); // dodatni konstruktor CRacunalnik(int HitPro, int KolPom); // e en dodatni konstruktor ~CRacunalnik(); // destruktor };

2.2. Uporaba razredov in objektov


Uporabljamo jih lahko statino ali dinamino, pri emer v praksi prevladuje uporaba dinaminega. Kot e reeno, razred definira nov tip spremenljivke in ga na tak nain tudi obravnavamo. Za statino uporabo imamo torej naslednji "vzorec":
CRacunalnik MojRac1; // deklaracija objekta z imenom MojRac1 MojRac1.HitrostPomnilnika = ...; // direktni dostop do javne spremenljivke MojRac1.KapacitetaDiska = ...; // to ne gre, ker je KapacitetaDiska privatna! MojRac1.PrizgiRacunalnik(); // klic javne metode

Konstruktor se avtomatsko poklie pri deklaraciji objekta in destruktor avtomatsko, ko se kona metoda v kateri je nek objekt lokalna spremenljivka ali pa ko se kona program, e je objekt globalna spremenljivka.

Programiranje 1 VS Informatika

C# . NET

230

Pri MojRac1 se uporabi osnovni konstruktor, e bi pisalo pa recimo MojRac1(1000) bi se pa avtomatsko uporabil dodatni konstruktor, ki kot parameter sprejme hitrost procesorja. Nekoliko ve pisanja (je pa zato morda celo bolj berljivo programerjem) je pri uporabi dinaminega pristopa, kjer imamo naslednji "vzorec":
CRacunalnik* MojRac2; // deklaracija objekta z imenom MojRac2 (tu se // e ne poklie noben konstruktor!) MojRac2 = new CRacunalnik(); // inicializacija preko osnovnega konstrukt. MojRac2->HitrostPomnilnika = ...;// direktni dostop do javne spremenljivke MojRac2->PrizgiRacunalnik(); // klic javne metode delete MojRac2; // unienje objekta in klic destruktorja

Ker je z razredom definiran nov tip spremenljivke je treba v datoteki, kjer se uporablja tak razred, podati kje se nahaja osnovna definicija razreda. Zato v glavi programa pri direktivah include zapiemo za na primer:
#include "Racunalnik.h"

Pomembno pri uporabi razredov je tudi, da loimo, da vsaka spremenljivka predstavlja svoj objekt. Tako sta obe spremenljivki, MojRac1 in MojRac2 posamezna objekta iz razreda CRacunalnik in vsak zase predstavljata samostojno enoto. e sta recimo oba raunalnika ugasnjena, pokliemo pa metodo PrizgiRacunalnik pri spremenljivki MojRac1, bomo s tem prigali samo raunalnik, predstavljen kot MojRac1. Stanje raunalnika, predstavljenega kot MojRac2 ostane nedotaknjeno! Vsak klic metod in dostopanje do spremenljivk je torej izvedeno samo pri objektih, katerih ime je napisano pred loilom (ali piko . ali pa puico ->).

2.3. Primer: razred CTocka


Definirajmo razred CTocka, ki ponazarja toko v treh dimenzijah. Razred vsebuje spremenljivke X, Y in Z, ki doloajo poloaj in metodo za izpis podatkov toke (Izpis) ter nekaj metod za setevanje poloajev dveh tok (e bi recimo toka predstavljala krajevni vektor). Metode za setevanje imajo vedno isto ime (Sestej), se pa razlikujejo v parametrih, ki jih sprejmejo in v rezultatu, ki ga vrnejo. Iz primera je razvidno tudi, da lahko metoda vrne nek objekt, ki je enakega tipa kot objekt, od katerega metoda se je poklicala. Dodatno ima ta razred ob osnovnem konstruktorju tudi dodatni konstruktor, v katerem lahko doloimo vrednosti vsem koordinatam. V osnovnem konstruktorju pa smo jih postavili na vrednosti 0. V nadaljevanju podajamo vsebino datoteke *.h, vsebino datoteke *.cpp ter primer uporabe v glavnem programu. Tocka.h:
class CTocka { public: // spremenljivke float X,Y,Z; // koordinate toke // metode CTocka(); // osnovni konstruktor

Programiranje 1 VS Informatika

C# . NET

231

CTocka(float X1, float Y1, float Z1); // dodatni konstruktor ~CTocka(); void Izpis(); // izpis podatkov toke void Sestej(float X1, float Y1, float Z1); void Sestej(float X1, float Y1, float Z1,float &X2, float &Y2, float &Z2); void Sestej(CTocka* T); CTocka* Sestej(float X1, float Y1, float Z1); };

Tocka.cpp:
#include "Tocka.h" // osnovni konstruktor CTocka::CTocka() { X = 0; Y = 0; Z = 0; } // dodatni konstruktor CTocka::CTocka(float X1, float Y1, float Z1) { X = X1; Y = Y1; Z = Z1; } // destruktor CTocka::~CTocka() {} // izpis podatkov tocke void CTocka::Izpis() { printf("(%f,%f,%f)\n",X,Y,Z); } // pristevanje druge tocke (sprememba se pozna na razrednih spremenljivkah) void CTocka::Sestej(float X1, float Y1, float Z1) { X += X1; Y += Y1; Z += Z1; } // sestevanje z drugo tocko (sprememba je vrnjena v spremenljivkah X2,Y2,Z2 // razredne spremenljivke pa se ne spremenijo void CTocka::Sestej(float X1,float Y1,float Z1,float &X2,float &Y2,float &Z2) { X2 = X+X1; Y2 = Y+Y1; Z2 = Z+Z1; } // pristevanje druge tocke, podane kot objekt (sprememba se pozna v razrednih // spremenljivkah klicanega objekta; ne pa od T!) void CTocka::Sestej(CTocka* T) { X += T->X; Y += T->Y; Z += T->Z; } // sestevanje druge tocke (ni spremembe razrednih spremenljivk, se pa rezultat // sestevanja vrne kot objekt! CTocka* CTocka::Sestej(float X1, float Y1, float Z1) { CTocka* Rezultat = new CTocka(); Rezultat->X = X+X1; Rezultat->Y = Y+Y1; Rezultat->Z = Z+Z1; return(Rezultat); }

V zadnji metodi imamo opravka s tremi "kompleti" koordinat. Spremenljivke X, Y in Z predstavljajo razredne spremenljivke, spremenljivke X1, Y1 in Z1 predstavljajo vrednosti, podane kot parameter metode in spremenljivke Rezultat->X, Rezultat->Y ter
Programiranje 1 VS Informatika

C# . NET

232

Rezultat->Z predstavljajo razredne spremenljivke od objekta Rezultat, ki ga vrnemo kot rezultat metode preko stavka return. To metodo bi lahko kraje zapisali tudi kot:
// sestevanje druge tocke (ni spremembe razrednih spremenljivk, se pa rezultat // sestevanja vrne kot objekt! CTocka* CTocka::Sestej(float X1, float Y1, float Z1) { return(new CTocka(X+X1,Y+Y1,Z+Z1)); }

V predzadnji metodi smo kot parameter metode uporabili objekt, oba tipa metod (predzadnja in zadnja) pa sta v objektnem programiranju zelo pogosta. e primer uporabe v glavnem programu:
#include "Tocka.h" void main() { CTocka* TockaA = new CTocka(); CTocka* TockaB = new CTocka(5,6,7); CTocka* TockaC; TockaA->Izpis(); TockaA->Y = 100; TockaA->Izpis(); TockaB->Izpis(); TockaA->Sestej(1,2,3); TockaA->Izpis(); TockaA->Sestej(TockaB); TockaA->Izpis(); TockaC = TockaA->Sestej(10,20,30); TockaC->Izpis(); TockaA->Izpis(); }

Rezultat tega je naslednji:


(0,0,0) (0,100,0) (5,6,7) (1,102,3) (6,108,10) (16,128,40) (6,108,10)

2.4. Primer: razred CDvigalo


Definirajmo razred, ki ponazarja delovanje dvigala. V dvigalu ves as beleimo v katerem nadstropju je, koliko oseb je v njemu in kakna je masa teh oseb. Dvigalo se lahko nahaja v nadstropjih od 0 (klet) do maksimalnega, ki je v osnovnem konstruktorju avtomatsko doloen na vrednost 10, sicer pa je odvisen od podane vrednosti v dodatnem konstruktorju. Delovanje dvigala je prikazano z metodami za vstop oseb v dvigalo, izstop in za premik gor ali dol. Ve razlinih metod bo definiranih za podobno obnaanje za ponazoritev razline implementacije obnaanja. Dvigalo.h:
class CDvigalo { public: // spremenljivke int Nadstropje; // trenutno nadstropje dvigala int MaxNadstropje; // najvije nadstropje dvigala int SteviloOseb; // trenutno tevilo oseb v dvigalu int TezaOseb; // skupna tea oseb v dvigalu int MaxTezaOseb; // najveja dovoljena tea vseh oseb // metode CDvigalo(); // osnovni konstruktor

Programiranje 1 VS Informatika

C# . NET

233

CDvigalo(int MaxNad); // dodatni konstruktor CDvigalo(int MaxNad, int MaxTeza);// dodatni konstruktor ~CDvigalo(); // destruktor bool SpustiDvigaloV(int Kam); // spuanje dvigala bool DvigniDigaloV(int Kam); // dviganje dvigala bool JeDvigaloVKleti(); // je dvigalo trenutno v kleti? bool JeDvigaloNaVrhu(); // je dvigalo trenutno na vrhu? bool JeVDvigaluKajOseb(); // je v dvigalu kaj oseb? bool VstopOsebe(int Teza); // vstop ene osebe v dvigalo bool IzstopOsebe(int Teza); // izstop ene osebe iz dvigala bool VstopOseb(int StOseb, int Teza); // vstop ve oseb v dvigalo bool IzstopOseb(int StOseb, int Teza); // izstop ve oseb iz dvigala void IzpisStanjaDvigala(); // izpis aktualnih podatkov dvigala };

Dvigalo.cpp:
#include "Dvigalo.h" // osnovni konstruktor CDvigalo::CDvigalo() { Nadstropje = 0; MaxNadstropje = 10; SteviloOseb = 0; TezaOseb = 0; MaxTezaOseb = 800; } // dodatni konstruktor, ki posebej nastavi najvije nadstropje CDvigalo::CDvigalo(int MaxNad) { Nadstropje = 0; MaxNadstropje = MaxNad; SteviloOseb = 0; TezaOseb = 0; MaxTezaOseb = 800; } // dodatni konstruktor, ki posebej nastavi najvije nadstropje in najvejo // dovoljeno teo CDvigalo::CDvigalo(int MaxNad, int MaxTeza) { Nadstropje = 0; MaxNadstropje = MaxNad; SteviloOseb = 0; TezaOseb = 0; MaxTezaOseb = MaxTeza; } // destruktor (v tem primeru je prazen) CDvigalo::~CDvigalo() {} // spuanje dvigala v nija nadstropja (e elimo spustiti nije kot v // klet ali pa e je eljeno nadstropje vije od trenutnega (torej ne gre za // spuanje dvigala) javi false, sicer javi true in temu primerno aurira // trenutno nadstropje dvigala bool CDvigalo::SpustiDvigaloV(int Kam) { if (Kam >= Nadstropje || Kam < 0) return(false); Nadstropje = Kam; return(true); } // dviganje dvigala v nija nadstropja (e elimo spustiti vije kot na // vrh ali pa e je eljeno nadstropje nije od trenutnega (torej ne gre za // dviganje dvigala) javi false, sicer javi true in temu primerno aurira // trenutno nadstropje dvigala bool CDvigalo::DvigniDvigaloV(int Kam) { if (Kam <= Nadstropje || Kam > MaxNadstropje) return(false); Nadstropje = Kam; return(true); } // vrne true, e je dvigalo v kleti, sicer vrne false bool CDvigalo::JeDvigaloVKleti() {

Programiranje 1 VS Informatika

C# . NET

234

if (Nadstropje == 0) return(true); return(false); } // vrne true, e je dvigalu na vrhu (na najvijem monem nadstropju), sicer // vrne false bool CDvigalo::JeDvigaloNaVrhu() { if (Nadstropje == MaxNadstropje) return(true); return(false); } // vrne true, e je v dvigalu kaj oseb (metoda bi bila ekvivalentna, e bi // gledali ali je v dvigalu skupna tea oseb veja kot 0) bool CDvigalo::JeVDvigaluKajOseb() { if (SteviloOseb > 0) return(true); return(false); } // vstop ene osebe v dvigalo z doloeno teo (e tea presega najvejo // dovoljeno skupno teo ali pa e je nepozitivna vrednost tee metoda javi // false, sicer true) bool VstopOsebe(int Teza) { if (TezaOseb+Teza > MaxTeza || Teza < 0) return(false); SteviloOseb++; TezaOseb += Teza; return(true); } // izstop ene osebe iz dvigala z doloeno teo (e v dvigalu ni toliko tee // ali pa e je nepozitivna vrednost tee metoda javi false, sicer true) bool CDvigalo::IzstopOsebe(int Teza) { if (TezaOseb > Teza || Teza < 0) return(false); SteviloOseb--; TezaOseb -= Teza; return(true); } // vstop ve oseb v dvigalo z doloeno teo (e tea presega najvejo // dovoljeno skupno teo ali pa e je nepozitivna vrednost tee metoda javi // false, sicer true) bool VstopOseb(int StOseb, int Teza) { if (TezaOseb+Teza > MaxTeza || Teza < 0) return(false); SteviloOseb += StOseb; TezaOseb += Teza; return(true); } // izstop ve oseb iz dvigala z doloeno teo (e v dvigalu ni toliko tee // ali pa e je nepozitivna vrednost tee metoda javi false, sicer true) bool CDvigalo::IzstopOseb(int StOseb, int Teza) { if (TezaOseb > Teza || Teza < 0) return(false); SteviloOseb -= StOseb; TezaOseb -= Teza; return(true); } // izpis aktualnih podatkov od dvigala (trenutno nadstropje, tevilo oseb v // dvigalu in njihova skupna tea) void CDvigalo::IzpisStanjaDvigala() { printf("trenutno v nadstropju : %d\n",Nadstropje); printf("v njem stevilo oseb : %d s skupno tezo : %d\n",SteviloOseb,TezaOseb); }

2.5. Dedovanje
Programiranje 1 VS Informatika

C# . NET

235

Na hitro e nekaj besed o dedovanju (na samih vajah to ne boste potrebovali, je pa to eden od pomembnejih principov objektnega programiranja!). V implementacijah se nam lahko pojavi mnoica razredov, ki se med seboj le malo razlikujejo (dopolnjujejo v kodi ali pa drugae implementirajo del kode) in jih je smiselno zaradi urejenosti in pregleda ustrezno hierarhino urediti. Obiajno se uporabljajo postopki dedovanja (ang. inheritance), kjer izpeljani razredi (in temu primerno potem tudi objekti) podedujejo nekatere lastnosti, podatke in operacije od drugih razredov. Na primer, imamo nek razred A, predstavljen z doloeno mnoico spremenljivk in metod, zatem pa elimo napisati nov razred B, ki je v skoraj vsem enak, le da ima e eno dodatno spremenljivko. Namesto, da bi spet pisali (kopirali ali pa pretipkali) isto kodo in le dodali eno vrstico zaradi te dodatne spremenljivke, lahko preprosteje doloimo, da ima razred B vse lastnosti in metode enake kot razred A, razlika je le dodatna spremenljivka. Pravimo, da smo razred B izpeljali iz razreda A oziroma, da je razred A nadrazred razredu B. Recimo, da imamo sploen razred CLik, ki vsebuje spremenljivki X in Y, ki doloata sredie lika in metodo Premakni za premik lika za podane koordinate. Imamo pa tudi razred CKrog, ki ima prav tako sredie kroga in e polmer in metodo za izraun povrine. Da ne ponavljamo kode, zapiemo, da je razred CKrog podedoval lastnosti od razreda CLik ima pa e svojo spremenljivko Radius:
class CLik { double X,Y; // koordinati sredia void Premakni(int ZaX, int ZaY); // premik sredia lika CLik(); ~CLik(); }; class CKrog : CLik { // nadrazredi so nateti za podpijem! double Radius; // radius kroga double IzracunajPovrsino(); // povrina kroga CKrog(); ~CKrog(); };

Vsi nadrazredi (ker lahko razred naenkrat deduje lastnosti veih razredov) so nateti za dvopijem, pri emer moramo biti zelo pazljivi, da nadrazredi ne vsebujejo istoimenskih spremenljivk in metod, ker sicer pride do zmede. Pri dedovanju je e posebej pomembno, kaj je v nadrazredu doloeno kot privatno, kaj javno in kaj kot prijateljsko (ang. friendly), vendar to presega okvire vaj in tega teksta.

2.6. Splone lastnosti objektnega programiranja ("na


Programiranje 1 VS Informatika

C# . NET

236

hitro")
Lastnosti objektno usmerjenih programskih jezikov/okolij bi lahko na hitro strnili v1: - nastanek/unienje objektov : objekti pri svojem nastanku zavzamejo prostor v pomnilniku in ga ob koncu sprostijo. Pri tem mora programski jezik za vsak nov objekt dovoliti dve proceduri: konstruktor ob nastanku in destruktor ob unienju. - inicializacija/prirejanje : C++ dovoljuje, da vgrajenim podatkovnim tipom ob definiciji priredimo zaetno vrednost. Vse vdelane tipe smemo prirejati med seboj. Enako mora veljati tudi za nove podatkovne tipe. - polimorfizem (mnogolinost) osnovnih operatorjev : isti operator ali funkcija dela razline stvari glede na razline parametre. Obstajati mora mehanizem, da operatorje priredimo tudi za delo z novimi tipi. - dedovanje : lastnosti enega ali ve razredov se prenesejo na nov razred in dopolnijo z novimi lastnostmi. - enkapsulacija : programski jezik omogoa kontrolo nad tem, kdo pozna detajle nekega razreda in kdo ga lahko uporablja samo prek za to doloenih podprogramov. Objektno programiranje se dolgorono gledano bogato obrestuje, ker je programiranje s knjinicami razredov ceneje, veinoma bolj uinkovito in bolj zanesljivo.
1

delno povzeto iz Objektno programiranje v C++, Stanko Dolenek,

4. Primeri iz izpitov
Zaenkrat so v nadaljevanju samo teksti iz izpitnih nalog, reitve e sledijo.

4.1. CAlbum in CPesem


Napiite razreda CAlbum in CPesem. Razred CPesem naj vsebuje tipine podatke neke pesmi (naslov pesmi, avtor), ki naj bodo shranjene v privatnih spremenljivkah. Vrednosti teh spremenljivk naj bo mono spremeniti in (loeno!) povpraati po njihovih vrednostih z javnimi metodami (torej 4 metode!). Razred CAlbum naj vsebuje v privatnih spremenljivkah podatke o zalobi albuma, tevilo pesmi in polje s podatki o pesmih (polje objektov razreda CPesem). Velikost polja pesmi naj se doloi v konstruktorju razreda CAlbum in takrat naj se v pomnilniku tudi rezervira prostor za polje pesmi. Zapiite deklaracije in definicije metod obeh razredov, v delu programa (ne piite vsega!) pa nakaite, kako bi "pripravili" album dvajsetih razlinih avtorjev (vsak eno pesem) iz koncertov na TUKu in kako bi ugotovili avtorja tretje pesmi na tem albumu.
class CPesem { private: char* Naslov; char* Avtor; public: void NastaviNaslov(char* Nas); void NastaviAvtorja(char* Avt); char* DajNaslov(); char* DajAvtorja(); CPesem(); ~CPesem(); }; CPesem::CPesem() {} CPesem::~CPesem() {}

Programiranje 1 VS Informatika

C# . NET

237

void CPesem::NastaviNaslov(char* Nas) { Naslov = Nas; } void CPesem::NastaviAvtorja(char* Avt) { Avtor = Avt; } char* CPesem::DajNaslov() { return(Naslov); } char* CPesem::DajAvtorja() { return(Avtor); } class CAlbum { private: char* Zalozba; int SteviloPesmi; CPesem* Pesmi; public: void NastaviPesem(int ZapSt, char* Naslov, char* Avtor); CPesem DajPesem(int ZapSt); CAlbum(int StPesmi); ~CAlbum(); }; CAlbum::CAlbum(int StPesmi) { Pesmi = new CPesem[StPesmi]; SteviloPesmi = StPesmi; } CAlbum::~CAlbum() { delete[] Pesmi;} void CAlbum::NastaviPesem(int ZapSt, char* Naslov, char* Avtor) { if (ZapSt>0 && ZapSt <= SteviloPesmi) { Pesmi[ZapSt].Naslov = Naslov; Pesmi[ZapSt].Avtor = Avtor; } } CPesem CAlbum::DajPesem(int ZapSt) { if (ZapSt>0 && ZapSt <= SteviloPesmi) return(Pesmi[ZapSt]); else return(false); }

4.2. CRacun
Napiite razred CRacun, ki predstavlja raun v nekem nakupu, npr. trgovini. Razred naj vsebuje metodo DodajNaRacun(char*, double, int), kjer boste "na raun" dodali novo zadevo (z nekim imenom, ceno in tipom stopnje davka: 1 za recimo 10%, 2 recimo za 20%). Prav tako naj obstaja metoda OdstraniIzRacuna(char*), kjer boste neko zadevo odstranili iz rauna. Dodatna naj bo e metoda IzpisRacuna(), kjer izpiete vse zadeve, ki so se nabrale "na raunu", njihovo skupno ceno in posebej, koliko zadev (tevilo in njihova skupna cena) je bilo za stopnjo davka 1 in koliko za stopnjo davka 2. Sami razmislite o tem, s katerimi spremenljivkami boste realizirali seznam zadev "na raunu" (naj jih bo recimo najve 30), za primerjavo nizov pa lahko uporabite kar vgrajeno funkcijo strcmp! Napiite deklaracijo razreda (*.h), izvedbo metod (*.cpp) in kratek primer uporabe, kjer boste uporabili te metode.
class CRacun { private: char** Stvari; double* Cene; int* Davki; int SteviloStvari; public: void DodajNaRacun(char* Kaj, double Cena, int Davek); void OdstraniIzRacuna(char* Kaj); void IzpisRacuna();

Programiranje 1 VS Informatika

C# . NET

238

CRacun(); ~CRacun(); }; CRacun::CRacun() { Stvari = new char*[30];} for (int i=0;i<30;i++) Stvari[i] = new char*[100]; // recimo, da je ime izdelka najvec 100 znakov SteviloStvari = 0; } CRacun::~CRacun() { for (int i=0;i<30;i++) delete[] Stvari[i]; delete Stvari; } void CRacun::DodajNaRacun(char* Kaj, double Cena, int Davek) { if (SteviloStvari == 30) // je sploh se mozno dati kaj na racun? return; Stvari[SteviloStvari] = Kaj; Cene[SteviloStvari] = Cena; Davki[SteviloStvari] = Davek; SteviloStvari++; } void CRacun::OdstraniIzRacuna(char* Kaj) { for (int i=0;i<SteviloStvari;i++) { if (strcmp(Stvari[i],Kaj) == 0) { // izdelek s tem imenom najden! for (int j=i;j<SteviloStvari-1;j++) { Stvari[j] = Stvari[j+1]; Cene[j] = Cene[j+1]; Davki[j] = Davki[j+1]; } SteviloStvari--; } // if } // for i } void CRacun::IpisRacuna() { double SkupnaCena = 0.0; int KolikoDavek1 = 0; int KolikoDavek2 = 0; double SkupnaCenaDavek1 = 0.0; double SkupnaCenaDavek2 = 0.0; for (int i=0;i<SteviloStvari;i++) { SkupnaCena += Cene[i]; if (Davki[i] == 1) { KolikoDavek1++; SkupnaCenaDavek1 += Cene[i]; } else KolikoDavek2++; SkupnaCenaDavek2 += Cene[i]; } } printf("Stanje racuna:\n"); printf("stevilo izdelkov : %d\n",SteviloStvari); printf("skupna cena izdelkov : %f\n",SkupnaCena); printf("izdelkov dav. stopnje 1 : %d v skupni ceni : %f\n",KolikoDavek1, SkupnaCenaDavek1); printf("izdelkov dav. stopnje 2 : %d v skupni ceni : %f\n",KolikoDavek2, SkupnaCenaDavek2); }

4.3. CTekma
Napiite razred CTekma, ki predstavlja neko poljubno tekmo, recimo nogometno, ker je

Programiranje 1 VS Informatika

C# . NET

239

to trenutno najbolj aktualno. Tekma se odvija med dvema motvoma (vsako motvo ima svoje ime), dogajanje na tekmi pa se belei z naslednjimi metodami: DalGol(ime_motva), RazveljaviGol(ime_motva), RumeniKarton(ime_motva), RdeciKarton(ime_motva), Prekrek(ime_motva) in IzpisRezultata() ter IzpisStatistike(ime motva). V teh metodah se motvu, katerega ime je podano kot parameter: doda gol, razveljavi gol, zabelei dobljen rumeni in rdei karton, zabelei napravljen prekrek, zadnji dve metodi pa sta namenjeni izpisu rezultata (koliko golov je na kateri strani) in statistiki tekme (rezultat, rumeni kartoni, rdei kartoni in prekrki). Imena motev se doloita s parametroma v konstruktorju razreda. Sami razmislite o tem, s katerimi spremenljivkami boste realizirali statistiko (in rezultat tekme). Za primerjavo nizov lahko uporabite kar vgrajeno funkcijo strmcp (<string.h>)! Napiite deklaracijo razreda (*.h), izvedbo metod (*.cpp) in kratek primer uporabe, kjer boste uporabili te metode.
class CTekma { public: char* ImeMostva1; char* ImeMostva2; int Gol1, Gol2; int PrekrsekRu1, PrekrsekRu2; int PrekrsekRd1, PrekrsekRd2; int Prekrsek1, Prekrsek2; void DalGol(char* Mostvo); void RazveljaviGol(char* Mostvo); void RumeniKarton(char* Mostvo); void RdeciKarton(char* Mostvo); void Prekrsek(char* Mostvo); void IzpisRezultata(); CTekma(char* Mostvo1, char* Mostvo2); ~CTekma(); }; CTekma::CTekma(char* Mostvo1, char* Mostvo2) { Gol1 = 0; Gol2 = 0; PrekrsekRu1 = 0; PrekrsekRu2 = 0; PrekrsekRd1 = 0; PrekrsekRd2 = 0; Prekrsek1 = 0; Prekrsek2 = 0; ImeMostva1 = Mostvo1; ImeMostva2 = Mostvo2; } CTekma::~CTekma() {} void CTekma::DalGol(char* Mostvo) { if (strcmp(Mostvo,ImeMostva1) == 0) Gol1++; else Gol2++; } void CTekma::RazveljaviGol(char* Mostvo) { if (strcmp(Mostvo,ImeMostva1) == 0) Gol1--; else Gol2--; } void CTekma::RumeniKarton(char* Mostvo) { if (strcmp(Mostvo,ImeMostva1) == 0) PrekrsekRu1++; else PrekrsekRu2++; } void CTekma::RdeciKarton(char* Mostvo) {

Programiranje 1 VS Informatika

C# . NET

240

if (strcmp(Mostvo,ImeMostva1) == 0) PrekrsekRd1++; else PrekrsekRd2++; } void CTekma::Prekrsek(char* Mostvo) { if (strcmp(Mostvo,ImeMostva1) == 0) Prekrsek1++; else Prekrsek2++; } void CTekma::IzpisRezultata() { printf("Stanje na tekmi med %s in %s:\n",ImeMostva1,ImeMostva2); printf("rezultat : %d:%d\n",Gol1,Gol2); printf("prekrski : %d:%d\n",Prekrsek1,Prekrsek2); printf("rumeni kartoni : %d:%d\n",PrekrsekRu1,PrekrsekRu2); printf("rdeci kartoni : %d:%d\n",PrekrsekRd1,PrekrsekRd2); }

Programiranje 1 VS Informatika

You might also like