You are on page 1of 46

NASTAVA RAQUNARSTVA

Stanka Matkovi, Mijodrag urixi


MALA XKOLA OBJEKTNO ORIJENTISANOG
PROGRAMIRAA U PROGRAMSKOM JEZIKU C#
Prvi deo

Klasa, atributi i metodi


Osnovni pojam u objektno orijentisanom programirau je klasa. Klasa
predstava uopxtee objekata koji imaju zajedniqke osobine i funkcionalnosti. Osobine opisujemo atributima a funkcionalnosti metodima.
Posmatrajmo nastavni proces u xkoli. Recimo da u uqionici 1 uqenik IVa,
Pera, radi zadatak iz matematike po zahtevu profesora Laze, a u uqionici 2
profesor Mika predaje svim uqenicima odeea IVb novu lekciju iz fizike.
Sasvim je mogue da sutradan uloge profesora budu promeene, pa da profesor
Mika u IVa ispituje ili predaje novu lekciju iz fizike, a profesor Laza u IVb
predaje novu lekciju iz matematike.
Ve u ovom uproxenom prikazu nastavnog procesa moemo uoqiti osnovne
objekte koji uqestvuju u emu (Pera, Mika, Laza, IVa, IVb, matematika, fizika,
uqionica 1, . . . ). Lako se moe uoqiti da Mika i Laza koordiniraju nastavni
proces tako xto upoznaju uqenike sa novim gradivom, vrxe proveru znaa uqenika, oceuju ga, itd. Oni imaju i zajedniqke osobine (ime, struqna sprema,
predmet koji predaju, godine staa). Samim tim oni pripadaju jednoj od klasa
uqesnika u nastavnom procesu, klasi Profesor. Na sliqan naqin moemo uoqiti
i klase Ucenik (Pera), Predmet (matematika, fizika), Odeljenje (IVa, IVb), . . .
Do klasa dolazimo polazei od pojedinaqnih objekata. Posmatraem svih
uqenika uoqavamo ihove zajedniqke osobine. Na primer, za sve uqenike je potrebno pratiti ime, prezime, datum roea, razred, odeee. Te osobine nazivamo
atributima. Takoe, svim uqenicima moemo pridruiti iste ,,akcije: uqenik odgovara i dobija ocenu, uqenik mea odeee . . . Te akcije u okviru klase
nazivamo metodima klase, i ima se opisuje funkcionalnost objekata te klase.
Klasu definixemo navoeem rezervisane reqi class iza koje sledi identifikator klase (ime klase). Posle imena, ako formiramo klasu koja nasleuje
neku, prethodno definisanu klasu, u zaglavu navodimo : pa ime klase iz koje je izvedena. Zatim navodimo telo klase u kome u vitiqastim zagradama {}
definixemo qlanove klase (atributi i metodi).

Mala xkola objektno orijentisanog programiraa

27

class <imeKlase> :<imePrethodnoDefinisaneKlase>


{
opis / definicija
clanova klase
}

Na primer, klasu uqenika moemo intuitivno definisati na sledei naqin:


class Ucenik
{
string ime, prezime;
DateTime datumRodjenja;
int razred;
int SkolskaGodina;
char odeljenje;
Ocena [] ocene;
double prosek()
{
...
}
double prosek(Predmet P)
{
...
}
void uci(Lekcija X)
{
...
}
}

Da bismo napravili objekat, upotrebavamo izraz oblika


<ime objekta> =new <ime klase> () .

Korixeem operatora new odvaja se u dinamiqkoj memoriji prostor za


registrovae objekta klase <ime klase>. Ovaj operator vraa adresu dodeenog
prostora koju moemo dodeliti imenu objekta:
Ucenik x=new Ucenik();

Atributima opisujemo odreenu osobinu objekta (ime, prezime, datum roea, razred, odeee). Najqexe, razliqiti objekti iste klase imaju razliqite
vrednosti atributa. Vrednosti atributa definixu stae objekta. Pri opisu
atributa moramo navesti tip kome taj atribut pripada (celobrojni, realni, znakovni, . . . ) i ime atributa. Pristup atributima objekta neke klase realizujemo
na sledei naqin:
imeObjekta.imeAtributa

28

S. Matkovi, M. urixi

Na primer, ako je x objekat klase Ucenik, atributu ime pristupamo navoeem x.ime.
Metodom opisujemo ponaxae objekta u odreenoj situaciji i pod odreenim
uslovima (uci), ali i odreujemo nove vrednosti na osnovu osobina koje objekat
poseduje (prosek). Na taj naqin opisujemo funkcionalnost objekta.
Metod klase je imenovani blok naredbi koji se sastoji iz zaglava i tela
metoda. U zaglavu navodimo povratni tip (ako metod ne proizvodi vrednost koju
vraa, navodimo rezervisanu req void), zatim ime metoda za kojim sledi u malim
zagradama spisak parametara metoda. Za svaki parametar navodi se tip kome taj
parametar pripada kao i ime parametra. Posle zaglava u vitiqastim zagradama
navodimo telo metoda koje se sastoji iz odgovarajuih iskaza programskog jezika
C#.
<povratni tip> <ime metoda>(<lista parametara>)
{ <telo metoda> }

Poziv metoda objekta u programskom jeziku C# realizujemo na sledei naqin:


imeObjekta.imeMetoda(lista stvarnih parametara)

Na primer, ako je x objekat klase Ucenik, metod prosek pozivamo sa


x.prosek(), a metod uci, x.uci(L) gde je L objekat klase Lekcija.
Ukoliko u telu metoda koristimo neki od atributa ili pozivamo neki drugi
metod te klase, ne navodimo ime objekta ve samo ime atributa, odnosno metode. Umesto imena objekta moemo navesti slubenu req this. Objekat kome se
obraamo preko this je tekui objekat.
Razliqiti metodi u jednoj klasi mogu imati isti naziv ali se moraju razlikovati po broju ili tipu parametara. Pisae metoda istog imena a razliqitih parametara naziva se preklapae (overloading), preoptereivae metoda.
U klasi Ucenik metod prosek smo preopteretili: za uqenika moemo raqunati
prosek svih zakuqenih ocena (prosek()), a moemo i prosek svih egovih ocena
iz datog predmeta (prosek(Predmet P)).
Svojstva
Jedna od najznaqajnih karakteristika objektno orijentisanog programiraa
je enkapsulacija (zatvorenost, uqauree) objekata. Pod enkapsulacijom objekta podrazumevamo kontrolisan pristup elementima objekta. Nekim elementima
objekta mogu pristupiti svi koji taj objekat na bilo koji naqin koriste. Te elemente nazivamo javnim (public) i oni qine deo preko koga objekat komunicira
sa drugim objektima. Nasuprot ima postoji deo objekta koji ne koristimo direktno u komunikaciji sa drugim objektima, da ne bi bio izloen neovlaxenom
pristupu ili promeni. Za takve elemente kaemo da su privatni (private).
Vrlo qesto postoji potreba da se atributi zaxtite od neovlaxenog pristupa ili promene pa su oni uglavnom privatni qlanovi klase, dok su metode u
veini sluqajeva javne.

Mala xkola objektno orijentisanog programiraa

29

Posmatrajmo klasu Vreme kojom emo opisivati trajae odreenih procesa. Vreme moemo definisati uz pomo razliqitih atributa na primer satima,
minutama i sekundama, ili danima, satima, minutama i sekundama i sliqno. Da
bismo xto efektnije prikazali razliqite elemente klase, vreme emo u primeru
koji sledi definisati samo jednim atributom koji predstava broj sekundi.
public class Vreme
{
long sekunde; // ili Int64 sekunde;
public long VratiSate() // broj sati sadrzanih u vremenu
{
return sekunde / 3600;
}
public long VratiMinute() // broj minuta sadrzanih u vremenu
{
return sekunde/60;
}
public long VratiSekunde()
{
return sekunde ;
}
}

Metodi VratiSate() i VratiMinute() raqunaju odreene informacije pa je


razlog ihovog postojaa intuitivno jasan. Postava se pitae zaxto postoji
metoda VratiSekunde() kada broj sekundi sadranih u vremenu opisuje atribut
sekunde. Atribut sekunde je privatni qlan klase pa ne moemo saznati egovu
vrednost van e. Zato uvodimo javni metod VratiSekunde() koji e nam omoguiti pristup toj informaciji. Ovim metodom dobijamo informaciju o broju
sekundi ali je i dae ne moemo promeniti (read-only).
Radi lakxeg pristupa privatnim atributima klase u programskom jeziku
C# moemo kreirati svojstva (property) i ona po potrebi mogu imati sledee
komponente:
get, koja na osnovu vrednosti atributa odreuje i vraa neku karakteristiku objekta (korixeem naredbe return)
set, koja na osnovu zadate vrednosti (value) raquna i postava vrednosti
atributa.
Svojstvo definixemo na sledei naqin:
public <povratni tip svojstva> <ime svojstva>
{
get { <telo get komponente> }
set {<telo set komponente> }
}

Svojstva nisu ni atributi ni metode iako imaju karakteristike i atributa


i metoda. Kao i atributi svojstva nemaju parametre, a u ihovim komponentama,

30

S. Matkovi, M. urixi

kao i u metodama, moe se navesti proizvoan niz naredbi programskog jezika


C#. U get komponenti obavezno je navoee naredbe return kojom se vraa
izraqunata vrednost.
Svojstva se pozivaju navoeem imena objekta za kojim sledi ime svojstva
odvojeno taqkom. Ako se u izrazu poziv svojstva nalazi sa leve strane operatora
dodele, izvrxava se set komponenta svojstva, a u suprotnom izvrxava se get
komponenta.
U klasi Vreme moemo definisati svojstvo Sekunde na sledei naqin:
public long Sekunde
{
get { return sekunde; }
set { sekunde = value; }
}

Komponenta get ovog svojstva ima ekvivalentno dejstvo kao i metoda VratiSekunde(), a set komponenta nam omoguava da postavamo vrednosti privatnom
atributu sekunde. Ovako definisanim svojstvom naruxavamo enkapsulaciju jer
je atribut sekunde postao potpuno dostupan. Samim tim mogli smo definisati
atribut kao javan. U veini sluqajeva potrebno je da van klase moemo proqitati vrednost atributa a da ga ne moemo meati. Tada koristimo svojstvo kod
kojeg nije definisana set komponenta (read only svojstvo, samo za qitae).
public long Sekunde
{
get { return sekunde; }
}

Ukoliko je vrednost atributa ograniqenog opsega, u set komponenti moemo


izvrxiti kontrolu vrednosti koju postavamo. Na primer, ako klasu Vreme opisujemo atributima sat, minut i sekund, moemo proveravati da li je vrednost
koju postavamo za atribute minut i sekund u dozvoenim granicama (od 0 do
59).
Vrlo qesto postoje karakteristike objekta koje zavise i mogu se izraqunati
na osnovu vrednosti atributa. Moemo definisati svojstva kojima odreujemo
vrednost tih karakteristika.
Primetimo da objekte klase Vreme moemo opisati i pomou tri cela broja
koji predstavaju broj sati, minuta (minut<60) i sekundi (sekund<60). Definiximo svojstva Sat, Minut i Sekund koja zadovoavaju jednakost:
Sat*3600+Minut*60+Sekund=sekunde.
public long Sekund
{
get { return sekunde%60; }
}
public long Minut

Mala xkola objektno orijentisanog programiraa

31

{
get { return (sekunde / 60) % 60; }
}
public long Sat
{
get { return sekunde / 3600; }
}

Ova svojstva nam omoguavaju da proqitamo vrednosti Sat, Minut i Sekund.


Bilo bi prirodno da moemo i postaviti ihovu vrednost. Promena vrednosti
svake od ovih karakteristika povlaqi i promenu atributa sekunde, pa moemo
realizovati i odgovarajue set komponente.
public long Sekund
{
get { return sekunde%60; }
set { sekunde = sekunde-Sekund+value; }
}
public long Minut
{
get { return (sekunde / 60) % 60; }
set { sekunde = sekunde-Minut*60+value*60; }
}
public long Sat
{
get { return sekunde / 3600; }
set { sekunde = sekunde - Sat * 3600 + value * 3600; ; }
}

Indekseri
U programskom jeziku C# moemo imati qlanove klase koje zovemo indekserima, koji imaju sliqnosti sa svojstvima ali i svojih specifiqnosti.
Indekser nam omoguava da pojedinim karakteristikama objekata klase pristupamo na efikasan naqin, navoeem imena objekta i u uglastim zagradama
indeksa koji nas upuuje na odgovarajuu karakteristiku. Kao i svojstva, indekseri imaju get i set komponentu u kojima se u zavisnosti od vrednosti indeksa odreuje karakteristika objekta, odnosno postavaju vrednosti atributa.
Za razliku od svojstava indekser ima najmae jedan parametar a moe imati i
vixe parametara, pa objekat dobija vixe dimenzija. Indekser definixemo na
sledei naqin:
public <povratni tip indeksera> this[ <tip indeksa > <ime indeksa>, ...]
{
get { <telo get komponente> }
set {<telo set komponente> }
}

32

S. Matkovi, M. urixi

Indekseru programer ne zadaje ime jer on uvek koristi ime this. Sliqno
metodama, indekseri mogu imati preklopene verzije, koje se moraju razlikovati
po broju ili po tipu indeksa.
Klasu Vreme moemo proxiriti indekserom koji, u zavisnosti od indeksa,
vraa Sat, Minut ili Sekund. Za indeks moemo izabrati: prethodno definisani nabrojivi tip (enum) qije su mogue vrednosti sat, minut i sekund, ili
tip char tako da za vrednosti indeksa redom h, m i s vraa Sat, Minut i
Sekund, ili tip string. U navedenoj realizaciji indeksera koristimo prethodno definisana svojstva. Ovaj indekser mogli smo realizovati i bez korixea
tih svojstava i u tom sluqaju on bi mogao i zameniti ta svojstva. Na sliqan
naqin kako je realizovana set komponenta svojstava Sat, Minut i Sekund moemo
realizovati set komponentu za svaki od navedenih indeksera.
public enum JedinicaVremena
{
sat,
minut,
sekund
};
public long this[JedinicaVremena j]
{
get
{
if (j == JedinicaVremena.sat)
return Sat; // return sekunde / 3600;
if (j == JedinicaVremena.minut)
return Minut; // return (sekunde / 60) % 60
return Sekund;
}
}
public long this[char ch]
{
get
{
if (ch == h)
return Sat;
if (ch == m)
return Minut;
if (ch == s)
return Sekund;
return sekunde;
}
}

Ako je A objekat klase Vreme vrednost izraza A[JedinicaVremena.sat] i


A[h] je broj sati sadranih u vremenu A.

Mala xkola objektno orijentisanog programiraa

33

Konstruktori
U C#-u pri deklaraciji neke instance klase, objekta, rezervixe se prostor
za adresu objekta (referencu) a sam objekat se kreira korixeem operatora
new.
<ime klase> <ime objekta> = new <ime klase>(<lista parametara>) ;

Operator new vraa adresu novog objekta koja se dodeuje imenu objekta.
Konstruktor je metod koji se poziva pri kreirau objekta. Konstruktori su
sastavni deo svake klase i nose eno ime. Pozivom konstruktora objekat poqie
svoj ivot. Klasa moe imati vixe konstruktora koji se razlikuju po listi parametara. Lista parametara najqexe sadri vrednosti kojima inicijalizujemo
atribute objekta, a moe biti i prazna.
Ako pogramer ne napixe ni jedan konstruktor programski prevodilac e
napraviti podrazumevani konstruktor (konstruktor bez parametara, numeriqkim
tipovima dodeuje 0, logiqkim atributima dodeuje vrednost false, referentne
atribute postava na null).
Ako pixemo vixe konstruktora, kako svi imaju ime klase, moraju se razlikovati po listi parametara, tj. po broju ili tipu parametara.
Za klasu Vreme, definisanu u prethodnom delu qlanka, moemo definisati
sledee konstruktore:
Konstruktor bez parametara koji postava atribut sekunde na 0
public Vreme()
{
sekunde = 0;
}

Konstruktor koji za parametar ima inicijalni broj sekundi


public Vreme(long x)
{
sekunde = x;
}

Konstruktor koji za parametar ima broj sati i broj minuta


public Vreme(long h, long m)
{
sekunde = 3600*h+60*m;
}

Konstruktor koji za parametar ima broj sati, minuta i sekundi


public Vreme(long h, long m, long s)
{
sekunde = 3600 * h + 60 * m + s;
}

Konstruktor koji za parametar ima string oblika sati:minuti:sekunde


(ukoliko se ovom konstruktoru prosledi drugaqiji format stringa on atribut sekunde postava na 0)

34

S. Matkovi, M. urixi

public Vreme(string s)
{
try
{
long h = Convert.ToInt64(s.Substring(0, s.IndexOf(:)));
long m = Convert.ToInt64(s.Substring(s.IndexOf(:)
s.LastIndexOf(:)

- s.IndexOf(:)

+ 1,

- 1));

long sek = Convert.ToInt64(s.Substring(s.LastIndexOf(:)+1));


sekunde = 3600 * h + 60 * m + sek;
}
catch
{
sekunde = 0;
}
}

Takozvani konstruktor kopije koji za parametar ima drugi objekat klase


Vreme, v, sekunde postava na vrednost istog atributa parametra v.
public Vreme(Vreme v)
{
sekunde = v.sekunde;
}

Zakuqak
Ovo je prvi u nizu qlanaka koji planiramo, kojima emo pokuxati da profesorima informatike pribliimo objektno orijentisano programirae i jedan
savremeni programski jezik koji se, po naxim dosadaxim iskustvima, vrlo uspexno moe upotrebiti u nastavi, u svim fazama uqea programiraa.
U ovom qlanku smo vas upoznali sa osnovnim elementima klase a planirano
je da u naredna dva obradimo operatore i nasleivae.
Predlaemo qitaocima da sliqno naxem primeru klase Vreme realizuju i
sledee klase:
TackaDekart koja predstava taqku u Dekartovom koordinatnom sistemu za
koju moete definisati svojstva RastojanjeOdCentra, Kvadrant
Krug, zadat sa dve dijametralno suprotne taqke, sa svojstvima Centar i
Poluprecnik
Vektor, zadat jednom taqkom u ravni, sa svojstvima Intezitet, FazniUgao
Za sve tri klase mogue je realizovati i raznovrsne konstruktore, kao i
indeksere.
Za kraj, evo i jednog segmenta koda pokazne aplikacije u kome se moe uoqiti ispravan naqin pozivaa svakog od elemenata klase koju smo kroz qlanak
obradili:

Mala xkola objektno orijentisanog programiraa

//kreiranje objekta uz poziv podrazumevanog konstruktora


Vreme T = new Vreme();
//koriscenje set komponente svojstava Sat, Minut, Sekund
T.Sat = 12;
T.Minut = 70;
T.Sekund = 0;
//koriscenje get komponente indeksera sa enum indeksom
Text=T[JedinicaVremena.sat]+" "+T[JedinicaVremena.minut];
//kreiranje objekta uz poziv konstruktora sa parametrom tipa string
T = new Vreme("12:46:30");
//koriscenje get komponente svojstava Sat, Minut, Sekund
label1.Text = T.Sat + " " + T.Minut + " " + T.Sekund;
//kreiranje objekta uz poziv konstruktora sa parametrom tipa string
T = new Vreme("1:20:4");
//koriscenje get komponente indeksera sa char indeksom
label1.Text += " " + T[h] + " " + T[m] + " " + T[s];

Matematiqka gimnazija, Kraice Natalije 37, Beograd

35

NASTAVA RAQUNARSTVA

Stanka Matkovi, Mijodrag urixi


MALA XKOLA OBJEKTNO ORIJENTISANOG
PROGRAMIRAA U PROGRAMSKOM JEZIKU C#
Drugi deo
Operatori
Kao xto smo naglasili u prethodnom qlanku, metodom opisujemo ponaxae
objekta u odreenoj situaciji i pod odreenim uslovima, odreujemo nove vrednosti na osnovu osobina koje objekat poseduje ali i opisujemo odreene akcije
meu objektima koje za rezultat imaju ili novi objekat ili neku vrednost.
Lako se moe napraviti analogija izmeu ovakvih akcija i matematiqkih
operacija koje definixemo kao preslikavae skupa ureenih n-torki u neki skup
objekata ili vrednosti. U skladu sa tim u veini objektno orijentisanih programskih jezika postoji mogunost definisaa operatora, pre svega da bi se xto
jednostavnije pozivali i xto efektnije koristili takvi metodi.
U C# ne moemo definisati nove operatore ali u svakoj klasi moemo
predefinisati veliki broj postojeih. Predefinisaem operatora u klasi dodeujemo operatoru novo znaqee koje se primeuje kada se operator poziva za
objekte te klase. Ponaxae istog operatora za druge tipove objekata se ne mea.
U tabeli koja sledi navedeni su operatori u C# koji se najqexe predefinixu.
Unitarni operatori

Binarni operatori

+, , !, , ++,

+, , , /, %, &, |,, <<, >>


==, ! =, <, >, <=, >=

Predefinisaem operatora ne moemo promeniti arnost (broj operanada),


prioritet i asocijativnost (grupisae) operatora.
U opxtem sluqaju operator se zapisuje na sledei naqin:
public static <povratni tip> operator <operacijski znak>(<lista parametara>)
<telo operatora>

Slubena req static oznaqava da je operator statiqki qlan klase, xto


znaqi da nije kao ostali (,,ne statik) qlanovi vezan za objekat this ve za samu
klasu. Kada je neki atribut klase static onda postoji samo jedna kopija tog

32

S. Matkovi, M. urixi

atributa koju dele svi objekti te klase. Kada je metod klase static on nije vezan
za konkretni objekat klase, odnosno ne moe koristiti this. Statiqke metode se
koriste da izraqunaju odreene vrednosti a ne da promene stae objekta (Math
klasa u C# sadri statiqke metode Sqrt, Sin, Cos, . . . ). Statiqke qlanove
klase moemo koristiti bez kreiraa objekta.
Operatori su static jer iako se primeuju na objektima klase nisu ihov
sastavni deo niti ihova funkcionalnost ve su funkcionalnost klase. U nekim,
starijim programskim jezicima operatori se vezuju za objekte ali je naqin na
koji su operatori realizovani u C# praktiqniji i prirodniji.
Kod operatora <povratni tip> moe biti bilo koji tip podataka definisan
u C#, sistemski ili od strane korisnika. ime definixemo tip rezultata
operacije realizovane operatorom. Povratni tip ne moe biti void jer operator
mora imati povratnu vrednost.
Slubena req operator zajedno sa operacijskim znakom zapravo predstava
ime metode. Skup moguih vrednosti za <operacijski znak> dat je prethodno
navedenom tabelom. Ukoliko izabrani operacijski znak predstava unarnu operaciju, <lista parametara> sadri samo jedan parametar a ukoliko predstava
binarnu operaciju, <lista parametara> sadri dva parametra meusobno odvojena zarezom. U svakoj <lista parametara> bar jedan od parametara mora biti
objekat klase qiji je operator qlan.
U klasi Razlomak moemo definisati vixe operatora. Navodimo ispravna
zaglava nekih od ih:
public static Razlomak operator +(Razlomak a, Razlomak b)
operator za odreivae zbira razlomaka a i b
public static Razlomak operator *(Razlomak a, Razlomak b)
operator za odreivae proizvoda razlomaka a i b
public static Razlomak operator +(Razlomak a, int b)
operator za odreivae zbira razlomka a i celog broja b
public static Razlomak operator -(Razlomak a)
operator za odreivae razlomka suprotnog znaka od razlomka a
public static Razlomak operator ~(Razlomak a)
operator za odreivae reciproqne vrednosti razlomka a
public static Razlomak operator -(Razlomak a, Razlomak b)
operator za odreivae razlike razlomaka a i b
public static bool operator >(Razlomak a, Razlomak b)
operator za proveru da li je razlomak a vei od razlomka b
U telu operatora mora postojati jedna ili vixe komandi return <izraz>
gde je <izraz> proizvoan izraz tipa <povratni tip>.

Mala xkola objektno orijentisanog programiraa

33

Unarni operatori se pozivaju prefiksno, <operacijski znak><objekat


klase>. Operatori ++ i imaju i postfiksnu notaciju pa se mogu pozivati i postfiksno, <objekat klase><operacijski znak>. Binarni operatori
se pozivaju infiksno <stvarni parametar><operacijski znak><stvarni parametar>.
U sledeem segmentu komandi C# navodimo ispravne pozive operatora klase
Razlomak qija su zaglava prethodno navedena.
Razlomak x = new Razlomak(3, 4);
Razlomak y = new Razlomak(-12, 5);
Razlomak z;
z = x + y;
z = x + 5;
z = ~x;
z = -y;
if (x > y)
z = x

y*z + 3;

else
x += y;

Predefinisaem binarnih operatora +, , , /, %, &, |,, <<, >> automatski


su predefinisani i operator + =, =, =, / =, % =, & =, | =,=, <<=, >>=.
Operatori za poreee moraju biti predefinisani u paru. Ako predefinixemo operator == onda moramo predefinisati i operator ! =. Sliqno i za
operatore <, > i <=, >=.
Klasa Razlomak
Upotrebu operatora ilustrujemo na primeru klase Razlomak, jer su operacije koje se izvode nad skupom razlomaka (racionalnih brojeva) svima bliske a
nijedan programski jezik nema ugraen tip podataka koji predstava razlomak.
Definximo binarni operator + kojim realizujemo operaciju sabiraa dva
Razlomka. Rezultat je, u skladu sa pravilima sabiraa racionalnih brojeva,
takoe Razlomak.
public static Razlomak operator +(Razlomak a, Razlomak b)
{
Razlomak r = new Razlomak();
r.imenilac = a.imenilac * b.imenilac;
r.brojilac = a.brojilac * b.imenilac + b.brojilac * a.imenilac;
r.skrati();
return r;
}

Operacije ne meaju operande ve kreiraju rezultat u zavisnosti od vrednosti operanada. Zato na poqetku metode kreiramo novi Razlomak r koji e

34

S. Matkovi, M. urixi

predstavati rezultat, a egove atribute postavamo u skladu sa matematiqkim


pravilima sabiraa razlomaka. Radi jednostavnije realizacije pri sabirau
ne traimo NZS imenilaca ve operande dovodimo na zajedniqki imenilac koji predstava proizvod polaznih imenilaca, pa izvrximo potrebno sabirae.
Zatim Razlomak r dovodimo u neskrativ oblik, deeem brojioca i imenioca
ihovim NZD, xto je realizovano metodom skrati.
Ako u klasi Razlomak napixemo konstruktor koji na osnovu datog brojioca i
imenioca inicijalizuje atribute objekta tako da on predstava pravi razlomak
(brojilac i imenilac uzajamno prosti brojevi) operator + moemo definisati
na sledei naqin.
public static Razlomak operator +(Razlomak a, Razlomak b)
{
return new
Razlomak(a.brojilac * b.imenilac + b.brojilac * a.imenilac,
a.imenilac * b.imenilac);
}

Operatori kao i sve druge metode mogu se preopteretiti, tako da moemo


pisati vixe operatora istog imena sa razliqitom listom parametara. Prethodno definisanim operatorom realizovana je operacija sabiraa dva razlomka.
Qesto je potrebno i sabirae objekta klase Razlomak i celog broja, pa moemo
definisati operator + sa parametrima redom Razlomak, int kao i operator +
sa parametrima redom int, Razlomak. Prilikom realizacije metoda operator
+(Razlomak a, int b) kreiramo novi razlomak b/1 od celog broja b, a zatim
korixeem operatora + za sabirae dva razlomka saberemo taj razlomak i
razlomak a.
public static Razlomak operator +(Razlomak a, int b)
{
return a + new Razlomak(b,1);
}

Korixeem prethodno definisanog operatora + moemo definisati i sabirae celog broja i objekta klase Razlomak na sledei naqin.
public static Razlomak operator +(int b,Razlomak a)
{
return a + b;
}

Sliqno moemo definisati i ostale operatore za rad sa racionalnim brojevima, oduzimae, mnoee, deee. I te operatore moramo preopteretiti na
sliqan naqin ako elimo da omoguimo izvoee operacija izmeu razlomaka i
celih brojeva.
Deee dva razlomka moemo realizovati kao mnoee razlomka egovom
reciproqnom vrednoxu. Zato je potrebno definisati operator za odreivae
reciproqne vrednosti, to je unarni operator koji jednostavno realizujemo:

Mala xkola objektno orijentisanog programiraa

35

public static Razlomak operator ~(Razlomak a)


{
return new Razlomak(a.imenilac, a.brojilac);
}

Pomou operatora moemo omoguiti i konverziju objekata klase (tipa podataka) koju definixemo u objekte druge klase ili u podatke osnovnog tipa kao
i obrnuto.
Konverzija se definixe kao unarni operator. Ime tog operatora je ime tipa
u koji se vrxi konverzija parametra operatora. Parametar operatora ili tip
u koji se vrxi konverzija, ali ne oba, moraju biti iz klase u kojoj definixemo
konverziju.
Konverzija moe biti implicitna ili eksplicitna. Prilikom raqunaa
vrednosti izraza da bi svi podaci u izrazu bili istog tipa vrxi se automatski
ihova implicitna konverzija (bez eksplicitnog navoee od strane programera). Implicitnom konverzijom ne dolazi do gubitka informacija pa se moe
bezbedno pozivati i bez znaa programera.
Eksplicitnu konverziju programer zahteva dodatnim kodom, korixeem
operatora cast. Prilikom eksplicitne konverzije moe doi do gubitka informacija.
Zaglava implicitnog i eksplicitnog operatora konverzije u C# izgledaju
ovako:
public static implicit operator TipRezultata(TipParametra parametar)
public static explicit operator TipRezultata(TipParametra parametar)

Svaki ceo broj moemo tumaqiti kao racionalan broj pa je mogue definisati implicitnu konverziju iz podatka tipa int u objekat klase Razlomak.
public static implicit operator Razlomak(int i)
{
return new Razlomak(i,1);
}

S druge strane, za svaki razlomak moemo odrediti egovu taqnu ili priblinu decimalnu vrednost, xto znaqqi da pri konverziji iz razlomka u realan
broj moe doi do gubitka informacija. Zato je prirodno definisati eksplicitnu konverziju iz klase Razlomak u osnovni tip double.
public static explicit operator double(Razlomak r)
{
return (double)r.brojilac / r.imenilac;
}

Definisaem operatora implicitne konverzije gubi se potreba za preoptereenim operatorima kojima omoguavamo izvoee operacija izmeu objekata
klase Razlomak i celih brojeva. U sledeem segmentu naredbi C# prikazana je

36

S. Matkovi, M. urixi

upotreba implicitnog i eksplicitnog operatora konverzije. U naredbi c = a +


5 prilikom raqunaa vrednosti izraza ceo broj 5 se automatski (implicitnom
konverzijom) prevodi u razlomak pa se izvrxava operacija sabiraa izmeu dva
razlomka. U naredbi x = (double)a + 5 korixeem cast operatora (double)
Razlomak a se konvertuje eksplicitnom konverzijom u realan broj pa se vrxi
operacija sabiraa izmeu realnih brojeva.
Razlomak a=new Razlomak(3,4), b=new Razlomak(textBox1.Text), c;
double x;
c = a + 5;
x = (double)a + 5;
b = a / 4 - 3;
x = (double)(a + b);

Radi boeg sagledavaa svih komponenti klase Razlomak navodimo celu klasu.
public class Razlomak
{
#region Atributi
int imenilac;
int brojilac;
# endregion
#region Konstruktori
public Razlomak()
{
imenilac = 1;
brojilac = 0;
}
public Razlomak(int br)
{
brojilac = br;
imenilac = 1;
}
public Razlomak(int br, int im)
{
if (im = = 0)
throw new Exception("Greska:
brojilac = br;
imenilac = im;
if (imenilac < 0)
{
brojilac=-brojilac;
imenilac=-imenilac;
}
skrati();

imenilac0");

Mala xkola objektno orijentisanog programiraa

37

}
public Razlomak(string s)
{
int p = s.IndexOf(/);
if (p != -1)
{
brojilac = Convert.ToInt32(s.Substring(0, p));
imenilac = Convert.ToInt32(s.Substring(p + 1));
if (imenilac = = 0) throw new Exception("Greska: imenilac 0");
this.skrati();
}
else
{
brojilac = Convert.ToInt32(s);
imenilac = 1;
}
}
private static int nzd(int a, int b)
{
if (b = = 0)
return a;
return
nzd(b, a % b);
}
private void skrati()
{
int p = nzd(Math.Abs(brojilac), Math.Abs(imenilac));
imenilac /= p;
brojilac /= p;
}
#endregion
#region Operatori
public static Razlomak operator +(Razlomak a, Razlomak b)
{
return new Razlomak(a.brojilac * b.imenilac + b.brojilac * a.imenilac, a.imenilac
* b.imenilac);
}
public static Razlomak operator -(Razlomak a)
{
return new Razlomak(-a.brojilac, a.imenilac);
}
public static Razlomak operator -(Razlomak a, Razlomak b)
{
return a + (-b);
}

38

S. Matkovi, M. urixi

public static Razlomak operator *(Razlomak a, Razlomak b)


{
return new Razlomak(a.brojilac * b.brojilac, a.imenilac * b.imenilac);
}
public static Razlomak operator (Razlomak a)
{
return new Razlomak(a.imenilac, a.brojilac);
}
public static Razlomak operator /(Razlomak a, Razlomak b)
{
return a * b;
}
public static explicit operator double(Razlomak r)
{
return (double)r.brojilac / r.imenilac;
}
public static implicit operator Razlomak(int i)
{
return new Razlomak(i, 1);
}
public static bool operator >(Razlomak A, Razlomak B)
{
return A.brojilac * B.imenilac > B.brojilac * A.imenilac;
}
public static bool operator <(Razlomak A, Razlomak B)
{
return A.brojilac * B.imenilac < B.brojilac * A.imenilac;
}
#endregion
public string UString()
{
if (brojilac = = 0)
return "0";
else
if (imenilac = = 1)
return brojilac + "";
else
return brojilac + "/" + imenilac;
}
}

Klase Vreme, Datum, VremenskiTrenutak


Neka je klasa Vreme definisana kao u prethodnom qlanku (jedan atribut,
sekunde, odgovarajui konstruktori, svojstva, . . . ). Ako posmatramo objekat te

Mala xkola objektno orijentisanog programiraa

39

klase A koji predstava vreme trajaa filma i objekat iste klase B koji predstava vreme trajaa filmskog urnala i reklama, sabiraem ta dva vremena
se moe dobiti vreme trajaa bioskopske projekcije, C. Ako bismo napisali
operator + za klasu Vreme mogli bismo vreme C da odredimo sledeim pozivom
tog operatora:
C = A + B;
Operator sabiraa moemo definisati na sledei naqin:
public static Vreme operator+(Vreme A, Vreme B)
{
return new Vreme(A.sekunde+B.sekunde);
}

Na sliqan naqin moemo definisati i operatore:


public static Vreme operator +(Vreme a,int b)
operator za odreivae zbira vremena a i broja sekundi b
public static Vreme operator -(Vreme a, Vreme b)
operator za odreivae apsolutne razlike vremena a i b
public static bool operator >(Vreme a, Vreme b)
operator za proveru da li vreme a traje due od vremena b
public static bool operator <(Vreme a, Vreme b)
operator za proveru da li vreme a traje krae od vremena b
Klasu Datum moemo realizovati sa tri celobrojna atributa (dan, mesec,
godina) sa odgovarajuim svojstvima i konstruktorima:
public class Datum
{
#region AtributiISvojstva
private int dan, mesec, godina;
public int Dan
{
get { return dan; }
}
public int Mesec
{
get { return mesec; }
}
public int Godina
{
get { return godina; }
}
#endregion

40

S. Matkovi, M. urixi

#region Konstruktori
public Datum()
{
dan = 1;
mesec = 1;
godina = 2010;
}
public Datum(Datum D)
{
godina = D.godina;
mesec = D.mesec;
dan = D.dan;
}
public Datum(string s)
{
dan = Convert.ToInt32(s.Substring(0,s.IndexOf(.)));
s=s.Remove(0, s.IndexOf(.) + 1);
mesec = Convert.ToInt32(s.Substring(0, s.IndexOf(.)));
godina = Convert.ToInt32(s.Substring(s.IndexOf(.) + 1));
}
public Datum(int d, int m, int g)
{
godina = g;
mesec = m;
dan = d;
}
#endregion
. . .
}

U ovako realizovanoj klasi moemo definisati raznovrsne operatore. Jedan od interesantnijih operatora je unarni operator koji obezbeuje prelazak
u sledei dan, odnosno odreivae sutraxeg datuma. Realizovaemo ga kao
operator++:
public static Datum operator ++(Datum D)
{
int d = D.dan + 1;
int m = D.mesec;
int g = D.godina;
// statiqkim metodom brDana(m,g)
// odreujemo broj dana u mesecu m godine g
if (d > brDana(m, g))
{

Mala xkola objektno orijentisanog programiraa

41

d = 1;
m++;
if (m == 13)
{
m = 1;
g++;
}
}
return new Datum(d, m, g);
}

Ovaj operator predefinixe poznati operator uveavaa za 1 iz programskog


jezika C pa je i egovo korixee u skladu sa tim. Naime, ovaj operator kao i
emu srodni operator -- moe se pozivati i u prefiksnoj i u postfiksnoj notaciji. On pri svakom pozivu mea vrednost parametra dodeujui mu povratnu
vrednost ali je vrednost samog izraza <parametar>++ jednaka staroj vrednosti
parametra, dok je vrednost izraza ++<parametar> jednaka novoj vrednosti.
Moemo primetiti da u klasi Datum nema smisla definisati operator kojim
se sabiraju dva objekta klase Datum ali se moe definisati operator kojim se
na objekat klase Datum moe dodati ceo broj dana. Takoe, od datuma moemo
oduzimati izvestan ceo broj dana ali se moe odrediti i broj dana izmeu dva
datuma.
public static Datum operator +(Datum a,int b)
public static Datrum operator -(Datrum a, int b)
public static int operator -(Datum a, Datum b)
Realizaciju ovih operatora prepuxtamo qitaocu.
Smisleno je i predefinisati operatore poreea dva datuma kako bi se
utvrdilo koji je datum pre a koji posle (operatori < i >) kao i da li su dva
datuma ista, odnosno razliqita (== i !=). Predefinisaem operatora == gubimo
egovo uobiqajeno znaqee poreea referenci dva objekta i definixemo novo.
U klasi Datum operatore == i != moemo definisati tako da porede datume po
vrednosti atributa.
public static bool operator==(Datum a, Datum b)
{
return a.godina==b.godina && a.mesec==b.mesec && a.dan==b.dan;
}
public static bool operator!=(Datum a, Datum b)
{
return !(a==b);
}

Kada govorimo o bilo kom dogaaju meu najznaqajnijim informacijama su


informacije koje govore o tome kada se taj dogaaj odvija. Kako bismo takve
informacije precizno zapisali neophodno je da imamo podatke i o datumu i o

42

S. Matkovi, M. urixi

vremenu. Moemo definisati klasu VremenskiTrenutak qije objekte opisuju


atributi D, tipa Datum i V , tipa Vreme. Ova klasa je naroqito interesantna
zbog operatora koje moemo realizovati u oj.
public static VremenskiTrenutak operator +(VremenskiTrenutak a,
Vreme b)
odreivae trenutka koji je za vreme b posle trenutka a
public static Vreme operator -(VremenskiTrenutak a,
VremenskiTrenutak b)
odreivae vremena izmeu dva trenutka
public static VremenskiTrenutak operator -( VremenskiTrenutak a,
Vreme b)
odreivae trenutka koji je za vreme b pre trenutka a
public static bool operator <( VremenskiTrenutak a,
VremenskiTrenutak b)
public static bool operator >(VremenskiTrenutak a,
VremenskiTrenutak b)
public static bool operator ==( VremenskiTrenutak a,
VremenskiTrenutak b)
public static bool operator !=( VremenskiTrenutak a,
VremenskiTrenutak b)
Klase Vreme, Datum i VremenskiTrenutak su vrlo upotrebive u velikom
broju aplikacija ali i kao atributi brojnih sloenijih klasa. Recimo da je
definisana klasa Manifestacija koja za atribute ima naziv, mesto odravaa,
poqetak (tipa VremenskiTrenutak) i duinu trajaa (tipa Vreme). Neka je zadat
raspored korisnika sa vremenom boravka u razliqitim mestima. Moemo kreirati aplikaciju kojom se na osnovu dostupnih informacija moe predloiti
korisniku koje sve manifestacije moe da poseti, tako da ne poremeti svoj raspored. Pri kreirau takve aplikacije definisani operatori bi doprineli jednostavnosti realizacije.
Predlaemo qitaocu da u potpunosti realizuje ove klase sa svim navedenim,
ali i nenavedenim, a smislenim operatorima kao i xto vixe aplikacija u kojima
se korisno mogu upotrebiti.
Klasa Polinom
Ilustrujmo definisae operatora u klasi koja kao atribut ima niz. Posmatrajmo klasu za rad sa polinomima. Polinom moemo opisati stepenom i nizom
koeficijenata, ili nizom monoma kod kojih su koeficijenti razliqiti od nule.
Radi jednostavnije realizacije u navedenoj klasi polinom je opisan stepenom (n)
i nizom koeficijenata (k) tako da i-ti element niza k (k[i]) predstava koeficijent uz i-ti stepen polinoma. U klasi Polinom moemo definisati operatore
(+, -, *, /) za izvoee osnovnih aritmetiqkih operacija nad objektima klase.

Mala xkola objektno orijentisanog programiraa

public class Polinom


{
float[] k;// niz koeficijenata polinoma
int n; // stepen polinoma
// podrazumevani konstruktor za formirae nula polinoma
public Polinom()
{
n = 0;
k = new float[1];
k[0] = 0;
}
// konstruktor kojim se formira polinom stepena n
// sa koeficijentima jednakim 0
public Polinom(int n)
{
this.n = n;
k = new float[n+1];
for(int i=0;i<=n;i++) k[i] = 0;
}
// privatni indekser uveden radi lakseg pristupa koeficijentima polinoma
private float this[int i]
{
get { return k[i]; }
set { k[i] = value; }
}
public static Polinom operator +(Polinom a, Polinom b)
{
Polinom c = new Polinom(Math.Max(a.n, b.n));
for (int i = 0; i <= c.n; i++)
{
//c.k[i] = 0; ovo je ve uraeno konstruktorom
if (i <= a.n) c[i] += a[i]; // c.k[i] += a.k[i];
if (i <= b.n) c[i] += b[i];
}
int n1=c.n;
while (n1 > 0 && c[n1] = = 0) n1--;
c.n = n1;
return c;
}
public static Polinom operator *(Polinom a, Polinom b)
{
Polinom c = new Polinom(a.n + b.n);
for (int i = 0; i <= a.n; i++)
for (int j = 0; j <= b.n; j++)
c[i + j] += a[i] * b[j];

43

44

S. Matkovi, M. urixi

return c;
}
}

Navodimo nekoliko interesantnih klasa na kojima moemo ilustrovati operatore:


klasa za rad sa kompleksnim brojevima (obezbediti i grafiqki prikaz objekta klase). U okviru te klase mogu se realizovati operatori za sabirae, oduzimae, mnoee, deee dva kompleksna broja, odreivae konjugovanog
kompleksnog broja (unarni operator npr. ), odreivae modula kompleksnog
broja, operator implicitne konverzije iz realnog u kompleksni broj.
klasa za rad sa vektorima (obezbediti i grafiqki prikaz objekata klase)
klasa kojom realizujemo aritmetiku velikih brojeva (brojeva sa proizvono
mnogo cifara). Mogu se postepeno razvijati klase za rad sa velikim brojevima polazei od prirodnih brojeva, zatim razvoj klase za rad sa celim
brojevima i na kraju sa velikim realnim brojevima. Veliki ceo broj moemo
opisati znakom i nizom cifara (znak i apsolutna vrednost broja), a moemo
i nizom cifara koji predstava zapis broja u potpunom komplementu osnove
10. U ovim klasama prirodno je realizovati sve aritmetiqke operatore kao
i operatore poreea.
klasa za rad sa skupovima (realizovati operatore unija, presek, razlika).
Matematiqka gimnazija, Kraice Natalije 37, Beograd

NASTAVA RAQUNARSTVA

Stanka Matkovi, Mijodrag urixi


MALA XKOLA OBJEKTNO ORIJENTISANOG
PROGRAMIRAA U PROGRAMSKOM JEZIKU C#
Trei deo

Nasleivae prvi deo


Nasleivae je jox jedna vana osobina objektno orijentisanih programskih
jezika. Ona je posledica generalizacije kao metoda za modelovae objekata.
Setimo se primera nastavnog procesa iz prvog dela ,,Male xkole OOP u
programskom jeziku C#. U nastavnom procesu uqestvuju uqenici, profesori,
psiholog, direktor, . . . Svi oni imaju neke zajedniqke karakteristike ali i svoje specifiqnosti. Svi uqesnici u nastavnom procesu imaju svoje ime, prezime,
datum i mesto roea, adresu stanovaa, . . . Generalizacijom dolazimo do klase
(nazovimo je Osoba) koja objediuje zajedniqke osobine i zajedniqke funkcionalnosti svih posebnih grupa koje uqestvuju u nastavnom procesu.
Svaka grupa ima i svoje specifiqne osobine, kao i specifiqno ponaxae u
nastavnom procesu. Za uqenika su, pored karakteristika opisanih klasom Osoba,
vane i informacije o razredu koji pohaa, o predmetima koje sluxa, o rezultatima koje postie ali i akcije koje izvodi u nastavnom procesu (uqi lekciju, radi
pismeni zadatak, odgovara, . . . ). Sliqno, za profesora moemo uoqiti niz dodatnih karakteristika (predmete koje predaje, godine staa, platni razred, . . . )
kao i niz specifiqnih funkcionalnosti u nastavnom procesu (predaje lekciju,
oceuje, . . . ). Operaciju izvoea posebnih klasa iz opxte (generalizovane)
klase zovemo specijalizacija.
Klase dobijene specijalizacijom, osim xto nasleuju sve qlanove (atribute
i metode) polazne klase, definixu i nove, specifiqne qlanove. Polaznu klasu
zovemo osnovna klasa (roditeska klasa, nadklasa), a klasu koja je nasleuje
zovemo izvedena klasa (podklasa).
U izvedenoj klasi definixemo samo atribute i metode specifiqne za tu klasu (eventualno predefinixemo metode osnovne klase) ali eni objekti nasleuju
i sve qlanove osnovne klase. Izvedena klasa proxiruje, a u nekim sluqajevima
i precizira osnovnu klasu.
U definiciji izvedene klase posle navoea imena klase navodimo : a
zatim sledi ime osnovne klase iz koje je izvedena.

Mala xkola objektno orijentisanog programiraa

43

class <imeIzvedeneKlase>:<imeOsnovneKlase>
{
opis / definicija
clanova klase
}

U programskom jeziku C# klasa moe naslediti samo jednu osnovnu klasu,


odnosno ne moe nastati kao specijalizacija dve ili vixe klasa. Takoe, izvedena klasa ne moe naslediti klasu koja sadri modifikator sealed. Ako elimo
da definixemo klasu iz koje se ne mogu izvoditi druge klase modifikator sealed
navodimo u zaglavu klase ispred slubene reqi class.
Vano je napomenuti da u izvedenoj klasi, bez obzira xto nasleuje sve qlanove osnovne klase, ne moemo pristupiti privatnim qlanovima osnovne klase.
Da se ne bi naruxila enkapsulacija atributi osnovne klase ne treba da budu
javni a ako su privatni onda im se ne moe pristupiti iz izvedene klase. Zato
postoji i trei nivo pristupa qlanovima klase zaxtieni (engl. protected).
Zaxtieni qlanovi klase dostupni su u klasi u kojoj su definisani i u svim
klasama izvedenim iz te klase, a izvan ih nisu. Prema tome, iz izvedene klase moe se pristupiti javnim i zaxtienim qlanovima osnovne klase, ali ne i
privatnim.
Da bi bio kreiran objekat izvedene klase mora se prvo kreirati egov osnovni, bazni deo sa atributima definisanim u osnovnoj klasi. Za kreirae objekta
osnovne klase zaduen je konstruktor osnovne klase. Zato se u konstruktoru izvedene klase implicitno (automatski) poziva konstruktor bez argumenata osnovne
klase osim ako programer eksplicitno ne navede koji konstruktor osnovne klase
poziva prilikom kreiraa objekta. Poziv konstruktora osnovne klase programer
realizuje tako xto posle potpisa konstruktora izvedene klase navede dve taqke
(:) a zatim slubenu req base i u zagradama redom parametre konstruktora
osnovne klase kojeg pozivamo.
public class Osnovna {
// ....
public Osnovna()
{
// ....
}
public Osnovna(int x)
{
// ....
}
//...
}
public class Izvedena:Osnovna
{
// ....
public Izvedena()

44

S. Matkovi, M. urixi

{
//....
}
public Izvedena(int a,int s):base(a)
{
// ...
}
//...
}

Izvedena klasa je nasleivaem dobila sve atribute i metode osnovne klase


pa objekat izvedene klase sadri sve qlanove kao i objekat osnovne klase. Zato se
objekat izvedene klase, bez eksplicitne konverzije, moe dodeliti promenivoj
osnovne klase. Obrnuto nije dozvoeno jer objekat osnovne klase ne sadri sve
elemente izvedene klase. Vano je istai da preko promenive osnovne klase
kojoj smo dodelili objekat izvedene klase moemo pozivati samo qlanove osnovne
klase.
Ako su A i B promenive, redom osnovne i izvedene klase, dozvoena je
dodela A = B. Posle te dodele preko promenive A moemo pozivati samo
qlanove osnovne klase. Nije dozvoena dodela B = A jer je A promeniva
osnovne klase (sadri samo qlanove osnovne klase) pa specifiqni qlanovi koje bi
trebalo da ima objekat izvedene klase, B, ne mogu biti definisani tom dodelom.
U izvedenoj klasi moemo, osim potpuno novih metoda, definisati i metode
koje po imenu, povratnom tipu i po argumentima (po tipu, broju i redosledu
argumenata) odgovaraju metodima osnovne klase. Moemo rei da ti metodi u
izvedenoj klasi ,,kriju odgovarajue metode osnovne klase. Skrivenom qlanu
osnovne klase u izvedenoj klasi moemo pristupiti samo ako ispred imena qlana
dodamo slubenu req base i taqku (.).
public class Osnovna
{
// ....
public void radi()
{
// ....
}
public string pisi()
{
// ....
}
//...
}
public class Izvedena:Osnovna
{
// ....

Mala xkola objektno orijentisanog programiraa

45

new public void radi()


{
base.radi();
//....
}
public string pisi()
{
return base.pisi()+...;
}
//...
}

Ako u izvedenoj klasi definixemo metod istog zaglava kao u osnovnoj klasi
(sa ili bez modifikatora new ispred zaglava) onda taj metod moemo pozvati
samo kao metod promenive izvedene klase (new se navodi da bi se kompajaleru
stavilo do znaa da smo namerno, a ne sluqajno, zaklonili metodu bazne klase;
ako se ne navede, kompajler upozorava programera).
Izvedena B = new Izvedena();
Text=B.Pisi(); B.radi();//pozivaju se metodi klase Izvedena

Ako objekat deklarixemo kao objekat osnovne klase pozivom metoda emo
pristupati metodu osnovne klase qak iako objekat kreiramo kao objekat izvedene
klase.
Osnovna A = new Izvedena();
A.radi();//poziva se metod klase Osnovna

Qesto se dexava da metode imaju istu svrhu ali se razliqitio realizuju


u razliqitim izvedenim klasama. U klasama izvedenim iz klase Osoba metod
za prikaz informacija o osobi razliqito se realizuje jer u svakoj klasi imamo
dodatne informacije, a metod za proveru da li je osoba starija od druge osobe
ili metod za promenu adrese osobe u svim klasama se realizuju na isti naqin.
Da bismo mogli predefinisati metod u izvedenoj potrebno je u osnovnoj klasi
proglasiti metod virtuelnim, navoeem slubene reqi virtual u zaglavu
metoda, pre navoea povratnog tipa metoda. U izvedenoj klasi pri definiciji
predefinisanog metoda treba navesti slubenu req override.
public class Osnovna
{
// ....
public virtual void radi()
{
// ....
}
public virtual string pisi()
{

46

S. Matkovi, M. urixi

// ....
}
//...
}
public class Izvedena:Osnovna
{
// ....
public override void radi()
{
//....
}
//...
}

Poziv virtuelnog metoda se vrxi na osnovu tipa objekta koji promeniva


sadri a ne na osnovu tipa promenive.
Osnovna A = new Izvedena();
A.radi();//poziva se metod klase Izvedena

Predefinisae virtuelnih metoda u jednoj ili vixe izvedenih klasa moe


biti izostaveno. Tada se za objekte tih klasa poziva odgovarajui metod iz
klase koja je u hijerarhiji klasa najblia klasi objekta.
Osnovna A = new Izvedena();
Text=A.pisi();//poziva se metod klase Osnovna

Izbor virtuelnog metoda koji se poziva vrxi se u toku izvrxavaa, a ne u


toku prevoea, korixeem tehnike dinamiqkog povezivaa.
Metod ToString() je virtuelni metod klase object koja je osnovna klasa za
sve klase realizovane u C#. Zato u svakoj C# klasi imamo mogunost predefinisaa ovog metoda. Ako ga ne predefinixemo, virtuelni metod klase object
vraa pun naziv klase u kojoj je objekat kreiran.
Virtuelne metode omoguavaju da promeniva osnovne klase, u zavisnosti
od klase qiji joj je objekat dodeen, isti metod izvrxava na razliqite naqine (korixeem predefinisanog (engl. override) metoda iz izvedene klase kojoj
objekat pripada). Tu osobinu objektno orijentisanog programiraa zovemo polimorfizam (pojavivae u vixe oblika).
Osnovna A = new Osnovna();
A.radi();//poziva se metod klase Osnovna
A = new Izvedena();
A.radi();//poziva se metod klase Izvedena

Promeniva A je promeniva klase Osnovna. Kada joj dodelimo objekat


iste klase poziv metoda A.radi() izvrxava virtuelni metod radi() iz klase
Osnovna. Kada promenivoj A dodelimo objekat klase Izvedena istim pozivom
izvrxava se predefinisani (override) metod radi() iz klase Izvedena.

Mala xkola objektno orijentisanog programiraa

47

Zahvaujui polimorfizmu moemo jednostavno kreirati aplikacije koje


rade na razliqitom hardveru i u razliqitim operativnim sistemima. Programer moe pozivati odreene metode bez osvrtaa na naqin ihove realizacije.
Zamislimo da iz aplikacije treba xtampati dokument. Programer e pri kodirau pozvati odgovarajui metod (recimo Print) aktivnog xtampaqa bez obzira
koji je model u pitau. Taj metod je razliqito realizovan za svaki model ponaosob, ali programer ne mora da razmixa o naqinu realizacije jer je svaki
xtampaq objekat neke od izvedenih klasa iz osnovne klase (npr. Printer). U
osnovnoj klasi je definisana virtuelna metoda Print koja je u izvedenim klasama predefinisana.
Primer 1. Osoba
U ovom primeru navexemo uproxenu realizaciju osnovne klase Osoba i
izvedenih klasa Ucenik i Profesor, i jednu jednostavnu aplikaciju kao ilustraciju prethodnog teksta. Sledei dijagram prikazuje hijerarhiju klasa u
primeru:

U realizaciji navedenih klasa, koja sledi, komentarima su objaxeni delovi koda koji se odnose na nasleivae.
public class Osoba//osnovna klasa
{
string ime, prezime;
int brGodina;
string adresa;
public Osoba (string ime, string prezime,int brGodina, string adresa)
{
this.ime = ime;
this.prezime = prezime;
this.brGodina = brGodina;
this.adresa = adresa;
}
public Osoba()
{
ime = prezime =adresa="";
brGodina = 0;
}
public Osoba(Osoba X)

48

S. Matkovi, M. urixi

{
ime = X.ime;
prezime = X.prezime;
brGodina = X.brGodina;
adresa = X.adresa;
}
// virtuelna metoda
public virtual string informacije()
{
return ime + " " + prezime;
}
// nema potrebe da metodi koji slede budu virtuelni
//jer se jednako realizuju kod svih osoba
public bool starijaOd(Osoba B)
{
return brGodina > B.brGodina;
}
public void promenaAdrese( string novaAdresa)
{
adresa = novaAdresa;
}
}
public class Ucenik :

Osoba

{
int razred;
int []ocene;
public Ucenik():base()
// nije neophodno eksplicitno pozvati konstruktor bazne klase,
// jer ako ne pozovemo nijedan konstruktor bazne klase automatski se
// poziva podrazumevani konstruktor, tj. konstruktor bez argumenata
{
razred = 1;
ocene=newint[15];
}
public Ucenik(string uIme, string uPrezime, int uBrGod, string uAdresa, int uRaz)
:

base(uIme, uPrezime,uBrGod,uAdresa)

//poziv odgovarajuceg baznog konstruktora


{
razred = uRaz;
ocene = newint[15];
}
public Ucenik(Ucenik U)
:

base(U)

// base(U) poziv konstruktora kopije bazne klase


// bez obzira sto je parametar konstruktora kopije bazne klase promenljiva tipa

Mala xkola objektno orijentisanog programiraa

// Osoba, poziv konstruktora kopije klase Osobe sa argumentom U koji je objekat


// izvedene klase Ucenik je ispravno jer je dozvoljeno promenljivoj bazne
// klase dodeliti objekat izvedene klase
{
razred = U.razred;
ocene=newint [U.ocene.Length];
for (int i = 0; i < U.ocene.Length; i++) ocene[i] = U.ocene[i];
}
//predefinisanje viruelnog metoda
public override string informacije()
{
returnbase.

informacije ()+ " " + razred;

//poziva se metod osnovne klase


}
}
public class RedovanUcenik :

Ucenik

{
char odeljenje;
int brojIzostanaka; public RedovanUcenik():
base()
{
odeee = ;
brojIzostanaka = 0;
}
public RedovanUcenik(string rIme, string rPrezime, int rBrGod,
string rAdresa, int rRaz,char rOdeljenje)
:

base(rIme,rPrezime,rBrGod,rAdresa,rRaz)

{
odeljenje = rOdeljenje;
brojIzostanaka =0;
}
public RedovanUcenik(RedovanUcenik r):

base(r)

{
odeljenje = r.odeljenje;
brojIzostanaka = r.brojIzostanaka;
}
public override string informacije()
{
returnbase.

informacije ()+" "+odeljenje+" "+brojIzostanaka;

//bazna klasa za klasu RedovanUcenik je klasa Ucenik


}
// Mozemo dodati metode karakteristicne za redovnog ucenika
// na primer ocenjivanje ucenika, dodavanje izostanaka, izracunavanje proseka
}
public class VanredanUcenik :

Ucenik

49

50

S. Matkovi, M. urixi

{
DateTime []datumPolagaa;
public VanredanUcenik():

base()

{
datumPolaganja=new DateTime[15];
}
public VanredanUcenik(string vIme, string vPrezime, int vBrGod,
string vAdresa, int vRaz)
:

base(vIme, vPrezime,vBrGod, vAdresa, vRaz)


{
datumPolaganja=new DateTime[15];
}

public VanredanUcenik(VanredanUcenik V)
:

base(V)
{
datumPolaganja = new DateTime[V.datumPolaganja.Length];
for (int i = 0; i < V.datumPolaganja.Length; i++)
datumPolaganja[i] = V.datumPolaganja[i];
}

// Mozemo dodati metode karakteristicne za vanrednog ucenika,


// na primer unos ocene ucenika
}
public class Profesor:Osoba
{
string predmet;
float koeficijent;
public Profesor()
{
predmet="";
koeficijent=0;
}
public Profesor (string ime, string prezime, int brGod,
string adresa,stringpredmet,float koeficijent)
:

base(ime, prezime, brGod,adresa)


{
this.predmet = predmet;
this.koeficijent = koeficijent;
}
public Profesor (Profesor z) :

base(z)

{
this.predmet = z.predmet;
this.koeficijent = z.koeficijent;
}
public override string informacije ()
{

Mala xkola objektno orijentisanog programiraa

51

returnbase. informacije () + " " + predmet + " " + koeficijent;


}
// Mozemo dodati jos metoda karakteristicnih za profesora
}

Sledi jednostavna aplikacija u kojoj koristimo prethodno realizovane klase. U fajlu skola.txt nalaze se informacije o uqesnicima nastavnog procesa u
nekoj xkoli (najvixe 1000 uqesnika). Za svakog uqesnika u jednoj liniji je data informacija o vrsti tog uqesnika (da li je redovan uqenik, vanredan uqenik
ili profesor), a zatim sve potrebne informacije o emu (svaka informacija u
posebnoj liniji). Aplikacijom je obezbeen prikaz informacija o svim uqesnicima nastavnog procesa te xkole qije ime ili prezime, u zavisnosti od izbora
korisnika, poqie datim stringom. Obezbeen je i ispis imena i prezimena
najstarije osobe meu prikazanim osobama.

Sve uqesnike nastavnog procesa, bez obzira xto pripadaju razliqitim klasama, moemo objediniti korixeem niza a promenivih osnovne klase Osoba.
Dozvoeno je promenivoj osnovne klase dodeliti objekat izvedene klase, tako
da svakom elementu niza amoemo dodeliti objekte klase RedovanUcenik, VanredanUcenik, Profesor.
Osoba[] a = new Osoba[1000];
int n = 0;
Osoba citajOsobu(StreamReader sr)
{
string vrsta = sr.ReadLine();
Osoba A;
string ime, prezime,adresa;
int brGod;
ime = sr.ReadLine();
prezime=sr.ReadLine();

52

S. Matkovi, M. urixi

brGod=Convert.ToInt32(sr.ReadLine());
adresa=sr.ReadLine();
if (vrsta == "redovan ucenik")
A = new RedovanUcenik(ime, prezime, brGod, adresa,
Convert.ToInt32(sr.ReadLine()), sr.ReadLine()[0]);
elseif (vrsta == "vanredan ucenik")
A = new VanredanUcenik(ime, prezime, brGod,adresa,
Convert.ToInt32(sr.ReadLine()));
else
A = new Profesor(ime, prezime, brGod, adresa,
sr.ReadLine(),Convert.ToSingle(sr.ReadLine()));
return A;
}
private void Form1 Load(object sender, EventArgs e)
{
StreamReader sr = new StreamReader("skola.txt");
Osoba max = null;
while (!sr.EndOfStream)
{
a[n] = citajOsobu(sr);
lbSpisak.Items.Add(a[n].informacije());
// metod informacije() je virtuelni i u svakoj izvedenoj klasi je predefinisan
// pa se u zavisnosti od objekta koji se nalazi u promenljivoj a[n] poziva metod
// informacije() iz odgovaraju
ce klase
if (max == null || a[n].starijaOd(max))
//poziv metoda starijaOd definisanog u klasi Osoba
max = a[n];
n++;
}
sr.Close();
if (max != null)
{
lbSpisak.Items.Add("* * * * * * * *");
lbSpisak.Items.Add("najstarija osoba je ");
lbSpisak.Items.Add(max.Ime+ " "+max.Prezime);
}
}
private void tbIme TextChanged(object sender, EventArgs e)
{
string s = tbIme.Text.ToLower();
lbSpisak.Items.Clear();
Osoba max = null;
for (int i = 0; i < n; i++)
{
if((rbIme.Checked && a[i].Ime.ToLower().StartsWith(s))||

Mala xkola objektno orijentisanog programiraa

(rbPrezime.Checked && a[i].Prezime.ToLower().StartsWith(s)))


// koriscenje svojstava Ime i Prezime definisanih u klasi Osoba
{
lbSpisak.Items.Add(a[i].informacije());
// poziv metoda informacije() iz odgovarajuce klase
if (max == null || a[i].starijaOd(max))
//poziv metoda starijaOd definisanog u klasi Osoba
max = a[i];
}
}
if (max != null)
{
lbSpisak.Items.Add("* * * * * * * *");
lbSpisak.Items.Add("najstarija osoba je ");
lbSpisak.Items.Add(max.Ime + " " + max.Prezime);
}
}
Matematiqka gimnazija, Kraice Natalije 37, Beograd

53

NASTAVA RAQUNARSTVA

Stanka Matkovi, Mijodrag urixi


MALA XKOLA OBJEKTNO ORIJENTISANOG
PROGRAMIRAA U PROGRAMSKOM JEZIKU C#
Qetvrti deo

Nasleivae, drugi deo apstraktne klase


U posledem primeru qlanka iz prethodnog broja mogli smo zakuqiti da
je svaki uqesnik nastavnog procesa objekat neke od klasa Ucenik ili Profesor.
Ne postoji uqesnik nastavnog procesa koji je objekat klase Osoba, pa moemo
rei da klasa Osoba samo postoji da bi objedinila zajedniqke karakteristike i
funkcionalnosti objekata izvedenih klasa.
Pri procesu generalizacije, izdvajaem zajedniqkih osobina i funkcionalnosti nekoliko srodnih klasa, moemo kreirati klasu na vixem nivou apstrakcije koja se ne materijalizuje kroz objekte (ne kreiramo ene objekte). Takvu
klasu zovemo apstraktnom klasom. Pri enoj definiciji neophodno je pre imena
klase navesti modifikator abstract.
abstract public class Osnovna
{
//
clanovi klase
}

Apstraktna klasa je nepotpuna. Neophodno je iz e izvoditi klase qije


emo objekte kreirati i definisati ihovo ponaxae. U apstraktnoj klasi
navodimo zajedniqke funkcionalnosti svih izvedenih klasa, koje u izvedenim
klasama moemo predefinisati. Naravno, svaka od izvedenih klasa moe imati
neke svoje specifiqne funkcionalnosti.
Vrlo qesto u klasi koja je dobijena generalizacijom ne moemo realizovati
zajedniqku funkcionalnost koju svaka od izvedenih klasa ima ali se u svakoj od
ih realizuje na razliqit naqin. Polazei od oblika poput kruga, pravougaonika, kvadrata, trougla generalizacijom dolazimo do klase Oblik, a specijalizacojom iz te klase razvijamo klase Krug, Kvadrat, Pravougaonik, Trougao. Svaki
oblik se moe nacrtati, i za svaki oblik moemo izraqunati obim i povrxinu,
ali u klasi Oblik ne moemo realizovati te metode. Potrebno je da klasa Oblik ima te funcionalnosti da bi, korixeem polimorfizma, svakom elementu

Mala xkola objektno orijentisanog programiraa

33

skupa razliqitih oblika mogli uputiti zahtev da ih izvrxi. Svaki element e


na zahtev (Crtaj, Povrsina, Obim) odgovoriti na sebi svojstven naqin.
Metod apstraktne klase za koji dajemo samo deklaraciju a ne i definiciju,
naziva se apstraktni metod. Apstraktni metod pixemo navoeem modifikatora
abstract ispred deklaracije metoda koju zavrxavamo taqka zarezom. Pri deklaraciji apstraktnog svojstva moramo navesti da li je to get i/ili set svojstvo.
abstract public povratniTip imeMetoda(listaParametara);
abstract public povratniTip imeSvojstva
{
get;
set;
}

U klasama koje su izvedene iz apstraktne klase pri realizaciji apstraktnih


qlanova modifikator abstract zameujemo slubenom reqi override. Ako u
izvedenoj klasi nismo realizovali sve apstraktne qlanove i ta izvedena klasa je
apstraktna pa je potrebno pri enoj definiciji navesti modifikator abstract.
Primer 2. Oblik.
Navodimo realizaciju apstraktne klase Oblik i iz e izvedenih klasa Krug,
Pravougaonik, Kvadrat i JednakostranicniTrougao. Posmatramo pojednostavene oblike, kod kvadrata i pravougaonika stranice su paralelene koordinatnim
osama, a kod jednakostraniqnog trougla jedna stranica je paralelna x-osi.

U osnovnoj klasi Oblik definixemo zajedniqke (centar i boju oblika) a u izvedenim klasama dodatne atribute. Svi oblici imaju sledee funkcionalnosti:
odreivae obima, odreivae povrxine, crtae, provera da li oblik sadri
datu taqku i pomerae oblika za date vrednosti po x i y osi. Samo posleda
od navedenih funkcionalnosti realizuje se na isti naqin u svim klasama, pomeraem centra oblika za date vrednosti. Zato taj metod realizujemo u osnovnoj
klasi i nema potrebe da ga u izvedenim klasama predefinixemo. Ostale finkcionalnosti (crtaj, obim, povrsina, sadrzi) ne moemo realizovati u osnovnoj
klasi dok ne konkretizujemo oblik. Zato su u klasi Oblik ove funkcionalnosti
apstraktne, a ihova realizacija se nalazi u izvedenim klasama.

34

S. Matkovi, M. urixi

Napomenimo da je kvadrat pravougaonik kod kojeg duina i xirina imaju


iste vrednosti, pa u skladu sa tim klasu Kvadrat dobijamo specijalizacijom iz
klase Pravougaonik.
public abstract class Oblik
{
protected Color boja;
protected PointF centar;
public Oblik(Color boja, PointF centar)
{
this.boja = boja;
this.centar = centar;
}
public Oblik()
{
this.boja = Color.Black;
this.centar = new PointF(0, 0);
}
public void Pomeri(int dx, int dy)
{
centar.X += dx;
centar.Y += dy;
}
// apstraktna get svojstva za odredivanje
obima i povrsine
public abstract float Obim
{ get; }
public abstract float Povrsina
{ get; }
// apstraktni metod za crtanje oblika
public abstract void Crtaj(Graphics g);
// apstraktni metod za proveru da li oblik sadr
zi datu ta
cku
public abstract bool SadrziTacku(PointF A );
}
public class Krug : Oblik
{
float r;
public Krug(Color boja, PointF centar, float r):base(boja, centar)
{
this.r = r;
}
public Krug():base()
{
this.r = 10;
}
public override void Crtaj(Graphics g)
{
g.FillEllipse(newSolidBrush(base.boja), base.centar.X - r, base.centar.Y - r,
2 * r, 2 * r);
}
public override float Povrsina
{
get { return r * r * (float)Math.PI; }
}
public override float Obim
{
get { return 2 * r * (float)Math.PI; }
}
public override bool SadrziTacku(PointF M)
{

Mala xkola objektno orijentisanog programiraa

35

return Math.Sqrt((M.X - centar.X) * (M.X - centar.X) + (M.Y - centar.Y) *


(M.Y - centar.Y)) <= r;
}
}
public class JednakostranicniTrougao : Oblik
{
float a;
public JednakostranicniTrougao(Color boja, PointF centar,float a) : base(boja,
centar)
{
this.a = a;
}
public JednakostranicniTrougao() : base()
{
this.a = 10;
}
public override void Crtaj(Graphics g)
{
PointF[] teme = newPointF[3];
float h=a*(float)Math.Sqrt(3) /2;
teme[0] = new PointF(centar.X - a / 2, centar.Y + h / 3);
teme[1] = new PointF(centar.X + a / 2, centar.Y + h / 3);
teme[2] = new PointF(centar.X, centar.Y - 2*h / 3);
g.FillPolygon(newSolidBrush(boja), teme);
}
public override float Povrsina
{
get { return a * a * (float)Math.Sqrt(3) / 4; }
}
public override float Obim
{
get { return 3 * a; }
}
/*Proveru da li trougao sadr
zi ta
cku M vrsimo tako sto proverimo da li su ta
cka M i centar
trougla sa iste strane svake od pravih odredenih
temenima trougla A i B, A i C, B i C. U takvom
resenju nismo koristili
cinjenicu da je jedna stranica trougla paralelna x osi, pa se ovo resenje
mo
ze lako uopstiti za proveru pripadnosti ta
cke proizvoljnom trouglu.*/
public override bool SadrziTacku(PointF M)
{
PointF A, B, C;
float h = a * (float)Math.Sqrt(3) / 2;
A = new PointF(centar.X - a / 2, centar.Y + h / 3);
B = new PointF(centar.X + a / 2, centar.Y + h / 3);
C = new PointF(centar.X, centar.Y - 2 * h / 3);
return SaIsteStranePrave(A, B, M, centar) && SaIsteStranePrave(B, C, M, centar)
&& SaIsteStranePrave(A, C, M, centar);
}
private static bool SaIsteStranePrave(PointF A, PointF B, PointF M, PointF N)
{
float a = B.Y - A.Y;
float b = -(B.X - A.X);
float c = -A.X * (B.Y - A.Y) + A.Y * (B.X - A.X);
returnf(a, b, c, M) * f(a, b, c, N) >= 0;
}
private static floatf(float a, float b, float c, PointF T)
{
return a * T.X + b * T.Y + c;
}
}

36

S. Matkovi, M. urixi

public class Pravougaonik : Oblik


{
protectedfloat a, b;
public Pravougaonik(Color boja, PointF centar, float a, float b) : base(boja,
centar)
{
this.a = a;
this.b = b;
}
public Pravougaonik() : base()
{
this.a = this.b = 10;
}
public override void Crtaj(Graphics g)
{
g.FillRectangle(newSolidBrush(base.boja), centar.X-a/2,centar.Y-b/2,a,b);
}
public override float Povrsina
{
get return a * b;
}
public override float Obim
{
get { return 2 * a + 2 * b; }
}
public override bool SadrziTacku(PointF M)
{
return(M.X >= centar.X - a / 2)&&(M.X <= centar.X + a / 2)
&&(M.Y >= centar.Y - b / 2)&&(M.Y <= centar.Y + b / 2);
}
}
public class Kvadrat : Pravougaonik
{
public Kvadrat(Color boja, PointF centar, float a) : base(boja,centar, a, a)
{ }
public Kvadrat() : base()
{ }
}

Sledi aplikacija u kojoj na sluqajan naqin generixemo n oblika, prikazujemo generisane oblike i obezbeujemo pomerae prevlaqeem mixa onih oblika
koji sadre taqku na kojoj smo pritisnuli taster mixa.
Generisane oblike pamtimo nizom o qiji su elementi klase Oblik. Klasa Oblik je osnovna klasa pa elementi niza o mogu biti objekti svih izvedenih klasa iz
klase Oblik. Prilikom crtaa oblika i provere da li oblik sadri datu taqku
ostvaruje se polimorfizam. Za svaki element niza na isti naqin pozivamo metod
za crtae o[i].Crtaj(e.Graphics), pri qemu se poziva predefinisani metod iz
odgovarajue klase u zavisnosti od oblika koji element o[i] sadri (Krug, Pravouganik, JednakostranicniTrougao, Kvadrat). Sliqno vai i pri pozivu
metoda za proveru da li oblik sadri datu taqku, o[i].SadrziTacku(A).
Oblik[] o;
int n;
Random R = new Random();
bool[] pomeraj;
float x=-1, y=-1;

Mala xkola objektno orijentisanog programiraa

37

private void pictureBox1 Paint(object sender, PaintEventArgs e)


{
for (int i = 0; i < n; i++)
o[i].Crtaj(e.Graphics);
}
private void numericUpDown1 ValueChanged(object sender, EventArgs e)
{
n = (int)numericUpDown1.Value;
o = newOblik[n];
for (int i = 0; i < n; i++)
{
int t = R.Next(1, 5);
Color boja = Color.FromArgb(R.Next(200, 256), R.Next(256), R.Next(256), R.Next(256));
PointFP=newPointF(R.Next(0,ClientRectangle.Width),R.Next(0,ClientRectangle.Height));
switch (t)
{
case 1:
o[i] = newKrug(boja, P,R.Next(10,20)); break;
case 2:
o[i] = newJednakostranicniTrougao(boja, P, R.Next(20,50)); break;
case 3:
o[i] = newPravougaonik(boja,P, R.Next(10,50),R.Next(10,50)); break;
case 4:
o[i] = newKvadrat(boja, P, R.Next(10, 50)); break;
}
}
pictureBox1.Refresh();
// aktivira metodu pictureBox1 Paint
}
private void pictureBox1 MouseDown(object sender, MouseEventArgs e)
{
x = e.X;
y = e.Y;
PointF A = new PointF(e.X, e.Y);
pomeraj = newbool[n];
for (int i = 0; i < n; i++)
pomeraj[i] = o[i].SadrziTacku(A);
}
private void picture Box1 MouseUp(object sender, MouseEventArgs e)
{

38

S. Matkovi, M. urixi

x = y = -1;
}
private void picture Box1 MouseMove(object sender, MouseEventArgs e)
{
if (x != -1 && y != -1)
{
for (int i = 0; i < n; i++)
if (pomeraj[i]) o[i].Pomeri(e.X - x, e.Y - y);
x = e.X;
y = e.Y;
pictureBox1.Refresh();
}
}

Primer 3. Funkcija.
Posmatrajmo matematiqke funkcije, definisane na skupu realnih brojeva.
Najprostije realne funkcije su konstante (funkcije oblika f (x) = c, c R) i
promenive (f (x) = x). Sve ostale gradimo primenom osnovnih aritmetiqkih
operacija ili specijalnih funkcija (trigonometrijske, logaritamske, eksponencijalne . . . ) na prethodno izgraene funkcije.
Generalizacijom moemo doi do osnovne klase Funkcija. Za svaku funkciju moemo odrediti vrednost u zadatoj realnoj taqki i nacrtati grafik u odreenom intervalu. Odreivae vrednosti se razlikuje od funkcije do funkcije
pa metod Vrednost(double x) mora biti apstraktan kao i sama klasa. Postupak crtaa grafika je za sve funkcije isti (spajamo taqke sa koordinatama (x,
Vrednost(x)) za uzastopne vrednosti x) pa ga realizujemo u klasi Funkcija
(metod Nacrtaj). U osnovnoj klasi moemo realizovati i operatore za osnovne
aritmetiqke operacije jer se izvrxavaju na isti naqin, bez obzira na to koje
funkcije se primeuju.
Iz klase Funkcija, specijalizacijom, izvodimo klase Konstanta, Promenljiva, SlozenaFunkcija, Sinusna . . . U svakoj od ovih klasa mora se predefinisati apstraktni metod Vrednost. Klase SlozenaFunkcija i Sinusna za
atribute imaju druge funkcije xto je u skladu sa odgovarajuim matematiqkim
funkcijama (znamo da je parametar sinusne funkcije proizvona realna funkcija a sloena funkcija predstava rezultat primene aritmetiqkih operacija na
proizvone realne funkcije).
abstract public class Funkcija
{
abstract public double Vrednost(double x);
public void Nacrtaj(Graphics g, PointF centar, double x0, double x1, float k)
//centar - (0,0), (x0,x1) - interval, k broj pt u jedinici Dekartovog KS
{
for (doublex = x0; x<= x1; x+=0.001)
g.DrawLine(Pens.Black, centar.X + (float)x * k, centar.Y (float)Vrednost(x) * k,
centar.X + (float)(x+0.001) * k, centar.Y - (float)Vrednost(x+0.001) * k);
}
public static Funkcija operator +(Funkcija A, Funkcija B)
{
return new SlozenaFunkcija(A, B, +);
}
public static Funkcija operator -(Funkcija A, Funkcija B)

Mala xkola objektno orijentisanog programiraa

{
return new SlozenaFunkcija(A, B, -);
}
public static Funkcija operator *(Funkcija A, Funkcija B)
{
return new SlozenaFunkcija(A, B, *);
}
public static Funkcija operator /(Funkcija A, Funkcija B)
{
return new SlozenaFunkcija(A, B, /);
}
public static Funkcij aoperator (Funkcija A, Funkcija B)
{
return new SlozenaFunkcija(A, B, );
}
}
public class Konstanta : Funkcija
{
double c;
public Konstanta(double c1)
{
c = c1;
}
public override double Vrednost(double x)
{
return c;
}
public override string ToString()
{
return c.ToString();
}
}
public class Promenljiva : Funkcija
{
public override double Vrednost(double x)
{
return x;
}
public override string ToString()
{
return"x";
}
}
public class Sinusna : Funkcija
{
Funkcija l;
public Sinusna(Funkcija f)
{
l = f;
}
public override double Vrednost(double x)
{
returnMath.Sin(l.Vrednost(x));
}
public override string ToString()
{
return"sin("+l.ToString()+")";
}

39

40

S. Matkovi, M. urixi

}
public class SlozenaFunkcija : Funkcija
{
Funkcija A;
Funkcija B;
Char operacija;
public SlozenaFunkcija(Funkcija a, Funkcija b, Char c)
{
A = a;
B = b;
operacija = c;
}
public override double Vrednost(double x)
{
switch (operacija)
{
case+: return A.Vrednost(x) + B.Vrednost(x);
case-: return A.Vrednost(x) - B.Vrednost(x);
case*: return A.Vrednost(x) * B.Vrednost(x);
case/: return A.Vrednost(x) / B.Vrednost(x);
case: returnMath.Pow(A.Vrednost(x), B.Vrednost(x));
}
return 0;
}
public override string ToString()
{
return A.ToString() + operacija + B.ToString();
}
}

Sliqno klasi Sinusna moemo definisati i mnoge druge klase koje predstavaju realne funkcije qije je izraqunavae realizovano u sistemskoj klasi
Math (trigonometrijske, eksponencijalne, logaritamske, . . . ).
Navodimo i primer jednostavne aplikacije koja crta grafik funkcije f (x) =
sin(x2 + 2) 2 na intervalu od 10 do 10.
private void btNacrtaj Click(object sender, EventArgs e)
{
Graphics g=pictureBox1.CreateGraphics();
Funkcija g1 = new Promenljiva(); //kreiranje promenljive x
Funkcija g2 = new Konstanta(2); //kreiranje konstante 2
Funkcija g3 = (g1 g2) + g2; //kreiranje funkcije x2+2
Funkcija f = (newSinusna(g3)) * g2;// kreiranje funkcije sin(x2+2)*2
f.Nacrtaj(g, new PointF(pictureBox1.Width/2, pictureBox1.Height/2),-10,10,30);
Text = f.ToString();
}

Ovo je samo prikaz osnovne ideje o klasama pomou kojih moemo predstaviti realne funkcije. Realizacijom konstruktora koji za parametar imaju string
moemo znaqajno poboxati mogunosti ovog sistema klasa. Sliqno metodu Vrednost moemo realizovati metod Izvod koji bi vratio funkciju koja predstava
prvi izvod polazne funkcije. Ostavamo qitaocima da sami usavrxe ovaj softver u skladu sa svojim eama!

Mala xkola objektno orijentisanog programiraa

41

Zakuqak
Nasleivae nam daje mogunost korixea ve definisane klase za izradu novih klasa koje unapred dobijaju veliki deo funkcionalnosti, a imamo i
mogunost prilagoavaa izvedene klase svojim potrebama. Na taj naqin obezbeujemo vixestruku upotrebu koda (isti kod koristimo u osnovnoj i izvedenoj
klasi). Zahvaujui tome, programirae je u prethodnom periodu ostvarilo
znaqajan napredak, jer su programeri usredsreeni na rexavae specifiqnih
problema a veliki deo projekta, pre svega dizajn i strukturu, nasleuju iz klasa grupisanih u sistemske biblioteke ili biblioteka drugih programera.
I u nastavi programiraa nasleivae se moe vrlo lepo iskoristiti. Mogue je postupno nadograivati odreene projekte kroz izvoee sve sloenijih
klasa. Takoe, profesor moe kreirati osnovnu klasu a acima prepustiti da
realizuju po grupama razne izvedene klase da bi na kraju zajedno kreirali vrlo
upotrebive aplikacije.
Ovim zavrxavamo ,,Malu xkolu OOP u C# na stranicama vaxeg qasopisa.
Nadamo se da smo vas bar malo zainteresovali i da smo vam pomogli da ove
savremene metode programiraa pribliite svojim acima.
Matematiqka gimnazija, Kraice Natalije 37, Beograd

You might also like