[5] C# - Klase, nasledjivanje, interfejsi

[5] C# - Klase, nasledjivanje, interfejsi

offline
  • Fil  Male
  • Legendarni građanin
  • Pridružio: 11 Jun 2009
  • Poruke: 14644

Klase






Klasa je skup objekata koji imaju zajedničku strukturu i ponašanje. Predstavlja strukturu podataka koju treba posmatrati kao novi tip.

Objekat je instanca klase i definiše se kao entitet koji je sposoban da čuva svoja stanja i koji okolini stavlja na raspolagaje skup operacija preko kojih se tim stanjima pristupa.

Objekat karakteriše njegov:
--> IDENTITET - razlikovanje objekata među sobom,
--> PONAŠANJE - dato preko skupa metoda koje sadrži objekat
--> STANJE - varijable (promenljive) vezane za objekat


//podvucimo još jednom da se stanja odnose na varijable, a ponašanje na metode Exclamation


Arrow Direktan pristup podacima je nepotreban i nepoželjan Exclamation
-->podatke treba "začauriti" (enkapsulirati)!

Postoje dva bitna aspekta enkapsulacije:
1. objedinjavanje podataka i funkcija u jedinstven entitet (preko klasa) ,
2. kontrola mogućnosti pristupa članovima entiteta (preko modifikatora pristupa).
//o modifikatorima pristupa je bilo reči u prethodnom članku


Enkapsulacija omogućava kontrolu korišćenja objekta (objekat se može koristiti isključivo preko javnih metoda/svojstava).



Arrow Instanciranje klasa

--> vrši se pomoću opreatora NEW:

 Amf argus = new Amf();

Konstruktor je specijalna metoda koja:
- ima isti naziv kao i naziv klase,
- nema nikakvu povratnu vrednost.

Idea Operator new vrši alokaciju memorije za objekat klase Amf, a metoda (konstruktor) Amf() kreira objekat.


Primer:

using System; namespace Metode {    class Amf    {       public string imeAmf;       public int brojResenihSlucajeva;                       public void DodajSlucajeve(int broj)         {          brojResenihSlucajeva+=broj;         }              public void PrikaziStanje()         {             Console.WriteLine("Broj resenih slucajeva AMF-a {0} je: {1} ", this.imeAmf,this.brojResenihSlucajeva);         }                 public static void Main (string[] args)       {          Amf amf = new Amf();             amf.imeAmf="Goran9888";             amf.DodajSlucajeve(70);             amf.PrikaziStanje();                             }    } }





Šta je ključna reč this?

--> upotrebom ključne reči this, implicitno se pokazuje na tekući objekat/parametar

(kod statičkih metoda se ne prosleđuje ovaj dodatni parametar, jer se ne pozivaju pomoću objekata)






Nasleđivanje





Nasleđivanje predstavlja jedan od koncepata Objekto Orijentisanog Programiranja (OOP).
-->omogućava da se na osnovu postojeće klase izvede nova klasa.

Izvedena klasa nasleđuje sve članove bazne klase.
// bazna klasa je super klasa ili nadređena klasa.
// izvedena klasa je podklasa ili podređena klasa (klasa koja nasleđuje baznu klasu).

Idea Treba razlikovati nasleđivanje klasa od nasleđivanja interfejsa. Klasa koja nasleđuje interfejs treba da implementira sve navedene metode interfejsa.

- Nasleđivanje klasa može biti DIREKTNO I INDEREKTNO.
Indirektno, svaka klasa nasleđuje klasu Object.

- Jednu baznu klasu može da nasledi više izvedenih klasa (broj izvedenih klasa je neograničen).

- U programskim jezicima, nasleđivanje može biti i jednostruko i višestruko
--> C# podržava samo jednostruko nasleđivanje !

Grupa klasa koje su povezane nasleđivanjem formiraju strukturu koja se naziva hijerarhija klasa.




Slika: hijerarhija klasa


––> klase na višim nivoima su opštije (koncept generalizacije), dok su one na nižim nivoima u hijerarhiji specifičnije (koncept specijalizacije).

––> Dubina hijerarhije predstavlja broj nivoa nasleđivanja
//preporučuje se da dubina nasleđivanja bude do 7 nivoa.


Arrow Sintaksa nasledjivanja:


class IzvedenaKlasa:BaznaKlasa { ... }

Izvedena klasa nasleđuje sve osim konstruktora i destruktora bazne klase. Exclamation

Idea Ukoliko nije eksplicitno navedena bazna klasa podrazumeva se klasa System.Object.


––> javni članovi bazne klase su implicitno i javni članovi izvedene klase.


Primer je dat u pseudokodu:

public class Forumas {   public void PosaljiPoruku(string tekst){...}   ............... } public class Moderator: Forumas { } ... Moderator simke = new Moderator(); simke.PosaljiPoruku("I da, za nijansu manje pijemo"); //pristup nasleđenoj metodi


- Izvedenoj klasi se, naravno, mogu dodati novi članovi.

- Nasleđivanje ne podrazumeva da će izvedena klasa imati pristup svim članovima bazne klase.
––> privatni članovi bazne klase, iako nasleđeni, su dostupni isključivo članovima bazne klase Exclamation

––> članovi bazne klase sa modifikatorom protected su jedino dostupni unutar bazne klase i direktno i indirektno izvedenim klasama.

PODSETIMO SE: ukoliko modifikator pristupa nije naveden podrazumeva se da su članovi klase označeni sa "private".

Preporuka:
––> sva polja klase treba da imaju modifikator pristupa private, a za svako polje treba navesti svojstvo sa modifikatorom pristupa protected.


Arrow Dostupnost izvedene klase je uslovljena dostupnošću bazne klase Exclamation
––> ukoliko je bazna klasa privatna, izvedena klasa ne može biti javna!


Arrow Za poziv konstuktora bazne klase iz konstruktora izvedene klase se koristi ključna reč base.


public class BaznaKlasa {   public BaznaKlasa() {...} } public class IzvedenaKlasa: BaznaKlasa {   public IzvedenaKlasa(): base() { ... } }

// prvo se izvršava konstruktor bazne klase.


Arrow Pošto pričamo o nasleđivanju, treba predstaviti i koncept polimorfizma.

––> polimorfizam predstavlja sposobnost promenljive da referencira objekte različitih tipova i da automatski poziva odgovarajuću metodu objekta koji referencira.

// Polimorfizam se zasniva na ideji da metoda koja je deklarisana u osnovnoj klasi može da se implementira na više različitih načina u različitim izvedenim klasama.

Idea Polimorfizam se realizuje preko virtualnih metoda Exclamation

- za deklaraciju virtuelnih metoda se koristi ključna reč virtual.
- virtualne metode se mogu reimplementirati u izvedenim klasama (kod njih se koristi ključna reč override).

public class Forumas {   public virtual void PrikaziForume() {...} } public class Moderator : Forumas {   public override void PrikaziForume() {...} }
--
// jer moderator vidi dodatne (skrivene potforume) koje ne vidi običan forumaš.

Virtuelna i reimplementirana (overrajdovana Mr. Green) metoda moraju biti identične, tj. moraju imati:
Exclamation isti naziv,
Exclamation isti modifikator pristupa,
Exclamation isti tip rezultata,
Exclamation iste tipove parametara.


- Mogu se sakriti i virtuelne i nevirtuelne metode.
// sakrivanje metoda utiče na polimorfizam.

Primer polimorfizma (pseuokod):

public class Forumas {    public virtual void PrikaziForume() {...} } public class Moderator : Forumas {    public override void PrikaziForume() {...} } Forumas bobby = new Moderator(); bobby.PrikaziForume();


REZULTAT --> poziva se reimplementirana metoda Exclamation
(pozvaće se metoda klase čijeg je tipa promenljiva)


Ukoliko ne želimo da drugi programeri, nasleđjuju neku od klasa, koje smo napravili
--> to možemo učiniti pomoću ključne reči sealed , a takve klase se nazivaju zapečaćene klase.

Zapečaćena (sealed) klasa ne može da se koristi kao bazna klasa bilo koje druge klase.


Sintaksa:

public sealed class ZapecacenaKlasa     {         //...     }






Interfejsi





Interfejs predstavlja "ugovor" kojim se garantuje da će se klasa, koja je nasledila taj interfejs, ponašati na određeni način.

// Dakle, klasa garantuje da prodržava metode, svojstva (properties), događaje (events) i indeksere nekog interfejsa!

Sintaksno
--> interfejs je klasa koja sadrži samo apstraktne metode.

Exclamation Kada klasa implementira interfejs ona mora da implementira sve njene metode !

Moguće je da jedna klasa implementira više interfejsa.
(podsetimo se, višestruko nasleđivanje klasa nije dozvoljeno u C#, ali jeste višestruko nasleđivanje interfejsa).

Ukoliko želimo da proverimo da li objekat implementira interfejs učinićemo to na jedan od sledeća dva načina:

A) preko IS operatora:

npr. (kocka is ITelo)

--> vraća true ako se kocka može kastovati u ITelo.


B) preko AS operatora:

npr. (ITelo telo = kocka as ITelo)

--> ovaj način kombinuje IS i operacije kastovanja tako što prvo testira da li je kastovanje moguće a zatim kompletira kastovanje ako je moguće. Ukoliko kastovanje nije moguće operator AS vraća povratnu vrednost null.
//dakle, u ovom slučaju se provera vrši na indirektan način!


Arrow Apstraktna klasa je klasa koja se može naslediti, ali se ne može instacirati.
Može posedovati apstraktne metode, koje nemaju svoju implementaciju, ali ih klase naslednice (ukoliko nisu apstraktne) moraju implementirati korišćenjem ključne reči “override”.

Takođe, apstraktna klasa može imati metode koje imaju implementaciju (za razliku od interfejsa), i koje u svom telu mogu koristiti apstraktne metode.


Sveobuhvatan primer:

using System; namespace ApstraktneKlase {    public interface IRacun    {        void IsplatiSaRacuna(double iznos);        void UplatiNaRacun(double iznos);        string VratiPodatkeORacunu();        double VratiStanje();     }    public abstract class AbstractRacun : ApstraktneKlase.IRacun    {        private double stanje;        private string brojRacuna;        public AbstractRacun(string brojRacuna):this(brojRacuna, 0) { }               public AbstractRacun(string brojRacuna, double pocetnoStanje)        {           this.brojRacuna = brojRacuna;           this.stanje = pocetnoStanje;        }               public double VratiStanje()        {           return stanje;        }               public void UplatiNaRacun(double iznos)        {           stanje += iznos - ProvizijaNaUplatu(iznos);        }             public void IsplatiSaRacuna(double iznos)        {           stanje -= iznos + ProvizijaNaIsplatu(iznos);        }               protected abstract double ProvizijaNaUplatu(double iznos);         protected abstract double ProvizijaNaIsplatu(double iznos);               public virtual string VratiPodatkeORacunu()         {             string podaci = "Racun broj: " + brojRacuna+"\nIznos na racunu: " + stanje;             return podaci;         }       public class TekuciRacun:AbstractRacun        {            public TekuciRacun(string brojRacuna) : base(brojRacuna) { }                  public TekuciRacun(string brojRacuna, double pocetnoStanje) : base(brojRacuna, pocetnoStanje) { }                      protected override double ProvizijaNaUplatu(double iznos)            {                return 0;            }                      protected override double ProvizijaNaIsplatu(double iznos)            {                double obracunataProvizija = 100 + (iznos * 3 / 100);                return obracunataProvizija;            }                  public override string VratiPodatkeORacunu()            {                return base.VratiPodatkeORacunu() + "\nTip racuna: TEKUCI";            }        }       public class DevizniRacun:AbstractRacun        {            public DevizniRacun(string brojRacuna) : base(brojRacuna) { }            public DevizniRacun(string brojRacuna, double pocetnoStanje) : base(brojRacuna, pocetnoStanje) { }            protected override double ProvizijaNaUplatu(double iznos)            {                double obracunataProvizija = 100 + (iznos * 5 / 100);                return obracunataProvizija;            }                  protected override double ProvizijaNaIsplatu(double iznos)            {                double obracunataProvizija = 100 + (iznos * 5 / 100);                return obracunataProvizija;            }                  public override string VratiPodatkeORacunu()            {                return base.VratiPodatkeORacunu() + "\nTipRacuna: DEVIZNI";            }        }                        public static void Main (string[] args)       {          AbstractRacun[] racuni = new AbstractRacun[2];             racuni[0] = new TekuciRacun("422-422", 0);             racuni[1] = new DevizniRacun("917-017", 0);             for (int i = 0; i < 2; i++)             {                 Console.WriteLine("Uplata na " + i + ". racun u iznosu od 1000");                 racuni[i].UplatiNaRacun(1000);                 Console.WriteLine("Podaci o racunu posle uplate: \n"+racuni[i].VratiPodatkeORacunu());                 Console.WriteLine();             }         }    } }


Izlaz:





Arrow Izbegavanje konflikta između imena klasa u programima se obezbeđuje preko imenskih prostora (namespace)

Imenski prostor obezbeđuje kontejner koji sadrži aplikacioni kod, na takav način da i kod i njegov sadržaj mogu biti jedinsveno identifikovani.

Takođe, promoviše se ponovna upotreba koda. Imenski prostori se koriste i za kategorizaciju objekata u .NET okruženju.


C# kod se sadrži u globalnom imenovanom prostoru, a to znači da se tom kodu može pristupiti iz nekog drugog koda koji je unutar globalnog imenovanog prostora, i to tako što se navede njegovo ime.

Kao što je već dosada viđeno u primerima, koristi se ključna reč namespace , kako bi se eksplicitno definisao imenski prostor.

Ukoliko imamo kod u jednom imenovanom prostoru, koji treba da koristimo u drugom imenovanom prostoru, mora se uključiti referenca na prvi imenovani prostor.



Registruj se da bi učestvovao u diskusiji. Registrovanim korisnicima se NE prikazuju reklame unutar poruka.
offline
  • Pridružio: 19 Maj 2011
  • Poruke: 297

Posto u C# nema pokazivaca, koja je sintaksa da neki objekat bude pokazivac/referenca na neki drugi objekat?
A kako da naznacim ako hocu da bude kopija?
Isto i za parametre metoda/funkcija, kako da naznacim da mi parametar bude referenca, mislim da bude output? I obrnuto, da kopira vrednost.



offline
  • C# and PHP Developer
  • Pridružio: 16 Feb 2011
  • Poruke: 1622
  • Gde živiš: Pancevo

Cek zar mora cela klasa da bude unutar NAMESPACE {}
Jel postoji mogucnost da se samo uradi namespace nest\jos\nesto\bla\bla;

offline
  • Milan
  • Pridružio: 17 Dec 2007
  • Poruke: 14172
  • Gde živiš: Niš

Napisano: 09 Feb 2014 21:57

ThePhilosopher :: Arrow Apstraktna klasa je klasa koja se može naslediti, ali se ne može instacirati.
Može posedovati apstraktne metode, koje nemaju svoju implementaciju, ali ih klase naslednice (ukoliko nisu apstraktne) moraju implementirati korišćenjem ključne reči “override”.
Dakle, to više nisu čiste virtuelne funkcije kao u C++? Ili ipak jesu? Very Happy

Dopuna: 09 Feb 2014 22:11

_iKaC ::Cek zar mora cela klasa da bude unutar NAMESPACE {}Mislim da ne mora. No, ako koristiš namespace moguće je kreirati dve klase sa istim imenom. Tom prilikom bi (recimo u C++) svakoj klasi pristupao sa <ime_namespace-a>::<ime_klase>. Ukoliko bi želeo implicitno da koristiš klasu iz određenog namespace-a, koristio bi direktivu using:
using namespace <ime_namespace-a>;

offline
  • C# and PHP Developer
  • Pridružio: 16 Feb 2011
  • Poruke: 1622
  • Gde živiš: Pancevo

Citat:
Preporuka:
––> sva polja klase treba da imaju modifikator pristupa private, a za svako polje treba navesti svojstvo sa modifikatorom pristupa protected.

U tvom slucaju property bi bio dostupan samo u izvedenoj i izvornoj klasi sto je totalno glupo. Ok je u nekim slucajevima (npr ako ce se ta vrednost koristi samo u baznoj(izvornoj) i izvedenoj klasi.

@morando
Mozes koristiti pokazivace iskljucivo ako kod navedes da je UNSAFE. To ces uraditi koriscenjem unsafe kljucne reci.

Evo primera:

public unsafe void HelloMC() {       int x = 10;       int y = 20;       int *ptr1 = &x;       int *ptr2 = &y;       Console.WriteLine((int)ptr1);       Console.WriteLine((int)ptr2);       Console.WriteLine(*ptr1);       Console.WriteLine(*ptr2); }

Evo i za metodu:
public unsafe int* TestMetoda(int *x, int *y)

Pre dok sam prelazio sa C++ na Javu i bio u fazi testiranja C# i ja sam se zapitao par puta isto pitanje.

Ko je trenutno na forumu
 

Ukupno su 586 korisnika na forumu :: 51 registrovanih, 6 sakrivenih i 529 gosta   ::   [ Administrator ] [ Supermoderator ] [ Moderator ] :: Detaljnije

Najviše korisnika na forumu ikad bilo je 1567 - dana 15 Jul 2016 19:18

Korisnici koji su trenutno na forumu:
Korisnici trenutno na forumu: 4bobo, 8u47, A.R.Chafee.Jr., bato3, bojcistv, BSD, bulovic, d.arsenal321, Davor Kondic, Eyes Wide Shut, Fog of War, Georgius, ikan, jesenko1974, Joja2, komkom, Kos93, krkalon, Kubovac, Logic005, majorgaspar, matorigile, MIG-3, Milenko Vujinovic, Mixelotti, nedeljkovici, Nenad Stankovic, Oluj2.1, Panter2, Raptor12, repac, RJ, rkekoke, robertino2, rovac, slonic_tonic, srecko81, SsssssNOVI, StepskiVuk2, stug, suton2, theNedjeljko, tmanda323, trutcina, Vatreni Zmaj, VJ, vobo, Vojkan Petrovic, wizzardone, zixmix, 1877