Professional Documents
Culture Documents
27
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> }
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 ;
}
}
30
S. Matkovi, M. urixi
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; }
}
31
{
get { return (sekunde / 60) % 60; }
}
public long Sat
{
get { return sekunde / 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;
}
}
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;
}
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));
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:
35
NASTAVA RAQUNARSTVA
Binarni operatori
+, , !, , ++,
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>.
33
y*z + 3;
else
x += y;
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
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:
35
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
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");
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
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);
}
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))
{
41
d = 1;
m++;
if (m == 13)
{
m = 1;
g++;
}
}
return new Datum(d, m, g);
}
42
S. Matkovi, M. urixi
43
44
S. Matkovi, M. urixi
return c;
}
}
NASTAVA RAQUNARSTVA
43
class <imeIzvedeneKlase>:<imeOsnovneKlase>
{
opis / definicija
clanova klase
}
44
S. Matkovi, M. urixi
{
//....
}
public Izvedena(int a,int s):base(a)
{
// ...
}
//...
}
45
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
46
S. Matkovi, M. urixi
// ....
}
//...
}
public class Izvedena:Osnovna
{
// ....
public override void radi()
{
//....
}
//...
}
47
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)
base(U)
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.
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)
:
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];
}
base(z)
{
this.predmet = z.predmet;
this.koeficijent = z.koeficijent;
}
public override string informacije ()
{
51
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))||
53
NASTAVA RAQUNARSTVA
33
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
35
36
S. Matkovi, M. urixi
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;
37
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)
{
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!
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