Klasa (programiranje)

Izvor: Wikipedija

U objektno orijentiranom programiranju, klasa je predložak programskog koda za kreiranje objekata. Sastoji se od podataka (članskih varijabli) i ponašanja (članskih funkcija ili metoda).[1][2] U mnogim se jezicima ime klase koristi i za ime datoteke koja istu definira, za zadani konstruktor klase (metodu koja instancira klasu, odn. stvara objekte klasnog tipa i također za tip podatka za instance klase.[2]

Kada konstruktor klase stvori objekt te klase, kažemo da je objekt instanca klase (klasa je instancirana), a članske varijable specifične za taj objekt nazivaju se varijablama instance. Varijable instance specifične su za stvoreni objekt, za razliku od varijabli klase, gdje sve instance dijele iste podatke.

Klasa naspram tipa[uredi | uredi kôd]

U svakodnevnoj upotrebi ljudi se često pozivaju na "klasu" objekta, ali objekti zapravo imaju tip podatka koji nastaje implementacijom klase. U tom je kontekstu tip podatka svojevrsno sučelje, dok je klasa implementacija sučelja koja ima konkretne varijable i metode. Sukladno tome, različite (konkretne) klase mogu istancirati objekte istog (abstraktnog) tipa. Primjerice, dvije klase, MaliStog (brži ali manje skalabilan) i SkalabilanStog (zahtijeva više resursa) mogu implementirati objekte istog tipa, Stog. Sukladno tome, pojedina klasa može imati više različitih (preopterećenih) konstruktora.

Tipovi klasa obično su imenice, poput bića, stvari ili mjesta. Primjerice tip Banana može predstavljati svojstva i funkcionalnost banana općenito, dok klase ABCBanana i XYZBanana mogu predstavljati neke funkcionalnosti banane u određenom kontekstu (npr. distribucija ili crtanje banana u videoigrici). Ako klasa ABCBanana stvara pojedinačne banane, instance te klase bile bi tipa Banana.

Obično se radi jedna implementacija svakog tipa, pa klase i tipovi dijele isto ime.

Dizajn i implementacija[uredi | uredi kôd]

Klase se sastoje od podataka i ponašanja.[1] Programski jezici koji uključuju klase kao programsku konstrukciju nude podršku za različite značajke klasa, a sintaksa uporabe ovih značajki uvelike se razlikuje po programskim jezicima.

Podaci[uredi | uredi kôd]

UML notacija za klase

Klasa sadrži podatke odnosno varijable (također se koriste nazivi svojstva, polja, članske varijable ili atributi).

Svaka varijabla klase ima tip podatka i ime, a može pripadati cijeloj klasi (sve instance klase dijele istu vrijednost) ili pojedinom objektu.

U većini jezika struktura koju definira klasa određuje raspored memorije koju koriste njezine instance. Moguće su i druge implementacije: na primjer, objekti u Pythonu koriste asocijativne spremnike ključ/vrijednost.[3]

Ponašanja[uredi | uredi kôd]

Ponašanje klase ili njenih instanci definira se korištenjem metoda. Metode su potprogrami ili funkcije koji se izvode nad objektima ili klasama. Metode mogu promijeniti stanje objekta (vrijednost njegovih varijabli) ili pružiti pristup varijablama klase.[4] Postoje mnoge vrste metoda, ali podrška za njih varira na različitim jezicima. Neke metode kreira i poziva programer, druge metode – naročito konstruktore, destruktore i operatore pretvorbe – stvara i poziva kompilator. Jezik također može omogućiti programeru da definira, preoptereti i pozove ove posebne metode i preopterećene operatore.[5][6]

Pristup članovima[uredi | uredi kôd]

Metode unutar klase i funkcije van klase mogu imati različita dopuštenja pristupa varijablama i metodama u klasi.

Slijedi popis čestih modifikatora pristupa:[7]

  • Private (ili class-private) ograničava pristup na samu klasu. Samo metode koje su dio iste klase mogu pristupiti njenim privatnim članovima.
  • Protected (ili class-protected) omogućuje samoj klasi i svim njezinim podklasama pristup njenim članovima.
  • Public dopušta bilo kojem kodu direktan pristup elementima klase.

Modifikatori pristupa ne kontroliraju nužno vidljivost članskih varijabli, s obzirom na to da čak i privatni članovi mogu biti vidljivi klijentskom vanjskom kodu. U nekim jezicima, nedostupni, ali vidljivi član može se u vrijeme izvođenja indirektno pozvati (primjerice, pokazivačem vraćenim iz članske funkcije), ali pokušaj direktnog pristupa imenovanjem člana iz klijentskog koda spriječit će kompilator.[8]

Razni objektno orijentirani programski jezici koriste različite koncepte pristupačnosti i vidljivosti članova klase. Na primjer, jezik Java ne dopušta kompilaciju klijentskog koda koji pristupa privatnim podacima klase.[9] U jeziku C++ privatne metode su vidljive, ali nisu dostupne u sučelju; međutim, mogu se učiniti nevidljivima eksplicitnom deklaracijom potpuno apstraktnih klasa koje predstavljaju sučelja klase.[10]

Neki jezici imaju druge sheme pristupačnosti:

  • Pristupačnost instance naspram klase: Ruby podržava modifikatore instance-private i instance-protected umjesto class-private i class-protected, respektivno. Razlikuju se po tome što ograničavaju pristup na temelju same instance, a ne instancirajuće klase.[11]
  • Friend: C++ podržava mehanizam u kojem funkcija koja je eksplicitno deklarirana kao prijatelj neke klase može pristupiti njenim privatnim i zaštićenim članovima.[12]
  • Temeljem putanje: Java podržava ograničavanje pristupa članu koji nije unutar istog Java paketa (odnosno logičke putanje datoteke). Pri uvođenju frameworka u Java kod, klase frameworka i aplikacije obično se stavljaju u isti paket, što će frameworku dopustiti pristup zaštićenim članovima aplikacijskih klasa. Izvorni kod Java aplikacije može se nalaziti na drugoj lokaciji ili unutar druge .jar datoteke, ali JVM će smatrati da sve što se nalazi u istom paketu ima istu logičku putanju.[7]

Primjeri[uredi | uredi kôd]

Primjer 1[uredi | uredi kôd]

Niže je osnovni primjer klase u programskom jeziku C++:

prostorija.h - definicija klase
class Prostorija {
    public:
        double duzina;
        double sirina;
        double visina;

        double izracunajPovrsinu(){   
            return duzina * sirina;
        }

        double izracunajVolumen(){   
            return duzina * sirina * visina;
        }
};

Klasa Prostorija ima javne (public) podatke (članske varijable) širina, visina, dužina tipa double (decimalni broj), i javna ponašanja (članske metode) izracunajPovrsinu() i izracunajVolumen() koje kao rezultat vraćaju double (decimalni broj).

main.cpp
#include <iostream>

#include "prostorija.h"

using namespace std;

void main() {

    Prostorija soba, kuhinja;
    // kreiramo nove objekte imena soba i kuhinja, koje imaju tip podatka "Prostorija"
    //soba i kuhinja su instance klase Prostorija
    
    soba.duzina = 5;
    soba.visina = 2.5;
    soba.sirina = 10.1
    
    kuhinja.duzina = 9;
    kuhinja.visina = 3;
    kuhinja.sirina = 10
    
    //svaka varijabla tipa Prostorija ima zasebne vrijednosti članskih varijabli (soba i kuhinja imaju zasebne dimenzije)
    // s obzirom da je sav kod ispod "public:", svaki dio koda može direktno pisati i čitati ove varijable
    
    cout << soba.izracunajPovrsinu(); //5 * 10.1 = 50.5
    
    cout << kuhinja.izracunajVolumen(); //9 * 3 * 10 = 270
}

Primjer 2 - konstruktor[uredi | uredi kôd]

U ovom ćemo primjeru uvesti konstruktor koji će standardizirati inicijalizaciju objekta.

prostorija.h - definicija klase
class Prostorija {
    public:
        double duzina;
        double sirina;
        double visina;
        
        //konstruktor s parametrima
        Prostorija(double _duzina, double _sirina, double _visina){
            duzina = _duzina;
            sirina = _sirina;
            visina = _visina;
        }

        double izracunajPovrsinu(){   
            return duzina * sirina;
        }

        double izracunajVolumen(){   
            return duzina * sirina * visina;
        }
};
main.cpp
#include <iostream>

#include "prostorija.h"

using namespace std;

void main() {

    Prostorija soba, kuhinja; // GREŠKA - objekti se sad moraju inicijalizirati pozivom konstruktora
    
    Prostorija soba("3", "4", "5");    //ispravno - duzina, sirina, visina
    Prostorija kuhinja("6", "7", "8"); //ispravno - duzina, sirina, visina
    
    // i dalje sav kod smije mijenjati članske varijable
    
    soba.visina = 2.5;
    
    kuhinja.visina = 3.5;
    
    cout << soba.izracunajPovrsinu(); //3 * 4 = 12
    
    cout << kuhinja.izracunajVolumen(); //6 * 7 * 3.5 = 147
}

Primjer 3 - privatni članovi[uredi | uredi kôd]

U ovom ćemo primjeru članske varijable učiniti privatnima.

prostorija.h - definicija klase
class Prostorija {
    private: //članske varijable su sad privatne, metode su i dalje javne
        double duzina;
        double sirina;
        double visina;
        
    public:
        //konstruktor s parametrima
        Prostorija(double _duzina, double _sirina, double _visina){
            duzina = _duzina;
            sirina = _sirina;
            visina = _visina;
        }

        double izracunajPovrsinu(){   
            return duzina * sirina;
        }

        double izracunajVolumen(){   
            return duzina * sirina * visina;
        }
};
main.cpp
#include <iostream>

#include "prostorija.h"

using namespace std;

void main() {
    
    // konstruktor je javan pa se vrijednosti varijabli mogu postaviti
    Prostorija soba("3", "4", "5");    
    Prostorija kuhinja("6", "7", "8");
    
    // članske varijable su u ovom primjeru privatne, pa im kod glavne funkcije više ne može pristupiti direktno
    soba.visina = 2.5;    //GREŠKA
    kuhinja.visina = 3.5; //GREŠKA
    
    // donje su funkcije dio klase pa mogu pristupati članskim varijablama
    cout << soba.izracunajPovrsinu(); //3 * 4 = 12
    
    cout << kuhinja.izracunajVolumen(); //6 * 7 * 8 = 336
}

Primjer 4 - getteri i setteri[uredi | uredi kôd]

U ovom ćemo primjeru dodati funkcije za pristup i promjenu članskih varijabli

prostorija.h - definicija klase
class Prostorija {
    private:
        double duzina;
        double sirina;
        double visina;
        
    public:
        Prostorija(double _duzina, double _sirina, double _visina){
            duzina = _duzina;
            sirina = _sirina;
            visina = _visina;
        }
        
    //getteri - služe za dohvaćanje vrijednosti članskih varijabli
    
        double getDuzina() {
            return duzina;
        }
    
        double getSirina() {
            return sirina;
        }
    
        double getVisina() {
            return visina;
        }
    
    //setteri - služe za postavljanje vrijednosti članskih varijabli
    
        void setDuzina(_duzina) {
            duzina = _duzina;
        }
    
        void setSirina(_sirina) {
            sirina = _sirina;
        }
    
        void setVisina(_visina) {
            visina = _visina;
        }
        
    //isto kao prije
        double izracunajPovrsinu(){   
            return duzina * sirina;
        }

        double izracunajVolumen(){   
            return duzina * sirina * visina;
        }
};
main.cpp
#include <iostream>

#include "prostorija.h"

using namespace std;

void main() {
    
    Prostorija soba("3", "4", "5");    
    Prostorija kuhinja("6", "7", "8");
    
    // članske varijable čitamo pomoću gettera i mijenjamo pomoću settera
    
    soba.setVisina("2.5");
    kuhinja.setVisina("3.5");
    
    kuhinja.getDuzina(); // 6
    
    cout << soba.izracunajPovrsinu(); //3 * 4 = 12
    
    cout << kuhinja.izracunajVolumen(); //6 * 7 * 3.5 = 147
}

Taksonomija klasa[uredi | uredi kôd]

Postoje mnoge kategorije klasa, od kojih se neke preklapaju.

Apstraktne i konkretne[uredi | uredi kôd]

U jezicima koji podržavaju nasljeđivanje, apstraktna klasa je klasa koja se ne može instancirati (ne mogu se stvarati objekti klasnog tipa) jer je označena kao apstraktna ili specificira apstraktne ili virtualne metode. Apstraktna klasa može sadržavati implementacije nekih metoda, i može definirati virtualne metode koje izravni ili neizravni potomci apstraktne klase trebaju nužno implementirati. Prije nego što se klasa izvedena iz apstraktne klase može instancirati, neka klasa u lancu izvođenja mora implementirati sve apstraktne metode svih roditeljskih klasa.[13]

Većina objektno orijentiranih programskih jezika dopušta programeru da specificira koje se klase smatraju apstraktnima, i sukladno tome jezik neće dopustiti njihovo instanciranje. Primjerice, u Javi, C# i PHP-u koristi se ključna riječ abstract.[14][15] Jezik C++, apstraktnom klasom smatra svaku klasu koja ima barem jednu virtualnu funkciju.[13]

U jeziku C++, klasa koja se sastoji samo od virtualnih metoda naziva se Pure Abstract Base Class (ili Pure ABC – čista apstraktna bazna klasa). Također se koristi i naziv sučelje.[10] Drugi jezici, osobito Java i C#, podržavaju deklaraciju interface kojom se označavaju klase s metodama bez implementacije. U tim jezicima višestruko nasljeđivanje klasa nije dopušteno, ali jedna klasa može implementirati više sučelja. Takva klasa može sadržavati samo apstraktne javno dostupne metode.[16][17][18]

Konkretna klasa je klasa koja se može instancirati, za razliku od apstraktnih klasa, koje se ne mogu instancirati.

Lokalne i unutarnje[uredi | uredi kôd]

U nekim jezicima klase se mogu deklarirati u opsegu (scope) koji nije globalan. Postoje razne vrste takvih klasa.

Unutarnja klasa je klasa definirana unutar druge klase. Unutarnja klasa obično nije povezana s instancama obuhvatne klase niti se instancira zajedno sa svojom obuhvatnom klasom. Povezani koncept su unutarnji ili ugnježđeni tip podatka (inner type, nested type), što je generalizacija koncepta unutarnjih klasa. C++ je primjer jezika koji podržava i unutarnje klase (deklaracija inner) i unutarnje tipove (deklaracija typedef).[19][20]

Drugi tip deklaracije opsega je lokalna klasa, odnosno klasa definirana unutar procedure ili funkcije. Ovo ograničava reference na naziv klase samo na opseg u kojem je klasa deklarirana. Ovisno o semantičkim pravilima jezika, mogu postojati dodatna ograničenja za lokalne klase. Jedno uobičajeno ograničenje je onemogućavanje metodama lokalne klase da pristupe lokalnim varijablama funkcije koja ih obuhvaća. Na primjer, u jeziku C++, lokalna klasa može pozivati statičke varijable deklarirane unutar njene obuhvatne funkcije, ali ne može pristupiti lokalnim (automatskim) varijablama funkcije.[21]

Metaklase[uredi | uredi kôd]

Metaklase su klase koje instanciraju druge klase.[4] Metaklasa opisuje zajedničku strukturu zbirke klasa i može implementirati obrazac dizajna ili opisati određene vrste klasa. Metaklase se često koriste za opisivanje frameworka.[22]

U nekim jezicima, kao što su Python, Ruby ili Smalltalk, klasa je također objekt; stoga je svaka klasa instanca jedinstvene metaklase koja je ugrađena u jezik.[3][4] Common Lisp Object System (CLOS) pruža metaobjektne protokole (MOP) za implementaciju tih klasa i metaklasa.[23]

Vidi također[uredi | uredi kôd]

Bilješke[uredi | uredi kôd]

  1. a b Gamma et al. 1995.
  2. a b Bruce 2002.
  3. a b 3. Data model. The Python Language Reference. Python Software Foundation. Pristupljeno 26. travnja 2012.
  4. a b c Booch 1994.
  5. Classes (I). C++ Language Tutorial. cplusplus.com. Pristupljeno 29. travnja 2012.
  6. Classes (II). C++ Language Tutorial. cplusplus.com. Pristupljeno 29. travnja 2012.
  7. a b Controlling Access to Members of a Class. The Java Tutorials. Oracle. Pristupljeno 19. travnja 2012.
  8. OOP08-CPP. Do not return references to private data. CERT C++ Secure Coding Standard. Carnegie Mellon University. 10. svibnja 2010. Inačica izvorne stranice arhivirana 3. listopada 2015. Pristupljeno 7. svibnja 2012.
  9. Ben-Ari, Mordechai. 24. siječnja 2007. 2.2 Identifiers (PDF). Compile and Runtime Errors in Java. Pristupljeno 7. svibnja 2012.
  10. a b Wild, Fred. C++ Interfaces. Dr. Dobb's. UBM Techweb. Pristupljeno 2. svibnja 2012.
  11. Thomas; Hunt. Classes, Objects, and Variables. Programming Ruby: The Pragmatic Programmer's Guide. Ruby-Doc.org. Pristupljeno 26. travnja 2012.
  12. Friendship and inheritance. C++ Language Tutorial. cplusplus.com. Pristupljeno 26. travnja 2012.
  13. a b Polymorphism. C++ Language Tutorial. cplusplus.com. Pristupljeno 2. svibnja 2012.
  14. Abstract Methods and Classes. The Java Tutorials. Oracle. Pristupljeno 2. svibnja 2012.
  15. Class Abstraction. PHP Manual. The PHP Group. Pristupljeno 2. svibnja 2012.
  16. Interfaces. The Java Tutorials. Oracle. Pristupljeno 1. svibnja 2012.
  17. Interfaces (C# Programming Guide). C# Programming Guide. Microsoft. Pristupljeno 15. kolovoza 2013.
  18. Inheritance (C# Programming Guide). C# Programming Guide. Microsoft. Pristupljeno 2. svibnja 2012.
  19. Nested classes (C++ only). XL C/C++ V8.0 for AIX. IBM. Pristupljeno 7. svibnja 2012.
  20. Local type names (C++ only). XL C/C++ V8.0 for AIX. IBM. Pristupljeno 7. svibnja 2012.
  21. Local classes (C++ only). XL C/C++ V8.0 for AIX. IBM. Pristupljeno 7. svibnja 2012.
  22. 13 Classes and metaclasses. pharo.gforge.inria.fr. Inačica izvorne stranice arhivirana 24. veljače 2021. Pristupljeno 31. listopada 2016.
  23. MOP: Concepts. The Common Lisp Object System MetaObject Protocol. Association of Lisp Users. Inačica izvorne stranice arhivirana 15. studenoga 2010. Pristupljeno 8. svibnja 2012.

Izvori[uredi | uredi kôd]

Daljnje čitanje[uredi | uredi kôd]