Professional Documents
Culture Documents
Cilj poglavlja
Razumijevanje koncepta enkapsulacije i skrivanja podataka
Razumijevanje notacije apstrakcije podataka i apstraktnih tipova podataka (ADT)
Ovladavanje kreiranjem apstraktnih (korisnikih) tipova podataka (ADT) u C++ = KLASE
Ovladavanje vjetinom kreiranja, koritenja i unitavanja objekata
Ovladavanje pristupom atributima (podaci lanice) i metodama (funkcije lanice)
Programiranje u jeziku C
Objektno orjentisano
Jedinica programiranja klasa (na osnovu koje se kreiraju objekti kao instance klase)
Programeri se koncentriu na kreiranje vlastitih tipova podataka KLASE
Imenice su te koje specificiraju sistem (imenice odreuju klase)
Svaka klasa sadri podatke i funkcije za manipulaciju podacima
Podaci koji se nalaze u klasi nazivaju se podaci lanice (data members)
Funkcije koje se nalaze u klasi nazivaju se funkcije lanice (metode)
Instance korisniki definisanih tipova (klasa) nazivaju se objekti
Primjer strukture:
struct Time {
int sat; // 0-23
int min; // 0-59
int sek; // 0-59
};
Mogue su sljedee instance ove strukture: promjenljiva (varijabla), niz, pokaziva, upuiva
Primjer:
Time timeObjekat, timeNiz[10], *timePtr, &timeRef = timeObjekat;
1
Implementacija (korisniki definisanih podataka) pomou strukture
Primjer kreiranja strukture, postavljanja lanica i ispisa
#include <iostream>
struct Time {
int sat; // 0-23
int min; // 0-59
int sek; // 0-59
};
void printMilitary( Time & );
void printStandard( Time & );
main()
{
Time vecera;
vecera.sat = 18; // postavljanje ispravnih vrijednosti
vecera.min = 30;
vecera.sek = 0;
cout << "Vrijeme za veceru u vojnom formatu: ";
printMilitary( vecera );
cout << " Vrijeme za veceru u standardnom formatu: ";
printStandard( vecera );
vecera.sat = 29; // postavljanje neispravnih vrijednosti
vecera.min = 73;
cout << "\nNekorektno vrijeme: " ;
printMilitary( vecera );
}
void printMilitary( Time &t )
{
cout << ( t.sat < 10 ? "0" : "" ) << t.sat << ":";
cout << ( t.min < 10 ? "0" : "" ) << t.min << endl;
}
void printStandard( Time &t )
{
cout << ( (t.sat == 12) ? 12 : t.sat % 12 ) << ":";
cout << ( t.min < 10 ? "0" : "" ) << t.min << ":" ;
cout << ( t.sek < 10 ? "0" : "" ) << t.sek ;
cout << ( t.sat < 12 ? " AM" : " PM" ) << endl;
}
Nekoliko je problema uoljivo ili se moe naslutiti ako se koriste strukture za kreiranje novih
tipova podataka:
Inicijalizacija podataka se ne zahtijeva prilikom kreiranja instance (promjenljive)
to moe da dovede do kasnijih problema u korienju podataka
ak i ako su inicijalizovani podaci, inicijalizacija moe biti nekorektna
pogrene vrijednosti mogu biti dodijeljene jer program direktno pristupa strukturi
ako se implementacija strukture promijeni (npr. ako se vrijeme pone izraavati u
sekundama proteklim od ponoi), itav program mora da se mijenja zato to PROGRAMER
DIREKTNO MANIPULIE PODACIMA I NJIHOVOM PREDSTAVOM
Nema interfejsa koji e omoguiti provjeru korektnosti i konzistentnost podataka
2
Implementacija (korisniki definisanih podataka) pomou klase
Klasa omoguava da se modeluje objekat koji ima:
atribute (podaci lanice data members)
ponaanje ili operacije (funkcije lanice member functions)
Funkcije lanice se u nekim drugim OO programskim jezicima zovu metode. Metode se izvravaju
kao odgovor na poruke (messages) koje se alju nekom objektu. Poruka je, u sutini, poziv funkcije
lanice od strane nekog objekta.
Definicija klase
class ime {
tip clan; privatne lanice klase sve do
... prve oznake public
public:
tip clan; javne lanice klase
...
private:
tip clan; privatne lanice klase
...
};
class Time {
public:
Time();
void setTime( int , int , int );
void printMilitary();
void printStandard();
private:
int sat; // 0 23
int min; // 0 59
int sek; // 0 59
};
3
Specifikatori pristupa lanicama:
public: sve lanice koje su definisane iza public su javne
dostupne su iz bilo kojeg dijela programa u kojem je dostupan objekat date klase
moe da im se pristupa i iz unutranjosti klase
uobiajeno je da su funkcije lanice javne lanice
U prethodnom primjeru imamo etiri javne funkcije lanice (Time, setTime, printMilitary,
printStandard). To su javne funkcije lanice ili javne usluge ili javne operacije (ponaanja) koje e
koristiti klijenti klase. Dakle, javne funkcije lanice pruaju neku uslugu klijentima klase, tanije funkcije
lanice neke metode omoguavaju interakciju sa objektima klase.
U prethodnom primjeru postoji funkcija lanica sa istim imenom kao i sama klasa. Ta funkcija
lanica naziva se konstruktor.
Konstruktor je specijalna funkcija lanica koja automatski poziva prilikom kreiranja objekta i
slui da bi se inicijalizovali podaci lanice prilikom kreiranja tog objekta.
Mogue je da klasa ima vie konstruktora (preklapanje imena funkcija).
Konstruktor ne vraa nikakav tip (ak ni void!)
Klasa je tip podataka. Kad je klasa definisana mogu se definisati i njene instance (objekat, niz
objekata, pokaziva na objekat i upuiva)
Primjer:
Deklaracija klase
class ime;
4
Primjer:
#include <iostream.h>
// definicija klase Time
class Time { public:
Time(); // konstruktor
void setTime( int , int , int );
void printMilitary();
void printStandard();
private:
int sat; // 0 - 23
int min; // 0 - 59
int sek; // 0 - 59
};
// definicija konstruktora
Time::Time()
{ sat = min = sek = 0; }
// definicija ostalih funkcija clanica
void Time::setTime( int h, int m, int s )
{
sat = ( h >= 0 && h < 24 ) ? h : 0;
min = ( m >= 0 && m < 60 ) ? m : 0;
sek = ( s >= 0 && s < 60 ) ? s : 0;
}
void Time::printMilitary()
{
cout << ( sat < 10 ? "0" : "" ) << sat << ":" ;
cout << ( min < 10 ? "0" : "" ) << min;
}
void Time::printStandard()
{
cout << ( (sat == 12) ? 12 : sat % 12 ) << ":" ;
cout << ( min < 10 ? "0" : "" ) << min << ":" ;
cout << ( sek < 10 ? "0" : "" ) << sek ;
cout << ( sat < 12 ? " AM" : " PM" );
}
// glavni program
main()
{
Time t; // kreira objekat t klase Time
cout << "Inicijalno vrijeme : ";
t.printMilitary();
cout << " ili ";
t.printStandard();
t.setTime( 13, 27, 6 );
cout << "\n\nNovo vrijeme : "; t.printMilitary();
cout << " ili "; t.printStandard();
t.setTime( 99, 99, 99 ); // uzaludan pokusaj
cout << "\n\nNovi pokusaj : "; t.printMilitary();
cout << " ili "; t.printStandard();
}
5
U prethodnom primjeru, glavni program kreira objekat t klase Time. Kad se objekat instancira
(kreira), automatski se poziva konstruktor Time() i inicijalizuje privatne atribute na nulu. Nakon toga
se to poetno vrijeme ispisuje u oba formata.
Potom se postavlja novo vrijeme pozivom funkcije lanice setTime, i vri odgovarajui ispis.
Nakon toga se pokuava definisati novo vrijeme, ali setTime to ne dozvoljava.
Funkcije lanice mogu da se definiu i unutar definicije klase. Meutim, praksa pokazuje
da je bolje da definicija klase sadri samo deklaraciju funkcija lanica (prototip), a da se
funkcije lanice onda definiu izvan definicije klase.
Primjer:
class Count {
public:
void print()
{ cout << x << endl; }
private:
int x;
};
Ako su funkcije lanice definisane izvan definicije klase, prilikom njihove definicije
koristi se operator za razrjeenje dosega kako bi se naglasilo da su to funkcije lanice date
klase. (Ovo je pogotovo bitno ako vie klasa ima funkcije lanice koje se isto zovu)
Funkcije lanice implicitno znaju da treba da koriste atribute (podatke lanice) klase, pa nema
potrebe za argumentima, to pozive metoda ini konciznijim nego pozive funkcija kod proceduralnog
programiranja.
6
Doseg (oblast definisanosti) klase i pristup lanicama klase
lanice klase dostupne su svim ostalim lanicama date klase i referenciraju se koritenjem svog imena.
Funkcije lanice mogu da se preklapaju. Tada treba u definiciji klase navesti prototip za sve
preklopljene fukcije, a izvan definicije klase dati definiciju svake od tih preklopljenih funkcija.
Primjer:
#include <iostream.h>
class Klasa {
public:
Klasa(); // konstruktor
void primjer();
private:
int x; // atribut
};
Klasa::Klasa() { x = 100; }
void Klasa::primjer()
{
int x=1; // lokalna promjenljiva
main()
{
Klasa t;
t.primjer();
}
Lokalno x : 1
Atribut x : 100
Globalno x : 0
7
lanicama klase pristupa se korienjem istih operatora kao da se radi o strukturi.
objekat.clanica
pointerNaObjekat->clanica ili (*pointerNaObjekat).clanica
Primjer:
#include <iostream.h>
class Count {
public:
int x;
void print() { cout << x << endl; }
};
main()
{
Count counter; // kreira objekat counter
Count *counterPok = &counter; // pointer na counter
Count &counterRef = counter; // upucivac na counter
7
8
10
8
Organizacija veih programa
Kod realizacije veih programa, preporuljivo je razdvojiti kod u vie fajlova, tj. odvojiti interfejs od
implementacije.
Primjer:
9
Pomone funkcije u klasi
Ne moraju sve funkcije lanice da budu javne, pogotovo ako one nisu dio interfejsa klase.
Ako neka funkcija slui kao pomona funkcija (helper function ili utility function)u klasi tako to je
njena uloga da npr. neto rauna ili slino za neku drugu funkciju lanicu klase, tada takvu pomonu
funkciju ostavljamo kao privatnu.
Funkcije lanice koje ine interfejs klase, odnosno omoguavaju pristup privatnim lanovima klase
nazivamo i pristupne funkcije (access functions).
Funkcije lanice koje provjeravaju ispunjenost ili neispunjenost nekog uslova (npr. da li je podatak
ovakav ili onakav, da li je tampa spreman, da li je lift zauzet i sl.) nazivaju se predikatske funkcije
(predicate functions).
Primjer:
#include <iostream.h>
class Prodaja { public: Prodaja();
void citajPodatke();
void postaviPodatak ( int , double );
void printTotal();
private: double total();
double iznos[7];
};
Prodaja::Prodaja()
{ for ( int i=0; i<7; iznos[i++] = 0.0 ); }
void Prodaja::citajPodatke()
{
double iznos;
cout << "Unesite dnevne iznose" << endl ;
for ( int i=1; i<=7; i++ )
{
cout << i << ". dan : ";
cin >> iznos;
postaviPodatak( i, iznos);
}
}
void Prodaja::postaviPodatak( int dan, double novac )
{
if ( dan >= 1 && dan <= 7 && novac >= 0 )
iznos[ dan-1 ] = novac;
else
cout << "Nekorektni podaci" << endl;
}
void Prodaja::printTotal()
{ cout << "Ukupna prodaja: " << total() << endl; }
10
Inicijalizacija objekata - KONSTRUKTORI
Kad kreiramo neki objekat, njegovi atributi mogu se inicijalizovati konstruktorom date klase.
Konstruktor ima isto ime kao to je ime klase. Konstruktor se automatski poziva svaki put kad se kreira neki
objekat.
Konstruktori mogu da se preklapaju (tj. da imamo vie konstruktora sa preklopljenim imenima u istoj klasi),
tako se omoguava vie razliitih poetnih stanja za objekte koji se kreiraju.
Podaci lanice (atributi) ne moraju se inicijalizovati korienjem konstruktora, nego nekom drugom funkcijom
lanicom (kao u prethodnom primjeru). Takve klase, npr. nemaju konstruktor.
Praksa pokazuje da je bolje da se atributi inicijalizuju odmah prilikom kreiranja!
Iako programer eksplicitno ne poziva konstruktor pri kreiranju objekta, ipak je mogue u konstruktor
prenositi neke parametre kojima e se inicijalizovati atributi. Ovi parametri nazivaju se inicijalizatori i
navode se unutar zagrada prilikom deklaracije objekta. Ovi inicijalizatori predstavljaju argumente koji se
prosljeuju konstruktoru klase.
Primjer: Primjer:
11
Primjer:
#include <iostream.h>
class Time { public:
Time( int = 0, int = 0, int = 0);
void setTime( int , int , int );
void printMilitary();
void printStandard();
private:
int sat, min, sek;
};
Time::Time( int h, int m, int s )
{ setTime( h, m, s ); }
void Time::setTime( int h, int m, int s )
{
sat = ( h >= 0 && h < 24 ) ? h : 0;
min = ( m >= 0 && m < 60 ) ? m : 0;
sek = ( s >= 0 && s < 60 ) ? s : 0;
}
void Time::printMilitary()
{
cout << ( sat < 10 ? "0" : "" ) << sat << ":" ;
cout << ( min < 10 ? "0" : "" ) << min;
}
void Time::printStandard()
{
cout << ( (sat == 12) ? 12 : sat % 12 ) << ":" ;
cout << ( min < 10 ? "0" : "" ) << min << ":" ;
cout << ( sek < 10 ? "0" : "" ) << sek ;
cout << ( sat < 12 ? " AM" : " PM" );
}
main()
{
Time t1; // sve vrijednosti podrazumijevane
Time t2(2); // minute i sekunde podrazumijevane
Time t3(21,34); // sekunde podrazumijevane
Time t4(12,25,42); // nema podrazumijevanih vrijednosti
Time t5(27,74,99); // sve vrijednosti nekorektne
cout << "t1: "; t1.printMilitary();
cout << " ili "; t1.printStandard();
cout << endl;
cout << "t2: "; t2.printMilitary();
cout << " ili "; t2.printStandard();
cout << endl;
cout << "t3: "; t3.printMilitary();
cout << " ili "; t3.printStandard();
cout << endl;
cout << "t4: "; t4.printMilitary();
cout << " ili "; t4.printStandard();
cout << endl;
cout << "t5: "; t5.printMilitary(); t1: 00:00 ili 0:00:00 AM
cout << " ili "; t5.printStandard(); t2: 02:00 ili 2:00:00 AM
cout << endl; t3: 21:34 ili 9:34:00 PM
} t4: 12:25 ili 12:25:42 PM
t5: 00:00 ili 0:00:00 AM
12
DESTRUKTORI
Destruktor je, poput konstruktora, jo jedna specijalna funkcija lanica klase.
I destruktor ima isto ime kao i klasa (konstruktor), ali se ispred stavlja tilda (~).
Intuitivno se moe napraviti analogija sa bitskim operatorom negacije, jer se destruktor ponaa kao
komplement konstruktora.
Primjer:
class Time {
public:
Time();
void setTime( int , int , int );
void printMilitary();
void printStandard();
~Time();
private:
int sat, min, sek;
};
Destruktor se poziva kad se neki objekat unitava. Destruktor sutinski ne unitava objekat, on samo isti
memoriju.
Klasa moe imati samo jedan destruktor. Nije dozvoljeno preklapanje imena destruktora.
Destruktori su izuzetno korisni za klase iji objekti dinamiki alociraju memoriju. (o tome kasnije)
13
Primjer:
#include <iostream.h>
class KonstDest {
public: KonstDest(int); // konstruktor
~KonstDest(); // destruktor
private: int data;
};
KonstDest::KonstDest( int x )
{
data = x;
cout << "Objekat " << data << " konstruktor";
}
KonstDest::~KonstDest()
{ cout << "Objekat " << data << " destruktor" << endl; }
void create( void )
{
KonstDest kd5(5);
cout << " (create: lokalni automatski)" << endl;
static KonstDest kd6(6);
cout << " (create: lokalni staticki)" << endl;
KonstDest kd7(7);
cout << " (create: lokalni automatski)" << endl;
}
14
Objekat kd1 je globalni. Njegov konstruktor poziva se prije main funkcije. Njegov destruktor poziva se po
zavretku programa nakon to su svi ostali objekti uniteni.
Funkcija main kreira tri objekta. Objekti kd2 i kd4 su lokalni automatski. Konstruktor se za svakog od njih
poziva na mjestima gdje su ovi objekti definisani. Destruktori za ova dva objekta pozivaju se odmah nakon
to se napusti funkcija main.
Objekat kd3 je statiki. On postoji sve dok se program ne zavri. Njegov destruktor poziva se neposredno
prije unitavanja kd1.
Funkcija create kreira tri objekta automatske kd5 i kd7, te statiki kd6. Ovi objekti kreiraju se
redoslijedom kojim su i definisani u funkciji.
Poto su kd5 i kd7 automatski, njihovi destruktori pozivaju se automatski nakon izlaska iz funkcije.
Poto je kd6 statiki, on postoji sve dok se program izvrava. Njegov destruktor poziva se prije destruktora
za kd3 i kd1. Mora se unititi prije kd3 jer je poslije kd3 kreiran.
Da je kd6 kreiran prije kd3, tada bi se kd6 unitio poslije kd3.
15
Primjer:
#include <iostream.h> void Time::printStandard()
class Time {
{ cout << ((sat==12) ? 12 : sat%12 );
public: cout << ":" ;
Time( int=0,int=0,int=0 ); cout << (min<10 ? "0":"" ) << min;
cout << ":" ;
void setTime( int,int,int ); cout << ( sek<10 ? "0":"" ) << sek;
void setSat( int ); cout << ( sat<12 ? " AM":" PM" );
void setMin( int ); }
void setSek( int );
void inkMin( Time &, const int );
int getSat();
int getMin(); main()
int getSek(); {
Time t;
void printMilitary();
void printStandard(); t.setSat(17);
t.setMin(34);
private: t.setSek(25);
int sat, min, sek; cout << "t1: " << t.getSat()
}; << ":" << t.getMin()
<< ":" << t.getSek() << endl;
Time::Time( int h, int m, int s )
{ setTime( h, m, s ); } t.setSat(234); t.setSek(6373);
cout << "t2: " << t.getSat()
void Time::setTime(int h,int m,int s) << ":" << t.getMin()
{ setSat(h); setMin(m); setSek(s); } << ":" << t.getSek() << endl;
t1: 17:34:25
t2: 0:34:0
Pocetno vrijeme: 11:58:00 AM
Inkrement za 3 minuta
Novo vrijeme : 12:01:00 PM
16
Dodjeljivanje objekata "lan po lan"
Operator dodjele (=) moe se koristiti da bi se jedan objekat dodijelio drugom (istog tipa)
Ovaka pristup moe da proizvede neeljene probleme kod objekata sa dinamikom alokacijom.
(O tome e biti rijei kasnije)
Primjer:
#include <iostream.h>
class Date {
public:
Date( int = 1, int = 1, int = 2001 );
void print();
private:
int dd, mm, gg;
};
void Date::print()
{ cout << dd << '.' << mm << '.' << gg; }
main()
{
Date dat1( 31, 12, 2004 );
Date dat2;
dat2 = dat1;
cout << "\n\nNakon kopiranja \ndat2 = ";
dat2.print();
}
dat1 = 31.12.2004
dat2 = 1.1.2001
Nakon kopiranja
dat2 = 31.12.2004
17
Konstantni objekti i konstantne funkcije lanice
Ranije smo vidjeli kako se definiu konstante instance standadnih tipova, koritenjem const.
Kljuna rije const moe da se koristi da se specificira da li neki objekat konstantan. Svaki pokuaj promjene
takvog objekta bie okarakterisan kao sintaksna greka.
Primjer:
Neka je definisana klasa:
class Time {
public:
Time(int = 0 , int = 0 , int = 0 );
void printMilitary();
void printStandard();
~Time();
private:
int sat, min, sek;
};
C++ kompajleri onemoguavaju poziv funkcija za konstantne objekte sve dok funkcija lanica
takoe nije deklarisana kao konstantna. Ovo vai ak i za get funkcije lanice!!!
Funkcija se proglaava konstantnom tako to se i u prototipu i u definiciji funkcije iza liste parametara, a
prije tijela funkcije navede kljuna rije const.
Primjer:
Funkcija lanica koja treba da vrati sat za neki konstantan objekat se deklarie na sljedei nain:
odnosno, definicija:
Ako se za datu klasu nee definisati konstantni objekti za koje bi trebala da se poziva neka od
funkcija lanica, funkcije lanice ne moraju da se definiu kao konstantne.
Ako se za neku klasu i definie konstantan objekat, a za taj objekat se nee pozivati funkcije
lanice, tada funkcije lanice date klase ne moraju da se definiu kao konstantne.
18
Primjer:
#include <iostream.h>
#include <math.h>
class Tacka
{
public:
Tacka ( double = 0 , double = 0 );
double getX() const;
double getY() const;
double daljina ( Tacka ) const;
void pisiTacka () const;
private:
double x, y;
};
main()
{
Tacka tA(3,4); // definisan objekat koji nije konstantan
const Tacka tO; // definisan konstantan objekat
Tacka A: 3,4
Tacka O: 0,0
Tacka A: (3,4)
Tacka O: (0,0)
Udaljenost od A(3,4) do O(0,0) iznosi: 5
Udaljenost od O(0,0) do A(3,4) iznosi: 5
19
Ako klasa sadri atribute koji nisu konstantni, tada se u konstruktoru inicijalizacija tih atributa
moe vriti na uobiajeni nain koritenjem operatora dodjele.
Npr.
Tacka::Tacka ( double xx, double yy) { x=xx; y=yy; }
Meutim, ako klasa sadri i neki konstantan atribut, tada se u konstruktoru inicijalizacija tih
konstantnih atributa ne moe vriti koritenjem operatora dodjele. Ako bi u prethodnoj klasi atribut
x bio konstantan, tada bi imali sljedei konstruktor:
Ako bi u prethodnoj klasi oba atributa (x i y) bili konstantni, tada bi imali sljedei konstruktor:
Primjer:
#include <iostream.h>
class Inkrement
{
public:
Inkrement( int b=0, int i=1 );
void dodaj() { brojac += korak; }
void print();
private:
int brojac;
const int korak; // konstantan atribut
};
void Inkrement::print()
{
cout << "brojac=" << brojac << ", korak=" << korak << endl;
}
main()
{
Inkrement data( 10, 5 );
20
Kompozicija: OBJEKAT kao ATRIBUT
Kad jedan objekat kao atribut ima neki drugi objekat, govorimo o kompoziciji.
Neka klasa moe da sadri jedan ili vie objekata drugih klasa. Tako npr. automobil ima motor, tokove,
sjedita, volan...
Kad se neki objekat kreira, njegov konstruktor se automatski poziva, pa treba specificirati kako se argumenti
prenose konstruktoru objektu lanu. Objekti lanice se kreiraju redoslijedom kojim su deklarisani u
definiciji klase (a ne redom kojim su navedeni u listi inicijalizatora u konstruktoru) i to prije nego to se
kreira objekat koji sadri te objekte lanice (ovaj se objekat esto naziva host objekat)
Primjer:
#include <iostream.h> class Osoba {
class Datum { public:
public: Osoba( char *, int , int , int );
Datum( int=1, int=1, int=2000 ); void print() const ;
void print() const ; ~Osoba();
~Datum(); private:
private: char ime[15];
int dd, mm, gg; const Datum rodjen;
int provjeriDan( int ); };
};
Osoba::Osoba(char *s, int d, int m, int g)
Datum::Datum( int d, int m, int g ) : rodjen( d, m, g )
{ {
gg = g; int bs=0;
mm = (m>0 && m<=12) ? m : 1; while ((ime[bs]=*(s+bs)) && bs<14)
dd = provjeriDan ( d ); bs++;
cout << "Konstruktor za datum: "; if (bs==14) ime[bs]='\0';
print(); cout << endl; cout << "Konstruktor za osobu : "
} << ime << endl;
}
void Datum::print() const
{ cout << dd<<'.'<<mm<<'.'<<gg<<'.'; } void Osoba::print() const
{
Datum::~Datum()
cout << ime << " je rodjen: ";
{
rodjen.print();
cout << "Destruktor za datum: ";
cout << endl;
print(); cout << endl;
}
}
Osoba::~Osoba()
int Datum::provjeriDan( int dan )
{ cout << "Destruktor za osobu : "
{
<< ime << endl; }
static const int mjeseci[13] =
{0,31,28,31,30,31,30,31,31,30,31,30,31}; main()
if ( dan>0 && dan<=mjeseci[mm] ) {
return dan; Osoba otac ("Marko", 28,2,1975),
if ( mm==2 && dan==29 && sin ("Janko", 29,2,2000),
(gg%400==0 || (gg%4==0 && gg%100!=0))) pradeda("Slavko",29,2,1900);
return dan; otac.print(); sin.print();
return 1; pradeda.print();
} }
21
Prijateljske funkcije i prijateljske klase
Prijateljska funkcija neke klase je funkcija definisana izvan dosega te klase, ali koja ima pravo
pristupa privatnim lanovima date klase. (kod nasljeivanja emo vidjeti da da moe i zatienim
lanicama te klase)
Da bi se funkcija deklarisala kao prijateljska funkcija klase, prototip te funkcije treba se navede u definiciji
date klase, pri emu prototip treba da zapoinje kljunom rijeju friend.
class Klasa {
friend tip funkcija... ;
...
}
Da bi se klasa A deklarisala kao prijateljska klasa klasi B, u definiciji klase B treba da se navede deklaracija:
class B {
friend class A ;
...
}
Sada su sve funkcije lanice klase A prijateljske funkcije klase B.
"Prijateljstvo se daruje, a ne uzima!!!".
Da bi klasa A bila prijatelj klasi B, klasa B mora eksplicitno da deklarie da joj je klasa A prijatelj.
"Prijateljstvo nije simetrino!!!".
Ako je klasa A prijatelj klase B to ne znai da je i klasa B prijatelj klasi A.
"Prijateljstvo nije tranzitivno!!!".
Ako je klasa A prijatelj klase B i ako je klasa B prijatelj klase C, to ne znai da je klasa A prijatelj klase C.
Mogue je koristiti i preklopljene prijateljske funkcije. Tada prototip svake od tih funkcija mora
biti deklarisan kao prijateljski u definiciji date klase.
Primjer:
#include <iostream.h>
class Data
{
friend void setX ( Data &, int ); // deklaracija prijatelja
public:
Data() { x=0; }
void print() const { cout << x << endl; }
private:
int x;
};
void setX( Data &dat, int val )
{
dat.x = val; // dozvoljeno: setX je prijatelj klase Data
}
main()
{
Data d;
cout << "d.x nakon kreiranja: "; d.print();
setX( d, 10 ); // postavi x pomocu prijatelja
cout << "d.x nakon poziva setX: ";
d.print(); d.x nakon kreiranja: 0
} d.x nakon poziva setX: 10
22
Pokaziva this
Osim formalnih argumenata, metode imaju i jedan "skriveni" argument (skriveni zato to se
ne vidi u prototipu funkcija). Taj argument je zapravo tekui objekat objekat za koji je
funkcija pozvana.
Adresa skrivenog argumenta (tekueg objekta) za vrijeme izvravanja funkcije lanice nalazi se
u pokazivau this. Svaki objekat ima pristup svojoj vlastitoj adresi preko pokazivaa this.
Primjer:
#include <iostream.h>
class Test {
public:
Test( int = 0 );
void print() const ;
private:
int x;
};
Test::Test( int a ) { x = a; }
main()
{
Test t(12); x = 12
t.print(); this->x = 12
} (*this).x = 12
U prethodnom primjeru ilustrovana je primjena this pokazivaa u funkciji lanici u kojoj se tampa vrijednost
privatnog atributa x datog objekta.
Navoenje *this.x bilo bi sintaksna greka jer je to *(this.x).
Jedna interesantna upotreba pokazivaa this je da se sprijei dodjela objekta samome sebi.
(vie rijei bie kod preklapanja operatora - kad "samododjela" moe dovesti do pozbiljnih greaka pri
dinamikoj alokaciji)
23
Primjer:
U prethodnom primjeru funkcije lanice setTime, setSat, setMin i setSek vraaju *this jer su to metode
iji je tip Time &. Ovakve funkcije lanice omoguavaju kaskadno pozivanje.
Asocijativnost operatora "." je slijeva udesno, pa iskaz
t.setSat(18).setMin(30).setSek(22);
zapravo znai sljedee: Prvo se izvrava t.setSat(18) to vraa upuiva na objekat t. Preostaje
t.setMin(30).setSek(22). Izvrava se t.setMin(30) to vraa upuiva na objekat t, pa preostaje
t.setSek(22).
24
Statiki (zajedniki) lanovi klase
Prilikom definisanja klase, lanice mogu da se proglase statikim stavljanjem kvalifikatora
static ispred date lanice. Ovakvom definicijom se lanica proglaava zajednikom za sve
objekte date klase stvorene tokom izvravanja programa.
lanice klase koje nisu zajednike, nazivaju se pojedinane lanice.
I atributi i funkcije lanice mogu biti zajedniki
Zajedniki atributi
Ako je atribut zajedniki, to znai da postoji samo jedan primjerak tog atributa, bez obzira na broj objekata.
Pristup zajednikom atributu je pristup istoj memorijskoj lokaciji.
Mijenjanjem vrijednosti zajednikog atributa utie se na stanje svih objekata te klase.
Primjer:
class Klasa {
...
static int a; // definicija zajednickog clana
int b; // definicija pojedinacnog clana
...
}
int Klasa::a = 55; // zajednicki atribut za sve objekte Klase
25
Zadatak
Rjeenje:
#include <iostream.h>
class Complex {
public:
Complex ( double = 0, double = 0 );
Complex saberiComplex (Complex &);
void printComplex ();
private:
double re, im;
};
void Complex::printComplex()
{ cout << "(" << re << "," << im << ")"; }
main()
{
Complex c1(1,3), c2(2,5), c3;
Za vjebu:
26
Zadatak
Rjeenje:
#include <iostream.h>
class Razlomak
{
public:
Razlomak ( int = 0, int = 1 );
Razlomak saberi ( Razlomak & );
void printRazlomak ( void );
private:
int broj;
int imen;
};
Za vjebu:
Dodati i ostale funkcije lanice u datu klasu (oduzimanje, mnoenje, dijeljenje, skraivanje...)
27