You are on page 1of 12

8.

Nasleđivanje
Objekti u svakodnevnom životu mogu da se grupišu na osnovu njihovih zajedničkih osobina. Unutar grupa
moguća su dalja grupisanja na osnovu nekih specifičnijih zajedničkih osobina. Svi objekti date podgrupe
poseduju sve osobine svoje opšte grupe kao i još neke specifične osobine. Na primer: 
 geometrijske figure u ravni mogu da budu okarakterisane položajem, orijentacijom, površinom i
obimom,  
o krugovi su geometrijske figure u ravni koje su dodatno okarakterisane poluprečnikom,  
o kvadrati su geometrijske figure u ravni koje su dodatno okarakterisane dužinom ivice,  
o trouglovi su geometrijske figure u ravni koje su dodatno okarakterisane dužinama stranica, 
 vozila prevoze stvari i ljude,  
o letelice su vozila koja lete, 
 avioni su letelice,  
 helikopteri su letelice, 
 rakete su letelice, 
 vasionski brodovi su letelice,  
o plovila su vozila koja plove po vodi, 
 čamci su plovila,  
 jedrenjaci su plovila,  
 brodovi su plovila, 
o suvozemna vozila su vozila koja se kreću po zemlji,  
 bicikli su suvozemna vozila s dva točka, 
 …,
o …,
 …,
Kaže se da podgrupa nasleđuje (inherits) sve osobine svoje opštije nadgrupe i da je nadgrupa predak
podgrupe, odnosno podgrupa je potomak nadgrupe. 
Podgrupe se mogu formirati i u više koraka. Nadgrupa za neku podgrupu može i sama da bude podgrupa
druge grupe. Na primer, za avione je rečeno da su letelice, a same letelice su podgrupa vozila. S druge
strane, i avioni bi mogli da se podele dalje na putničke i teretne. Drugim rečima, osobine neke opšte grupe
mogu da se nasleđuju u više koraka — kroz više generacija.

8.1 Izvedene klase


U jeziku C# grupe objekata opisuju se pomoću klasa. Klase koje opisuju podgrupu objekata s nekim
dodatnim, specifičnim osobinama u odnosu na opštije grupe nazivaju se izvedene klase (derived classes).
Polazne klase, koje opisuju opštiju grupu objekata, nazivaju se osnovne klase (base classes) za date
izvedene klase. U praksi se često koristi i par naziva potklase (subclasses) i natklase (superclasses).

8.1.1 Definisanje izvedenih klasa

Izvedene klase se definišu opisom class čiji je opšti oblik:


modifikatori class ImeIzvedeneKlase : ImeOsnovneKlase {
modifikatori član
modifikatori član
}

Klasa je izvedena ako u definiciji postoji ImeOsnovneKlase. Inače se dobija već dobro poznata „obična”
klasa. Postojanje osnovne klase označava se dvema tačkama ( : ) iza identifikatora (imena) klase koja se
definiše, a iza koje slede identifikatori osnovnih klasa.
Ako se na početku definicije klase stavlja modifikator sealed, klasa je zapečaćena (sealed class) i iz nje ne
mogu da se izvedu druge klase. Drugim rečima, ne može biti osnovna klasa drugim klasama. Klasa
nasleđuje samo jednu klasu, koja može da bude izvedena iz neke druge klase. C# ne podržava višestruko
nasleđivanje, odnosno mogućnost da klasa ima više osnovnih klasa.
Ako klasa C nasleđuje klasu B, a klasa B nasleđuje klasu A onda klasa C nasleđuje sve dostupne članove (ne
nasleđuje konstruktore i privatne članove) klasa A i B.
Pristupačnost izvedene klase ne može biti šira od pristupačnosti osnovne klase. Na primer, iz interne
(internal) klase ne može da se izvede javna (public) klasa.
Članove izvedene klase, pored sopstvenih članova (navedenih unutar para vitičastih zagrada { } ) čine i
članovi (polja, metode, svojstva…) njene osnovne klase. Kaže se da izvedena klasa nasleđuje (inherits) sve
članove svoje osnovne klase i da je osnovna klasa predak izvedene klase, odnosno izvedena klasa potomak
osnovne klase. Nenasleđeni članovi izvedene klase nazivaju se i sopstveni ili specifični članovi.
Kontrola korišćenja članova klase ostvaruje se dodavanjem jednog ili nijednog od modifikatora pristupa
private, internal, protected internal, protected i public. Time se članovi dele na privatne, interne,
zaštićene, interne zaštićene i javne. Privatni članovi (private) mogu da se koriste (vidljivi su) samo u
matičnoj klasi. Interni članovi (internal) mogu da se koriste u matičnoj klasi i u svim klasama koje pripadaju
istom sklopu kao i matična klasa. Zaštićeni interni članovi (protected internal) mogu da se koriste u
matičnoj klasi, u svim klasama koje pripadaju istom sklopu kao i matična klasa i u svim klasama koje su
izvedene iz matične klase, nezavisno od toga kojem sklopu pripadaju. Zaštićeni članovi (protected) mogu da
se koriste u matičnoj klasi i u svim klasama koje su izvedene iz matične klase, nezavisno od toga kojem
sklopu pripadaju. Na kraju, javni članovi (public) mogu da se koriste unutar svih klasa, bez ograničenja.
Relacija nasleđivanja (izvođena) u dijagramima klasa označava se orijentisanom linijom od izvedene klase
ka osnovnoj klasi sa vrhom strelice u obliku praznog trougla (slika 1.a). Zaštićeni članovi označavaju se
znakom # ispred imena člana (polje c i metoda M3 na slici 1.b).
a) b)
Slika 1 – Nasleđivanje na dijagramima klasa

Glavni smisao nasleđivanja manifestuje se kod nestatičkih članova. Jedan primerak nasleđenog nestatičkog
polja postoji u svakom objektu izvedene klase, pored toga što nezavisno postoji i u svakom objektu osnovne
klase. 
Nasleđivanje statičkog polja ogleda se u tome da izvedena klasa ne dobija svoj primerak „nasleđenog”
statičkog polja, već izvedena klasa koristi isti primerak koji koristi i osnovna klasa. Može da se kaže da se
statički članovi nasleđuju samo logički, a ne i fizički. 
Članovi izvedene klase koji su nasleđeni od osnovne klase imaju istu pristupačnost kao i u osnovnoj klasi.
Posebno je važno to što su javni članovi osnovne klase javni i u izvedenoj klasi. Zbog toga s objektima
izvedene klase mogu da se obavljaju sve radnje koje mogu s objektima osnovne klase i, pored njih, još neke
druge radnje koje postoje samo u izvedenoj klasi. 
Kaže se da su izvedena klasa i osnovna klasa u odnosu jeste ili je: izvedena klasa je osnovna klasa sa
dodatnim mogućnostima. Tamo gde se očekuje objekat osnovne klase, može ravnopravno da se navede i
objekat izvedene klase. 
Konstruktori se ne nasleđuju. Kao i bilo koja klasa, i izvedena klasa može da ima proizvoljan broj
sopstvenih konstruktora. 
Za potrebe inicijalizacije nasleđenih polja može da se pozove konstruktor osnovne klase dodavanjem
inicijalizatora oblika :base (nizAgumenata) iza nizaParametra a ispred telaKonstruktora. Opšti
oblik definicije konstruktora s inicijalizatorom je: 
ImeKlase ( nizParametara ) : base ( nizArgumenata ) teloKonstruktora 

U nizuArgumenata smeju da se koriste parametri iz nizaParametara.


Ako se u definiciji konstruktora izvedene klase ne navede inicijalizator, za inicijalizaciju nasleđenih polja
poziva se podrazumevani konstruktor osnovne klase (base ( )).
Ako se u izvedenoj klasi ne definiše nijedan konstruktor, generiše se podrazumevani konstruktor koji samo
poziva podrazumevani konstruktor osnovne klase.
U inicijalizatoru konstruktora eksplicitno može da se poziva najviše jedan konstruktor: konstruktor svoje
klase (this (...) ) ili konstruktor osnovne klase (base (...).

Primer. Definisanje izvedenih klasa s konstruktorima


namespace pro1 {
class A { //Osnovna klasa

public A(…) {…}

}
}
Klasa A je u prostoru imena pro1. Pored nekoliko članova ima bar jedan konstruktor.
namespace pro1 {
class B : A { //Izvedena klasa u istom prostoru

public B(…) : base(…) {…}

}
}

Klasa B, takođe u prostoru imena pro1, je izvedena klasa iz klase A. U inicijalizatoru konstruktora poziva se
konstruktor osnovne klase (base (...)) radi inicijalizacije nestatičkih polja nasleđenih iz klase A. Argumenti
ovog poziva određuju koji će od konstruktora klase A biti pozvan.
namespace pro2 {
sealed class C : pro1.A { //Izvedena klasa u drugom prostoru

public C(…) {…}

}
}

Klasa C u prostoru imena pro2 je zapečaćena (sealed). Neće moći da se definišu klase koje bi bile izvedene
iz nje. Da bi mogla biti izvedena iz klase koja nije u istom prostoru imena potrebno je navesti kvalifikovano
ime klase A (pro1.A). Druga mogućnost je da se ime klase A prethodno uveze naredbom using u doseg
prostora imena pro2. U konstruktoru klase C nema eksplicitnog poziva konstruktora osnovne klase, pa će se,
pre tela konstruktora pozivati podrazumevani konstruktor klase A (base ()). 
namespace pro2 {
class D : C { //Greška: Klasa C je zapečaćena

public D(…) {…}

}
}

Pošto je klasa C zapečaćena, iz nje ne mogu da se izvedu druge klase, bez obzira na to u kom prostoru
imena se one nalaze.

8.1.2 Korišćenje članova izvedenih klasa


Svi članovi izvedena klase, kako sopstveni tako i nasleđeni, mogu da se koriste na jedinstven način koji je
opisan za „obične” klase, vodeći računa o njihovoj pristupačnosti. 
Unutar izvedene klase prosto ime člana je dovoljno za sve članove: sopstvene - nasleđene, nestatičke -
statičke. Po potrebi može da se koristi i skriveni parametar metode (this.član). 
Za nestatičke nasleđene članove može da se koristi i izraz base.član, gde je base simboličko ime za
podobjekat neposredne osnovne klase, ako samo član nije dovoljan. Treba razlikovati ovu upotrebu ključne
reči base od pozivanja konstruktora osnovne klase (base(...)) iz prethodnog odeljka. Dok base(...) može biti
samo inicijalizator konstruktora, izraz base.član može da se koristi u telu u bilo kojoj metodi proizvoljan
broj puta. 
Za statičke članove može da se koristi i izraz OsnKlasa.član, pri čemu može da se navede ime osnovne
klase i na višem nivou hijerarhije nasleđivanja (starije generacije), a ne samo ime neposredne osnovne
klase. 
Primer.Korišćenje članova unutar izvedene klase
class Alfa
{
private int a;
protected int b;
public static int c;
protected int d;
public Alfa(int x) { a = b = c = d = x; }
public Alfa() { a = b = c = d = 1; }
protected void M1() { }
public static void M2() { }
}
Klasa Alfa sadrži četiri polja različitih nivoa pristupačnosti, dva javna konstruktora i jednu zaštićenu i jednu
javnu metodu. Jedno polje i jedna metoda su statički članovi. Od članova ovde su posebno interesantna
zaštićena polja b i d, kao i zaštićena metoda M1. Pored matične klase Alfa oni mogu da se koriste i u onim
klasama koje su definisane kao izvedene klase iz klase Alfa. Od konstruktora prvi ima parametar tipa int.
Drugi je bez parametara, tj. podrazumevani je konstruktor.
class Beta : Alfa //Prva izvedena klasa
{
private int e;
public int f;
public Beta(int x, int y) : base(x) { e = f = y; }
public Beta() { e = f = 2; }
public void M1(int x) { }
public void M3()
{
e = f = 33; //Pristupi sopstvenim poljima
this.f = 33; // može i ovako
a = 11; //Greška : nepristupačno polje
b = c = d = 22; //Pristup nasleđenim poljima
this.b = 22; //samo nestatička polja
base.b = 22;
Alfa.c = 22; //samo statička polja
M1(44); //Poziv sopstvene metode
M1(); //Pozivi nasleđenim metodama
M2();
this.M1(); //Samo nestatičke metode
base.M1();
Alfa.M2(); //Samo statičke metode
}
}

Klasa Beta je izvedena iz klase Alfa. Ima svoja dva polja (privatno e i javno f) i četiri nasleđena polja (a, b,
c i d) različitih nivoa pristupačnosti.
Prvi konstruktor ima dva parametra od kojih je prvi naveden kao argument u pozivu konstruktora osnovne
klase (base(x)). Drugi konstruktor je podrazumevani konstruktor i nema eksplicitan poziv konstruktora
osnovne klase. Tu se implicitno poziva podrazumevani konstruktor osnovne klase (base()).
U klasi Beta postoje četiri metode: dve nasleđene (zaštićena M1() i javna M2()) i dve sopstvene javne
(Ml(int) i M3()). U slučaju metoda M1 radi se o preopterećivanju imena metoda (orerload).
U metodi M3 prikazane su razne mogućnosti korišćenja članova izvedene klase Beta.
U prvom redu se pristupa sopstvenim poljima prostim imenima. U drugom redu je pokazan pristup pomoću
skrivenog parametra this.
Pristup polju a u trećem redu nije dozvoljen pošto je to privatno polje osnovne klase Alfa. U četvrtom redu
prikazan je pristup svim dostupnim poljima osnovne klase prostim imenima.
U naredna tri reda prikazane su druge mogućnosti pristupanja nasleđenim poljima Nestatičkom polju b
pomoću skrivenog parametra (this.b) i podobjekta osnovne klase (base .b). Statičkom polju c pomoću imena
osnovne klase (Alfa.c).
U preostalim redovima metode M3 prikazani su pozivi sopstvene metode M1(int), kao i nasleđenih metoda
M1() i M2() , kako prostim tako i kvalifikovanim imenima.
Svojstva (properties) su funkcijski članovi klasa koji se koriste kao i polja klasa.

objekat.imeSvojstva
Klasa.imeSvojstva

Za razliku od polja, kod svojstava postavljanje i dohvatanje vrednosti može da se sastoji od većeg
broja operacija. U toku postavljanja vrednosti mogu da se sprovedu razne provere i može da se
promeni vrednost više polja. Takođe, vrednost svojstva može da se određuje na osnovu vrednosti
više polja.

Opšti oblik definisanja svojstva je:

tipSvojstva imeSvojstva {
get telo
set telo
}

Dodavanjem modifikatora private (podrazumeva se), internal ili public na početku definicije
označava se da je svojstvo privatno, interno, odnosno javno. Dodavanjem modifikatora static
označava se da je svojstvo statičko (podrazumevano je nestatičko). Telo je po formi blok.

Svojstvo je "pametno" polje (kombinacija polja i metode). Ona su prirodni nastavak polja. Svojstvo
tvorcu klase izgleda kao metoda a korisniku klase se čini kao da je polje koje pruža neograničen
pristup putem operatora dodele.
Deo get telo naziva se dohvatač (getter). Izvršava se kada se vrednost svojstva dohvata (očitava).
Na primer, izrazom oblika:
promenljiva = objekat.imeSvojstva;
promenljiva = Klasa.imeSvojstva;

Izvršavanje dohvatača završava se naredbom return izraz;, gde je izraz tipa tipSvojstva ili
tip koji može implicitnom konverzijom da se pretvori u taj tip. Drugačije rečeno dohvatač se ponaša
kao da je metoda bez parametara.
Deo set telo naziva se postavljač (setter). Izvršava se kada se vrednost svojstva postavlja
(upisuje) izrazom oblika:
objekat.imeSvojstva = izraz
Klasa.imeSvojstva = izraz

Vrednost izraza unutar postavljača može da se koristi pomoću skrivenog parametra value čiji je tip
jednak tipuSvojstva. Drugačije rečeno, postavljač se ponaša kao da je metoda sa jednim
parametrom.
U većini slučajeva uz svojstvo postoji jedno zasebno definisano, pozadinsko polje (backing field)
čija vrednost se postavlja i dohvata. Tip pozadinskog polja je obično jednak tipuSvojstva, ali to
nije formalan uslov.
Svojstvo je uglavnom javno, a njegovo pozadinsko polje privatno. Ustaljena je praksa da svojstvo i
pozadinsko polje imaju isto ime, pri čemu se ime svojstva piše velikim, a pozadinskog polja malim
početnim slovom.
Svojstvo može da bude i složeno u smislu da se pri postavljanju menja vrednost više polja i da se
pri dohvatanju rezultat određuje na osnovu vrednosti više polja.

class Alfa
{
private int a = 1, b = 2;
public int A
{
get { return a; }
set { a = value; }
}
public int B
{
get { return b; }
set { b = value; }
}
public int C
{
get { return a + b; }
set { a += value; b += value; }

}
}

Javna svojstva A i B su jednostavna svojstva kojima mogu da se dohvataju i postavljaju vrednosti


privatnih polja a i b.

Javno svojstvo C, ilustracije radi, pri dohvatanju ima vrednost koja je jednaka zbiru privatnih polja
a i b. Prilikom „postavljanja“ dostavljena vrednost (value) se dodaje na zatečene vrednosti
polja a i b.
internal class AlfaTest
{
static void Main(string[] args)
{
Alfa alfa = new Alfa();
int p = alfa.A; // p = 1
alfa.A = 5; // a = 5
int q = alfa.A; // q = 5
int r = alfa.B;// r = 2
alfa.B = 3; // b = 3
int s = alfa.B; // s = 3
int t = alfa.C; // t = 8
alfa.C = 4; // a = 9; b = 7
int u = alfa.A; // u = 9
int v = alfa.B; // v = 7
int w = alfa.C; // w = 16
}

Postavljač ili dohvatač (ali ne oba istovremeno) može da se izostavi. Ako se izostavlja postavljač
vrednost može samo da se dohvata, tj. samo da se očitava (read-only). Ako se izostavi dohvatač,
vrednost svojstva može samo da se postavlja, tj samo da se upisuje (write-only). Svojstva samo za
postavljanje su u praksi znatno ređa od svojstava koja su samo za dohvatanje.
class Beta
{
private int a = 1, b = 2;
public int A
{
get { return a; }
}
public int B
{
set { b = value; }
}
}

Svojstvo A je samo za dohvatanje a svojstvo b samo za postavljanje.

internal class BetaTest


{
static void Main(string[] args)
{
Beta beta = new Beta();
int p = beta.A; // p = 1
beta.A = 5; // GREŠKA: ne može da se postavlja
int q =beta.B; // GREŠKA: ne može da se dohvata
beta.B = 4; // b = 4
}
}

Definicija jednostavnog svojstva oblika:


tipSvojstva imeSvojstva
{
get { return ime polja; }
set { imePolja = value; }
}

može sažetije da se napiše:


tipSvojstva imeSvojstva { get; set; }

Sadržaj dohvatača i postavljača, kao i definicija pratećeg privatnog pozadinskog polja generišu se
automatski. Ime pozadinskog polja nije vidljivo za programera. Ovakva svojstva nazivaju se
automatski implementirana svojstva.
Tip pozadinskog polja je jednak tipuSvojstva. Mora postojati dohvatač jer u suprotnom vrednost
pozadinskog polja ne bi mogla da se dohvata.
Za automatski implementirana svojstva mogu da se navedu inicijalizatori:
tipSvojstva imeSvojstva { get; set; } = izraz;
Početna vrednost pridruženog pozadinskog polja biće jednaka vrednosti izraza. Izostavljanjem set
ne pravi se postavljač pa se dobija nepromenljivo svojstvo.
Nepromenljivo svojstvo može sažetije da se napiše na sledeći način:
tipSvojstva imeSvojstva => izraz;
class Gama
{
private int a = 1, b = 2;
public int A { get; set; }
public int B { get; set; } = 1;
public int C { get; } = 2;
public int D => 4; //read only
public int E { set; }; // GREŠKA: nema dohvatača
}
internal class GamaTest
{
static void Main(string[] args)
{
Gama gama = new Gama();
int p = gama.A; // p = 0
gama.A = 5;
int q = gama.A; // q = 5
int r = gama.B; // r = 1
gama.B = 8;
int s = gama.B; // s = 8

int t = gama.C; // t = 2
gama.C = 6; // GREŠKA: ne moze da se postavlja
int u = gama.D; // u = 4
gama.D = 7; // GREŠKA: ne moze da se postavlja
}
}

You might also like