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

o
o

14

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

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)

new NekiObjekt();

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


NekiObjekt

a = new NekiObjekt();

V pomnilniku se je naredil objekt tipa NekiObjekt() in a kae na ta novo ustvarjeni objekt

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__

o
o

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;

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
7:
8:
9:
10:
11:
12:
13:
14:
15:
16:
17:
18:
19:
20:
21:
22:
23:

17

// 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;
z1.masa = 0.12;
72:
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
int i = 0;
31:
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;
zajci[i].masa = 0.12;
36:
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 {


public string serijska;
86:
87:
public bool spol;
88:
public double masa;
89:
90:
// konstruktor
public Zajec() {
91:
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";
a.leto_vpisa = 2000;
88:
89:
a.vpisna_st = "2304";
90:
91:
Clan b = new Clan();
b.ime = "Mojca";
92:
93:
b.priimek = "Mavko";
b.leto_vpisa = 2001;
94:
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;
public int leto_vpisa;
114:
115:
public string vpisna_st;
116:
public Clan(string i, string p, int l, string v) {
117:
118:
this.ime = i;
this.priimek = p;
119:
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

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

33

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");
Clan c = b;
134:
135:
c.ime = "Katarina";
136:
137:
Console.WriteLine("Clan a:\n" + a.ime + " " + a.priimek +
138:
" " + a.leto_vpisa + " (" + a.vpisna_st +
")\n");
139:
Console.WriteLine("Clan b:\n" + b.ime + " " + b.priimek +
140:
141:
" " + b.leto_vpisa + " (" + b.vpisna_st +
")\n");
142:
Console.WriteLine("Clan c:\n" + c.ime + " " + c.priimek +
143:
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";
leto_vpisa = 0;
133:
Programiranje 1 VS Informatika

C# . NET

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

34

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) {
Clan a = new Clan("Janez", "Starina", 2000, "2304");
153:
string inicialnkeClanaA = a.Inicialke();
154:
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();
nov.ime = this.ime;
165:
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

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: }

36

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;
public int leto;
244:
245:
public Datum() {
246:
dan = 1;
247:
mesec = "januar"
248:
leto = 2000;
} // privzeti datum je torej 1.1.2000
249:
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;
if (dan == 29 && mesec == "februar" && this.JePrestopno()) return;
269:
270: // lahko nehamo, mesec in leto sta ok
271:
string[] meseciPo30 = {"april","junij","september", "november"};
272:
if (dan == 31) {
if (meseciPo30.IndexOf(mesec) > 0){
273:
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()) {
Console.WriteLine("Je prestopno leto");
286:
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)

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.

najtejega
najcenejega
vse zajklje
najtejega samca

Datum

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{


public static void Main(string[] args) {
332:
333:
Clan novClan = new Clan();
334:
novClan.ime = "Katarina";
novClan.leto_vpisa = 208;
335:
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

349:
350:
351:

44

}
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";
novClan.leto_vpisa = 2007;
358:
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:
public string Inicialke() {
382:
383:
return this.ime[0] + "." + this.priimek[0] + ".";
384:
}
385:
public Clan Kopija() {
386:
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() {
Console.WriteLine("Clan:\n" + this.ime + " " +
396:
397:
this.priimek
+
"
"
+
this.Datum_vpisa.OpisDat() +
398:
" (" + this.vpisna_st + ")\n");
399:
}
400:
401:
public string Opis() {
402:
return this.ime + " " + this.priimek + " " +
this.datum_vpisa.OpisDat() + " (" + this.vpisna_st + ");
403:
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:

426:

public int VrniLetoVpisa() {

427:
428:

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

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

V RAZREDU

430:

public int VrniLetoVpisa() {

431:
432:

CLAN

Z DATUMOM

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
private double masa; // masa zajca ob zadnjem pregledu
162:
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

447:
448:
449: }

50

// 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
// in javimo, da spremembe nismo naredili
461:
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")

Znajo vrniti spremiti rke v male in vrniti nov niz:

Znajo povedati, e so enaki nekemu drugemu nizu:

o
o

nekNiz.toLower()
mojPriimek.Equals("Lokar")

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

IZPIS

53

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

CELOTNI

RAZRED

ZAJEC

472: public class Zajec {


473:
private string serijska;
474:
private bool spol;
475:
private double masa;
476:
// konstruktor
public Zajec() {
477:
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

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:

55

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

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

56

// 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 {


public static void Main(string[] ar) {
196:
197:
Zajec z1 = new Zajec();
198:
z1.serijska = "1238-12-0;
199:
z1.spol = false;
200:
z1.masa = 0.12;
z1.masa = z1.masa + 0.3;
201:
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

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

60

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() {}
public Kovanec(int r, int v) {}
247:
248:
249:
// "SET" metode
public void NastaviPolmer(int r) {
250:
251:
polmer = r;
252:
}
253:
254:
public void NastaviVisino(int visina) {
// smiselna visina je le med 1 in 100
255:
256:
// drugace jo pustimo pri miru
if ((1 <= visina) && (visina <= 100))
257:
258:
this.visina = visina;
259:
}
260:
// "GET" metode
261:
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

289:
290: }

62

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

BREZ PARAMETROV

public Kvader(){
a = 1;
b = 1;
c = 1;
}
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

291: public class Kvader {


292:
// z /* ... */ so oznaceni komentarji za razlago zakaj
293:
// v "pravem" razredu jih ne bi bilo!
294:

doloceni konstrukcijski prijemi

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

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

64

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

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:

65

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

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

66

// 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
Object */
407:
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
nam ob morebitni
414:
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.

KODA

Z NAPAKO

552: public class X {


553:
public int a = 0;
public int b = 2;
554:
555:
556:
override public ToString() {
return "a = " + a + " b = " + b;
557:
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

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

y2
y3
y4
y5
y6

=
=
=
=
=

new
new
new
new
new

75

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) {
a = aa;
574:
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: }

588:
589:

Ali je v kodi kakna napaka? e je, jo odpravi!


Kaj izpie sledea koda?

PovecajR inc = new PovecajR();


Programiranje 1 VS Informatika

C# . NET

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

76

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

Datum
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

int CompareTo(Datum d), ki primerja this in 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.

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

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


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

o
o

o
o

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.

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
Console.WriteLine("Najprimernejsi
je:
633:
NajPrimernejsi(kandidati));
634:
635:
636:
Console.Write("Press any key to continue . . . ");
Console.ReadKey(true);
637:
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

o
o

80

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() {
// DOPOLNI!
667:
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:
// OBJEKTNE SPREMENLJIVKE
425:
426:
private string serijska;
427:
private bool spol;
428:
private double masa;
429:
// konstruktorji
430:
431:
432:
public Zajec() {
433:
this.spol = true; // vsem zajcem na zaetku doloimo m. spol
this.masa = 1.0; // in tehtajo 1kg
434:
435:
ZajecNov.kolikoZajcev++; // NAREDILI SMO NOVEGA ZAJCA
436:
this.serijska = ZajecNov.OsnovaSerijska + ZajecNov.kolikoZajcev;
437:
}
public Zajec(bool spol, double masa) {
438:
439:
this(); // poklicali smo konstruktor Zajec() - ta
// bo e poveal tevilo zajcev + naredil
440:
441:
// nj. ser. tevilko
442:
this.SpremeniTezo(masa); // uporabimo metodo za sprem.
this.spol = spol;
443:
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;
int decim = (int)((this.masa - tezaKg) * 10);
451:
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
// napojiti, da bomo "ujeli" naslednjih pol kg
492:
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;
private double c;
506:
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

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:

91

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

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:

92

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:
//
public string ToString() { /* prekrivanje metode iz razreda
637:
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:
private int polmer;
691:
692:
private int visina;
693:
public static final int OBI_POLMER = 3; // obicajni polmer
public static final int OBI_VISINA = 1; // obicajna visina
694:
695:
public static final int NAJ_POLMER = 3; // najveji moni polmer
public static final int NAJ_VISINA = 1; // najveja mona visina
696:
697:
698:
699:
// konstruktorji
public Kovanec() {
700:
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

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:

94

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:
public Foo(int z) {
653:
654:
this.y = z;
655:
}
656:
public static int F(int a) {
657:
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:
}
// ali y + Foo.x + a ALI y + x + y ALI ...
665:
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
public static final int NAJ_POLMER = 3; // najveji moni polmer
673:
674:
public static final int NAJ_VISINA = 1; // najveja mona visina
675:
676:
// konstruktorji
public Kovanec() {
677:
678:
// "obicajni" kovanec
this.polmer = OBI_POLMER;
679:
680:
this.visina = OBI_VISINA;
}
681:
682:
public Kovanec(int polmer, int visina) {
683:
684:
// "drugacni" kovanec
685:
// ce ni ustreznih dimenzij, naredimo "obicajni" kovanec
if (Vmes(polmer, 1, NAJ_POLMER) && Vmes(visina,1,NAJ_VISINA)){
686:
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;
this.visina = OBI_VISINA;
693:
694:
}
695:
}
696:
// "SET" metode
697:
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

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: }

97

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

770:
771:
772: }

99

// 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

784:
785:
786: }

100

}
}

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:
zelvak.Kvadrat(40);
796:
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;
private int visina;
806:
807:
private double gostota;
private double cistost;
808:
809:
// "SET" metode
810:
public bool NastaviPolmer(int r) { }
public bool NastaviVisino(int visina) { }
811:
812:
public void NastaviGostoto(double x) { }
public void NastaviCistost(double x) { }
813:
814:
public static void NastaviVrednostCistegaZlata(int v) { }
815:
// vrednost lahko spreminajmo tudi, ce se ni nobenega zlatnika!
816:
// "GET" metode
817:
818:
public int PovejPolmer() { }
public int PovejVisino() { }
819:
820:
public double PovejGostoto() { }
public double PovejCistost() { }
821:
822:
public static double PovejVrednostCistegaZlata() { }
823:
// vrednost lahko zvemo tudi, ce se ni nobenega zlatnika!
824:
825:
// tostring
override public string ToString() { }
826:
827:
// podedovana tostring metoda nam ne ustreza!
828:
// "znanje"
829:
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

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:

102

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

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:

103

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

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

104

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:
private double gostota;
977:
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:
// konstruktorji
982:
983:
public Zlatnik() : base() {
984:
// "obicajni" zlatnik
this.gostota = OBI_GOSTOTA;
985:
986:
this.cistost = OBI_CISTOST;
987:
}
988:
public Zlatnik(int polmer, int visina, double gostota,
989:
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

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: }

105

// 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

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:

109

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

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

111

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,

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;
this.steviloKoles = steviloKoles;
912:
913: }
914:
915: public Tovornjak Klonirajv0() {
916:
return new Tovornjak(this.steviloKoles, this.barva,
917:
this.maxHitrost);
918: }
919:
920:
921: public Tovornjak Klonirajv1() {
return new Tovornjak(this.steviloKoles, this.barva,
922:
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() {
return new Vozilo(this.steviloKoles, this.barva, this.maxHitrost);
976:
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());
return a;
986:
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

6.

117

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

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:

118

// 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

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:

120

{ // 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

double B = 4;

136

//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.
2

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.

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

new public void Izpis()


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

Vaja:

Programiranje 1 VS Informatika

metodo Izpis

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();

//zbirka oseb

Oseba mike = new Oseba("mike");


osebe.Add(mike);
Console.WriteLine("Osebe:");

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());

//zbirka vseh skupaj

}
public class Oseba
{
public string ime;
public Oseba(string ime)
{
this.ime = ime;
}

//bazini razred
//bazino polje
//bazini konstruktor

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

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# :

Podatke

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:

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, ...

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

Seveda, e je nain spraevanja in odgovarjanja ostal nespremenjen


e so metode ostale enake (imajo enaka imena, nabor parametrov in tip rezultata)

Npr.:

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(en-

us).aspx

Razporejeni v imenske prostore

System, System.IO

Drugi viri

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)

new NekiObjekt();

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


z opisom razreda 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

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

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

Kako dosei, da se podatki drijo skupaj

Tabela ni ustrezna

Sestavimo razred Zajec


Opis podatkov, ki sestavljajo poljubnega zajca

Tabela je zbirka istovrstnih podatkov

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.

tabZ[0] = new 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.

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();

Kako napolniti stevec in imenovalec?

x.stevec : spremenljivka tipa int!


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

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?

Ob prvem klicu je ???? objA, ob drugem pa objC. To


"zamenjavo" doseemo z this. Napiemo

Console.WriteLine("Starost je: " +


?????.starost);

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)

Vasih pa so zajci "nestandardni"

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

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?

Preobteevanje

Overloading
Velja tudi splono, za vse metode

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,

x)

bool spol, double masa)

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

Uporabimo lahko le kot PRVI stavek v konstruktorju

this()
this(<parametri>)

this.

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

"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;
}
}

Ni teav!

Poskus testa

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");
}
}

Imamo

Sprememba razreda

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;

//leto je smiselno, popravimo stanje objekta in vrnemo true

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

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 ==

Nobene kontrole nad pravilnostjo podatkov o objektu!

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

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;

Uporabnik pozna predstavitev

Kasneje je ni mogoe spremeniti

Naini dostopa

public
private
protected

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

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

Kdorkoli naredi objekt vrste MojObjekt

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;

// v

razredu MojObjekt

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"

Pogosto na to pozabimo

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!

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!
}

Poizvedba

Dostop do stanj

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 3, 2.502 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

Odzivi objektov
"znanje objektov"

Objekti tipa string

213

Znajo povedati, kje se v njih zane nek podniz:

"niz".IndexOf("i")

Znajo vrniti spremeniti rke v male in vrniti nov niz:

nekNiz.ToLower()

Znajo povedati, e so enaki nekemu drugemu nizu:

mojPriimek.Equals("Lokar")

"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
pove emo v delujoe programe predstavlja mnogim na zaetku zaradi nekoliko
druganega razmiljanja te avo. 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 mno ice tipk, torej mno ice 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 prig an 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, pri iganje 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
- prig an ali ugasnjen raunalnik
- prikljuen tiskalnik
obnaanje:
- zapis datoteke na disk
- tiskanje dokumenta
- pri iganje 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 pri gan, 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
izka e, 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(); // pri iganje 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 prig an ali ne. Ima torej vrednost true,
e
je pri gan in false, e je ugasnjen zaradi esar imamo pri metodi dve mo nosti:
bodisi
bomo ugasnili raunalnik, ki je pri gan ali pa bomo eleli ugasniti raunalnik, ki je e
ugasnjen. Ne glede na ti dve mo nosti 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 za eljeno
ve
informacije. Na primer, ko bomo izvedli tiskanje dokumenta (torej, ko bomo v
programu
poklicali metodo NatisniDokument), ne vemo ali je dokument sploh mo no natisniti ali
ne. Z drugimi besedami, ali je na raunalnik sploh prikljuen tiskalnik ali ne in ali je
raunalnik sploh pri gan? Obnaanje metode za tiskanje dokumentov bi tako lahko
bilo
"bolje", e bi metoda recimo vrnila true, e je bilo tiskanje mo no, oziroma false, e
tiskanje ni bilo mo no, ker na raunalnik ni prikljuen tiskalnik ali pa ker raunalnik ni
prig an. 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 pri iganje (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(); // pri gi raunalnik

lahko bolj primerno zapisali kot

bool PrizgiRacunalnik(); // pri gi 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 pri gan, 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(); // pri iganje 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 pri gali 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 pri iganju 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 te avo, 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 te avo, 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 prig emo
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 prig ali 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 pri gan, 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(); // pri iganje 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 prig ali 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 polo aj in metodo za izpis podatkov toke (Izpis)
ter
nekaj metod za setevanje polo ajev 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 bele imo 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 te a oseb v dvigalu
int MaxTezaOseb; // najveja dovoljena te a 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 te o
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 ni ja nadstropja (e elimo spustiti ni je 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 a urira
// trenutno nadstropje dvigala
bool CDvigalo::SpustiDvigaloV(int Kam) {
if (Kam >= Nadstropje || Kam < 0)
return(false);
Nadstropje = Kam;
return(true);
}
// dviganje dvigala v ni ja nadstropja (e elimo spustiti vije kot na
// vrh ali pa e je eljeno nadstropje ni je od trenutnega (torej ne gre za
// dviganje dvigala) javi false, sicer javi true in temu primerno a urira
// 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 mo nem 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 te a oseb veja kot 0)
bool CDvigalo::JeVDvigaluKajOseb() {
if (SteviloOseb > 0)
return(true);
return(false);
}
// vstop ene osebe v dvigalo z doloeno te o (e te a presega najvejo
// dovoljeno skupno te o ali pa e je nepozitivna vrednost te e 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 te o (e v dvigalu ni toliko te e
// ali pa e je nepozitivna vrednost te e 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 te o (e te a presega najvejo
// dovoljeno skupno te o ali pa e je nepozitivna vrednost te e 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 te o (e v dvigalu ni toliko te e
// ali pa e je nepozitivna vrednost te e 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 te a)
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 mno ica 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 mno ico 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
knji nicami 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 mo no spremeniti in (loeno!) povpraati po njihovih
vrednostih
z javnimi metodami (torej 4 metode!). Razred CAlbum naj vsebuje v privatnih
spremenljivkah podatke o zalo bi 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 naka ite, 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 bele i 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, zabele i dobljen rumeni in rdei karton, zabele i
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