Professional Documents
Culture Documents
US - Programski Jezik C++ Sa Rešenim Zadacima PDF
US - Programski Jezik C++ Sa Rešenim Zadacima PDF
Programski jezik
Ranko Popovi
Zona Kosti
sa reenim zadacima
UNIVERZITET SINGIDUNUM
Beograd, 2010.
PROGRAMSKI JEZIK C++ SA REENIM ZADACIMA
Autori:
Prof. dr Ranko Popovi
Zona Kosti
Recenzenti:
Prof. dr Dragan Cvetkovi
Dr Boko Nikoli, docent
Izdava:
UNIVERZITET SINGIDUNUM
Beograd, Danijelova 32
www.singidunum.ac.rs
Za izdavaa:
Prof. dr Milovan Stanii
Tehnika obrada:
Ranko Popovi
Dizajn korica:
Aleksandar Mihajlovi
Godina izdanja:
2010.
Tira:
250 primeraka
tampa:
Mladost Grup
Loznica
ISBN: 978-86-7912-286-5
Predgovor
-3-
Sadraj
Predgovor ....................................................................................................... 3
Sadraj ........................................................................................................... 4
1. Uvod .......................................................................................................... 6
1.1 Programski jezik C++ .......................................................................... 6
1.2 Proirenja programskog jezika C ......................................................... 7
1.3 Jednostavan C++ program ................................................................... 9
1.4 Celi brojevi i aritmetika ..................................................................... 16
2. Realni brojevi, iteracije i donoenje odluka ............................................ 23
2.1 Realni brojevi..................................................................................... 23
2.2 Iteracije (petlje) .................................................................................. 30
2.3 Donoenje odluke .............................................................................. 38
2.4 Pravila prioriteta ................................................................................ 42
3. Koncept funkcije ...................................................................................... 49
3.1 Definicija funkcije ............................................................................. 49
3.2 Prosleivanje parametara po vrednosti .............................................. 52
3.3 Promenljive kao atributi .................................................................... 54
4. Nizovi ...................................................................................................... 57
4.1 Definicija niza .................................................................................... 57
4.2 Viedimenzionalni nizovi .................................................................. 64
5. Pokazivai ................................................................................................ 68
5.1 Deklarisanje i inicijalizacija pokazivaa ........................................... 68
5.2 Pokazivai i nizovi ............................................................................. 71
6. C-stringovi, pokazivai, nizovi, funkcije, korisniki definisani tipovi
podataka i tabele .......................................................................................... 76
6.1 Definicija i inicijalizacija stringa ....................................................... 76
6.2 String konstante i pokazivai ............................................................. 79
6.3 Nizovi stringova i pokazivaa ........................................................... 83
6.4 Pokazivai, reference na promenljive i funkcije................................ 86
6.5 Nizovi i funkcije ................................................................................ 93
6.6 Stringovi i funkcije ............................................................................ 98
6.7. Korisniki definisani tipovi podataka i tabele ................................ 110
6.8 Strukture .......................................................................................... 112
6.9 Nizovi struktura: tabele.................................................................... 117
7. Uvod u klase i objekte ........................................................................... 119
7.1 Objekti, klase i objektno orijentisani sistemi ................................... 119
-4-
7.2 Uvod u string objekte ....................................................................... 121
7.3 Donoenje odluka u radu sa stringovima ......................................... 131
7.4 Funkcije i string objekti ................................................................... 133
7.5 Primeri rada sa string objektima ...................................................... 138
7.6 Nizovi stringova ............................................................................... 147
8. Programerski definisane klase i objekti ................................................ 148
8.1 Deklarisanje objekata i klasa............................................................ 148
8.2 Konstruktor klase ............................................................................. 150
8.3 Preklapanje konstruktora.................................................................. 160
8.4 Destruktori ....................................................................................... 164
8.5 Opte preklapanje funkcija i abloni funkcija .................................. 174
9. Rad sa objektima .................................................................................... 178
9.1 Korienje nizova, pokazivaa i dinamika alokacija memorije ..... 178
9.2 Konstruktor kopije ........................................................................... 185
9.3 Korienje rezervisane rei const u radu sa klasama ....................... 197
9.4 Objekti, funkcije i pokazivai .......................................................... 215
9.5 Dinamika alokacija objekata .......................................................... 241
9.6 Statiki podaci lanovi i funkcije ..................................................... 247
10. Nasleivanje ......................................................................................... 256
10.1 Primeri nasleivanja i osnovna terminologija ................................ 256
10.2 Polimorfizam.................................................................................. 278
10.3 Apstraktne osnovne klase............................................................... 297
11. Fajlovi .................................................................................................. 299
11.1 Ulazno/izlazni tokovi ..................................................................... 299
11.2 Procesiranje fajla karakter po karakter........................................... 321
11.3 Sluajni pristup fajlu ...................................................................... 325
11.4 Procesiranje binarnog fajla sekvencijalno...................................... 332
12. Specijalne teme: Prijateljske funkcije, preklapanje operatora, makroi i
inline funkcije ............................................................................................ 338
12.1 Prijateljske (friend) funkcije .......................................................... 338
12.2 Preklapanje osnovnih aritmetikih operatora ................................. 344
12.3 Makroi i inline funkcije ................................................................. 359
Dodatak A: Integrisano razvojno okruenje Microsoft Visual C++ .......... 365
Dodatak B: Integrisano razvojno okruenje Microsoft Visual C++ 2008 . 394
Reference: .................................................................................................. 412
-5-
1. Uvod
1.1 Programski jezik C++
-6-
projektovanje nego na samu implementaciju (kodovanje). Razmilja se
najpre o problemu, a tek naknadno o programskom reenju. Razmilja se o
delovima sistema (objektima) koji neto rade, a ne o tome kako neto radi
-7-
Ako se promenljivoj tipa bool dodeljuje numerika vrednost, vrednost nula
se pretvara u false, a bilo koja nenulta vrednost u true.
Znakovne konstante, na primer A, u jeziku C++ su tipa char dok u
jeziku C su tipa int. To dovodi do toga da se A i 65 razliito tretiraju, bez
obzira to u sluaju korienja ASCII koda imaju istu brojanu vrednost. U
jeziku C te dve vrednosti ne mogu da se razlikuju ni pod kojim uslovima.
U jeziku C++, dodavanjem modifikatora const na poetku naredbi za
definisanje podataka dobijaju se prave konstante, pod uslovom da su
inicijalizatori konstantni izrazi. Tako uvedeni identifikatori predstavljaju
simbolike konstante koje mogu da se koriste i na mestima na kojima se
izriito trae konstante.
Deklarativne naredbe u jeziku C++ smatraju se izvrnim naredbama i
mogu da se koriste bilo gde u programu gde su naredbe dozvoljene, a ne
samo na poetku pojedinih blokova. Doseg uvedenih identifikatora se
protee od mesta definisanja do kraja bloka unutar kojeg su definisani.
Identifikatori nabrajanja, struktura i unija u jeziku C++ mogu da se
koriste kao identifikatori tipa bez slubenih rei enum, struct, odnosno union,
pod uslovom da su jedinstveni u svojim dosezima.
Pokazivau na podatke poznatih tipova u jeziku C++ ne moe da se
dodeli vrednost generikog pokazivaa (void*).
U jeziku C argumenti su prenoeni funkciji iskljuivo po vrednosti.
Da bi neka funkcija mogla da promeni vrednost neke spoljne promenljive,
trebalo je preneti pokaziva na tu promenljivu. U jeziku C++ mogu je i
prenos po referenci. Referenca ili upuiva je alternativno ime za neki
podatak. Reference mogu da budu formalni argumenti i vrednosti funkcije.
Za potrebe dodele memorije u dinamikoj zoni memorije u vreme
izvravanja programa, u jeziku C++ uvedeni su operatori new i delete.
Veliina dodeljenog prostora pomou operatora new automatski se odreuje
na osnovu veliine podatka (kod funkcija iz C jezika malloc, calloc i realloc,
veliina mora da se navede, obino primenom operatora sizeof).
Za vrlo male funkcije, pozivanje funkcije i povratak iz funkcije moe
da traje znatno due od izvravanja samog sadraja funkcije. Za takve
funkcije je efikasnije da se telo funkcije ugradi neposredno u kd na svakom
mestu pozivanja. To, pored utede u vremenu, esto znai i manji utroak
memorije. Treba dodati modifikator inline na poetku definisanja funkcije.
U jeziku C nije bilo mogue definisati dve funkcije sa istim imenom.
Mehanizam preklapanja imena funkcija (eng. function overloading) u jeziku
C++ omoguava da se srodnim funkcijama daju ista imena. Pod
preklapanjem imena funkcija podrazumeva se definisanje vie funkcija sa
-8-
istim modifikatorima. Sve te funkcije mora da se meusobno razlikuju po
broju i/ili tipovima argumenata na nain koji obezbeuje njihovu
jednoznanu identifikaciju.
Imenski prostori (namespace) slui za grupisanje globalnih imena u
velikim programskim sistemima u vie dosega.
Objekat je neko podruje u memoriji podataka tokom izvravanja
programa. To moe biti eksplicitno definisana promenljiva (globalna ili
lokalna), ili privremeni objekat koji nastaje pri izraunavanju izraza.
Objekat je primerak nekog tipa (ugraenog ili klase), ali ne i funkcije.
C++ je strogo tipizirani jezik, odnosno svaki objekat ima tano
odreeni tip. Kada se oekuje objekat jednog tipa, a koristi objekat drugog
tipa, potrebno je izvriti konverziju tipova.
-9-
Drugi korak: dizajn programa - postoji vie naina da se opie dizajn
programa. Dva prosta metoda su dijagram toka i pseudokod. Dijagram toka
je grafiki opis dizajna programa koji koristi kombinaciju razliitih simbola.
Pseudokod opisuje dizajn programa izbegavajui sintaksu programskog
jezika naglaavajui dizajn reenja problema.
Kada dizajnirate program, vano je da proverite njegovu logiku pre
nego to ponete da piete sam programski kd. Dizajner programa je esto
suvie blizak sa dizajnom da bi video neke greke.
Trei korak: pisanje koda - koraci 3, 4, 5 i 6 - se izvravaju u
integrisanom razvojnom okruenju (eng. Integrated Development
Environment, IDE). Primeri ovih okruenja su: Visual Studio.NET, Borland
Enterprise Studio (windows platforma), Code Forge (Linux okruenje),
KDevelop (Unix okruenje).
Pisanje koda programa u tekst editoru odgovarajueg programskog
jezika, kao i kompajliranje, odnosno prevoenje izvornog programa ili sors
koda (eng. source) su sledei koraci.
Korak 4: kompajliranje (prevoenje) i linkovanje (povezivanje)
programa - jedini jezik koji dati raunar razume je njegov sopstveni
mainski jezik. Instrukcije mainskog jezika su binarno kodirane instrukcije
- 10 -
(sastavljene od nula i jedinica) koje kau raunaru da treba da uradi
odreeni zadatak, kao to je add (dodaj) 1 u registar. Svaki raunar ima svoj
sopstveni mainski jezik koji se meusobno razlikuju. Kako je mainski
jezik binarni, teko je pisati kod i pronai greke u mainskom
programskom jeziku. Poto raunar razume samo svoj sopstveni mainski
jezik, on ne moe da direktno izvrava instrukcije programskih jezika
srednjeg i visokog nivoa. Raunar koristei program koji se zove kompajler
(prevodilac), treba da prevede programe programskih jezika u ekvivalentne
programe mainskog jezika. PC bazirani C++ kompajler prevodi C++ u PC
mainski jezik. Kompajler ne moe da prevede razliite jezike (kao to je
Java) i ne moe se koristiti na razliitim tipovima raunara (kao to je
Macintosh).
- 11 -
programskog jezika. Ako kompajler ne nae fatalne greke, on prevodi
svaku instrukciju jezika visokog nivoa u jednu ili vie instrukcija mainskog
jezika. Ova verzija sors programa na mainskom jeziku se zove objektni
program.
Mada je na mainskom jeziku, objektni program nije spreman za
izvrenje. Program moe da sadri reference, nazvane spoljne reference,
prema drugim programima koje je korisnik napisao ili koje C++ kompajler
obezbeuje na korienje svim korisnicima sistema. U oba sluaja treba da
koristite program koji se zove linker da bi razreili ove spoljne reference.
Linker nalazi druge programe koji su deo vaeg programa. Ovaj proces je
linkovanje-povezivanje. Linker proizvodi izvrivi kd (executable code).
Ovo je program koji raunar izvrava.
Korak 5: Izvravanje programa - kada se program kompajlira i
linkuje on moe i da se izvri preko ikone, menija ili komandne linije.
Korak 6: testiranje i debagovanje programa - ak i kada se program
izvrava ne znai da je korektan-ispravan. Program treba testirati pod
raznim uslovima i sa raznim podacima.
Greke u ciklusu
// Vas prvi program u C++ koji ispisuje na monitoru (konzolni izlaz) tekstaulne
//poruke
#include <iostream>
using namespace std;
int main()
{
cout << "This is our first C++ program." << endl;
cout << "It works!!!" <<endl;
- 12 -
Prve dve linije koda su komentari. Komentar poinje sa dva
karaktera // i nastavlja do kraja linije. Komentar nije izvrna naredba, sledi,
kompajler ignorie sve od // do kraja linije.
Prazne linije ili blank moete da postavite bilo gde u programu kako
bi poveali preglednost programa.
C++ program je kolekcija funkcija koje rade zajedno u cilju reenja
problema. Svaki program mora da sadri funkciju main(). Ova funkcija
kontrolie C++ program izvravajui C++ naredbe i druge funkcije. Re int
koja prethodi rei main() kae C++ kompajleru da main() proizvodi (vraa)
celobrojnu vrednost.
Svaki postupak se naziva izraz (eng. expression). Izraz koji se
zavrava znakom taka-zapeta ";" naziva se naredba (eng. statement).
Zanemarivanje znaka ; izaziva sintaksnu greku pri kompajliranju. Kada
biste napisali glavni program na sledei nain, kompajler ne bi prijavio
sintaksnu greku.
int main(){ cout << "This is our first C++ program." << endl; cout << "It works!!!" <<endl;
cout << endl; return 0;}
C++ je case sensitive, tj. kada piemo C++ naredbe postoji razlika
izmeu velikih slova i malih slova. Na primer: int Main() je nepravilno, treba
da stoji int main().
Izlaz na monitor je tok podataka (eng. data stream), odnosno niz
karaktera. Tok cout (konzolni izlaz "console output" i ita se kao "see-out")
predstavlja standardni izlazni tok, koji se automatski prikazuje na
korisnikovom monitoru kada se C++ program izvrava. Podaci se mogu
poslati na izlazni tok cout koristei operator umetanja (eng. insertion
operator), <<, koji se ita kao "poslato je" ili "uzima se". String (niz
karaktera) se postavlja unutar znaka navoda.
Zavretak linije i skok u novi red se ostvaruje pomou endl (eng. end
of line) i odgovara specijalnoj sekvenci '\n'.
- 13 -
Poslednja naredba return zavrava izvrenje funkcije main() i alje
ceo broj ija je vrednost 0 operativnom sistemu da bi pokazala da se
program zavrio normalno.
Kompajliranje C++ programa se izvodi u dva koraka. Prvo, program
nazvan pretprocesor analizira C++ sors kod i izvrava sve pretprocesorske
direktive. Svaka direktiva poinje karakterom #. Drugi korak kompajliranja
je prevoenje programa u mainski kod.
Direktiva #include kao rezultat ima zamenu linije koja sadri direktivu
#include tekstom sadraja heder (eng. header) fajla koji je unutar zagrada < >,
tako da on postaje deo vaeg programa i kao takav se prevodi sa naredbama
vaeg programa.
Heder fajlovi obino sadre informacije o konstantama, funkcijama,
klasama i drugim C++ elementima koji se esto pojavljuju u C++
programima. Heder fajl iostream (input/output stream), je jedan od
standardnih skupova sistemskih heder fajlova kojim je svaki od C++
kompajlera snabdeven. Heder fajl iostream sadri informacije o standardnim
ulazno/izlaznim tokovima.
Treba obratiti panju da se pretprocesorska direktiva
#include <iostream>
- 14 -
da moemo direktno da koristimo sva imena unutar std prostora imena (cout i
cin su dva takva imena).
Sva standardom predviena zaglavlja sve globalne identifikatore
stavljaju u imenski prostor std. Standardom je predviena mogunost da
uskladitavanje standardnih zaglavlja ne bude (mada moe) u vidu
tekstualnih datoteka. Zbog toga imena standardnih zaglavlja ne sadre
proirenja imena .h, to je uobiajeno u jeziku C.
Rezervisane rei
Do sada smo koristili rezervisane rei (kljune, slubene rei ili eng.
keywords) kao to su int, using, namespace i return. One imaju posebno znaenje
i predstavljene su u tri grupe:
Prva grupa 32 slubene rei iz C jezika:
- 15 -
reda na ekranu monitora je \n (eng. newline character). Sledee dve linije
koda proizvode isti efekat kao u prethodnom primeru:
\a upozorenje
\b backspace
\f formfeed
\n novi red
\r carriage return
\t horizontalni tabulator
\v vertikalni tabulator
\\ obrnuta kosa crta
\? znak pitanja
\' jednostruki znaci navoda
\" dvostruki znaci navoda
\000 oktalni broj
\xhh heksadecimalni broj
Identifikatori
- 16 -
(ceo broj int, znak char i realni broj float i double) i korisniki definisane
tipove. Iza tipa podatka dolazi ime promenljive i zavrni znak naredbe
(taka zarez ";").
Na primer, ovo je deklaracija promenljive:
int i1;
#include <iostream>
using namespace std;
int main()
{
// Deklaracija promenljivih
int i1,
i2,
sum,
- 17 -
difference,
product,
quotient,
remainder;
// Dobijanje podataka od korisnika
cout << "Input an integer followed by a return: ";
cin >> i1;
cout << "Input an integer followed by a return: ";
cin >> i2;
// Izvrsavanje aritmetickih operacija
sum = i1 + i2;
difference = i1 - i2;
product = i1 * i2;
quotient = i1 / i2;
remainder = i1 % i2;
// Izlazni rezultati
cout << endl;
cout << "The sum of " << i1 << " and " << i2 << " is " << sum << endl;
cout << "The difference of " << i1 << " and " << i2 << " is "
<< difference << endl;
cout << "The product of " << i1 << " and " << i2 << " is "
<< product << endl;
cout << "The quotient of " << i1 << " and " << i2 << " is "
<< quotient << endl;
cout << "The remainder when " << i1 << " is divided by " << i2
<< " is " << remainder << endl;
return 0;
}
- 18 -
operator, >>). Naredba cin >> i1; uzima ceo broj koji korisnik ukuca na
tastaturi kao odziv na prompt i smeta vrednost celog broja
u varijablu i1.
Celi brojevi koje korisnik ukuca na tastaturi se ne
alju odmah programu na procesiranje. Umesto toga
raunar smesti karaktere u privremenu lokaciju za
skladitenje zvanu ulazni bafer. Raunar alje ove karaktere
programu kada korisnik pritisne taster. Ovo nazivamo
pranjenje ulaznog bafera (eng. flushing the input buffer).
Operator dodele ili pridruenja (eng. assignment
operator) =, radi na sledei nain: raunar razvija izraz na
desnoj strani operatora =, i dodeljuje rezultujuu vrednost
varijabli na levoj strani znaka =. Ime varijable mora da
bude na levoj strani operatora dodele. Izraz na desnoj strani
je celobrojna konstanta, koja moe biti pozitivna, negativna
ili jednaka nuli.
Aritmetiki operatori
Operatori Asocijativnost
() sa leva na desno
+ (unarni) - (unarni) sa desna na levo
*/% sa leva na desno
+- sa leva na desno
= sa desna na levo
#include <iostream>
#include <iomanip>
using namespace std;
- 19 -
int main()
{
const int HOURLY_RATE = 44;
int parts, // Cena delova
hours, // Broj radnih sati
labor, // Cena rada
total; // Ukupna cena za korisnika
cout << "Enter the cost of parts: ";
cin >> parts;
cout << endl;
cout << "Enter the number of hours worked: ";
cin >> hours;
cout << endl;
// Trazena izracunavanja
labor = HOURLY_RATE * hours;
total = parts + labor;
// Prikaz rezultata
cout << "Cost of parts: " << setw(5) << parts << endl;
cout << "Labor charge: " << setw(6) << labor << endl;
cout << "--------------" << endl;
cout << "Total charge: " << setw(6) << total << endl;
return 0;
}
cout << "Cena delova: " << setw(5) << parts << endl;
- 20 -
prvo prikazuje string "Cena delova: " ("Cost of parts: ") sa blanko pozicijom
nakon dvotake. Zatim, manipulator setw(5) kae cout-u da smesti sledei
uzorak u polje irine 5. Na taj nain variabla parts, ija je vrednost 239, je
prikazana u poslednje tri pozicije od pet pozicija polja kao na donjoj slici:
Za drugu naredbu:
cout << "Cena rada: " << setw(6) << labor << endl;
short k = 3;
int i = 8;
long j = 56;
#include <iostream>
- 21 -
using namespace std;
int main()
{
const int HOURLY_RATE = 44;
long parts, // cena delova
hours, // broj radnih sati
labor, // cena rada
total; // ukupna cena za korisnika
// Unos ulaznih podataka
cout << endl;
cout << "Enter the cost of parts: ";
cin >> parts;
cout << endl;
cout << "Enter the number of hours worked: ";
cin >> hours;
// Izracunavanje
labor = HOURLY_RATE * hours;
total = parts + labor;
// Prikaz rezultata
cout << endl;
cout << "Cost of parts: " << setw(9) << parts << endl;
cout << "Labor charge: " << setw(10) << labor << endl;
cout << "------------------------" << endl;
cout << "Total charge: " << setw(10) << total << endl;
return 0;
}
- 22 -
2. Realni brojevi, iteracije i donoenje odluka
2.1 Realni brojevi
Realni broj, ili floating point, je broj koji ima decimalni deo, tj.
decimalnu taku. Postoje dva tipa floating point C++ podataka float i double.
Sledee deklaracije definiu varijablu fl koja je tipa float i varijablu db koja je
tipa double.
float fl;
double db;
- 23 -
Operator dodele daje varijabli db3 rezultat sa desne strane 76.72949.
Izraz sa desne strane operatora dodele sadri razliite tipove podataka. Pre
nego to uradi aritmetike operacije, raunar automatski konvertuje
celobrojnu vrednost 2 u realan broj 2.0. Zatim raunar mnoi vrednost db1 sa
2.0, to daje 6.28318. Konano, raunar dodaje ovaj rezultat vrednosti db2,
to daje 76.72949. Raunar tada izvrava operaciju dodele vrednosti koja je
na desnoj strani, promenljivoj db3 na levoj strani.
Tip float ima preciznost samo sedam cifara, pa se ne moe tano
raditi sa vrednostima veim od 99.999,99. Zbog toga to veina modernih
poslovnih transakcija ukljuuje brojeve vee od 100.000,00 evra, tip float je
neadekvatan.
- 24 -
cout << 0.0825 * 19.95
- 25 -
1728394.85
1.65
356.70
#include <iostream>
#include <iomanip>
using namespace std;
int main()
{
const double TAX_RATE = 0.0825;
double base_price, // cena jednog dela
tax, // porez
price; // prodajna cena (price + tax)
//definisanje izlaza
- 26 -
return 0;
}
#include <iostream>
#include <iomanip>
using namespace std;
int main()
{
const double SALES_TAX_RATE = 0.0825;
double meal_price, // cena obroka koju je uneo korisnik
sales_tax, // iznos poreza na promet
total, // ukupno: meal_price + sales_tax
amt_tendered, // iznos dobijen od korisnika
change; // kusur: amt_tendered - total
// Definisanje izlaza
cout << setprecision(2)
<< setiosflags(ios::fixed)
<< setiosflags(ios::showpoint);
- 27 -
cout << endl;
cout << "Price of Meal: " << setw(6) << meal_price << endl;
cout << "Sales Tax: " << setw(10) << sales_tax << endl;
cout << "---------------------" << endl;
cout << "Total Amount: " << setw(7) << total << endl;
// Izracunavanje kusura
change = amt_tendered - total;
return 0;
}
- 28 -
Kada aritmetiki izraz sadri vie promenljivih tipa int ili long i vie
promenljivih tipa float ili double, C++ automatski konvertuje sve promenljive
u tip double pre nego to izvri aritmetike operacije. Sledi, rezultat je tipa
double.
Tip cast (nakon koga sledi izraz u malim zagradama) menja tip
podatka vrednosti koja je ukljuena u odreeni tip, na primer
int i = 5;
double(i);
Primeri iz aritmetike
int h = 17;
i,
j,
k;
i = j = k = h;
ili
Operatori Asocijativnost
() sa leva na desno
+ (unarni) - (unarni) sa desna na levo
*/% sa leva na desno
+- sa leva na desno
= += -= *= /= sa desna na levo
- 29 -
Operatori uveanja i umanjenja (eng. increment, decrement)
poveavaju ili smanjuju vrednost promenljive za jedan. Mogu da se koriste
pre ili posle varijable sa prefiksom pre ili post. To su unarni operatori. Na
donjoj slici je dat primer.
Izraz
j = 4 + -- i j = 4 + i --
Inicijalna vrednost i je 7
Upotrebljena vrednost i 6 7
Dodeljena vrednost j 10 11
Konana vrednost i 6 6
Relacioni uslovi
#include <iostream>
using namespace std;
int main()
{
int i = 3,
j = 8,
k = 5,
result;
result = (i < j < k);
cout << "result = " << result << endl;
return 0;
}
- 30 -
Kompajler e upozoriti korisnika:
Operatori Asocijativnost
() [] -> . Sa leva u desno
! ~ ++ -- + - * (type) sizeof Sa desna u levo
*/% Sa leva u desno
+- Sa leva u desno
<< >> Sa leva u desno
< <= > >= Sa leva u desno
== != Sa leva u desno
& Sa leva u desno
^ Sa leva u desno
| Sa leva u desno
&& Sa leva u desno
|| Sa leva u desno
?: Sa desna u levo
= += -= *= /= %= &= ^= |= <<= >>= Sa desna u levo
, Sa leva u desno
- 31 -
Beskonane petlje: while i do
Petlja while
while (kontrolni-izraz)
telo-petlje
int count = 0;
while (count < 5)
{
++count;
cout << "Hello" << endl;
}
cout << endl;
cout << "Hello je prikazan " << count << " puta." << endl;
- 32 -
broji karaktere jedne linije koje korisnik unosi sa tastature. Linija je niz
karaktera zavrena sa return odnosno enter. Return nije deo linije i ne broji
se kao karakter. Program ne zna unapred broj karaktera koje e korisnik da
unese.
Znakovna konstanta (eng. character constant) je prost karakter
unutar jednostrukih znaka navoda. Na primer, 'A' i ';' su znakovne konstante.
Moete da dodelite znakovnu konstantu promenljivoj tipa karakter (eng.
character variable) na isti nain kao to se dodeljuje brojna konstanta
brojnoj promenljivoj. Moete da incijalizujete promenljivu tipa karakter u
deklaraciji
char ch = 'A';
Korienje cin.get()
char ch;
// Ovaj program broji karaktere sa ulaza koje korisnik unosi kao jednu liniju
// Linija se zavrsava ukucavanjem return, koji se ne broji kao karakter
#include <iostream>
using namespace std;
int main()
{
char ch; // Koristi se da skladisti ulazni karakter
int num_chars = 0; // Broji karaktere
cout << "Enter any number of characters terminated by return."
- 33 -
<< endl << endl;
return 0;
}
ch = cin.get();
- 34 -
Proces se nastavlja sve dok izvrenje ch = cin.get() u telu petlje ne
dodeli ch karakter za novi red '\n', kada je uslov false.
Efikasnije reenje umesto dela koda
je:
do-while petlja
while petlja testira uslov petlje pre nego to izvri telo petlje. Sledi,
ako je uslov petlje netaan- false prvi put kada se testira, program nee da
izvrava telo petlje. Ponekad je potrebno da se program izvri najmanje
jednom pre nego to se testira uslov. Ova petlja se zove do-while, ili do,
petlja.
Format naredbe je:
do
loop body
while (uslov petlje);
U prethodnom primeru deo koda napisan sa do-while naredbom je:
do
{
ch = cin.get();
++num_chars;
}
while (ch != '\n');
--num_chars;
Odreene petlje
Kada se zna tano koliko esto program treba da izvrava telo petlje
koristi se odreena iteraciona petlja, odnosno for petlja.
- 35 -
for petlja
int line_count = 1;
int line_count;
for (line_count = 1; line_count <= 25; ++line_count)
cout << endl;
- 36 -
Ugnjeene while petlje
#include <iostream>
using namespace std;
int main()
{
int ch; // skladisti karakter koji unosi korisnik
int num_chars = 0; // broji karaktere koji se unose
cout << "Ovaj program broji ukupan broj karaktera" << endl
<< "koje ukucate u vise linija. Svaku liniju zavrsavate ukucavajuci Enter"<< endl
<< "Program zavrsavate ukucavajuci Enter, [Ctrl]+Z, i Enter." << endl << endl;
return 0;
}
- 37 -
Promenljiva ch u koju se smeta karakter koji korisnik unosi preko
tastature je tipa int umesto tipa char. Jedina razlika u skladitenju karaktera
recimo 'a', u varijablu tipa int, umesto u varijablu tipa char, je da int varijabla
zahteva 2 ili 4 bajta memorije dok promenljiva tipa karakter zahteva 1 bajt
(dva bajta za Unicode karaktere) memorije. U oba sluaja karakter 'a' je
uskladiten kao ceo broj ija je vrednost 97.
Operator Znaenje
! negacija
&& i
ili
- 38 -
Operator not !
int i = 7;
char ch;
if (!(i == 3))
ch = 'A';
else
ch = 'B';
Operator and && kombinuje dva uslova na sledei nain: (uslov 1) &&
(uslov 2). Tablica istinitosti za operator konjukcije je true samo ako su oba
uslova true; inae, vrednost je false.
Uslov 1
&& T F
T T F
Uslov 2
F F F
Primer:
- 39 -
Mada C++ esto ne zahteva to, treba da koristite zagrade za svaki prost
uslov zbog jasnijeg prikaza koda.
Sledei program pita korisnika da ukuca jedan karakter i zatim return.
Program testira karakter da li je broj i prikazuje odgovarajuu poruku.
#include <iostream>
using namespace std;
int main()
{
char ch;
ch = cin.get();
cout << "The key you pressed was a digit." << endl;
else
cout << "The key you pressed was not a digit." << endl;
return 0;
}
or operator || (disjunkcija)
- 40 -
samo kada su oba uslova false. Donja tabela daje vrednosti istinitosti za
disjunkciju za razliite kombinacije uslova.
Uslov 1
T F
T T T
Uslov 2
F T F
#include <iostream>
using namespace std;
int main()
{
char ch;
ch = cin.get();
return 0;
}
- 41 -
2.4 Pravila prioriteta
Operatori Asocijativnost
() sa leva na desno
! + (unarni) - (unarni) ++ -- sa desna na levo
*/% sa leva na desno
+- sa leva na desno
< <= > >= sa leva na desno
== != sa leva na desno
&& sa leva na desno
|| sa leva na desno
= += -= *= /= sa desna na levo
int i = 7,
result;
Kako && ima vei prioritet od ||, raunar izraunava, odnosno razvija
konjukciju prvo. Uslov (i != 0) je istinit i uslov (i <= 10) je istinit. Zbog toga,
konjukcija ova dva uslova je true. Ceo uslov u naredbi je true. Zbog toga
kod postavlja vrednost result na 1. Donja slika prikazuje razvoj sloenog
uslova.
- 42 -
Ovaj primer pokazuje interesantan aspekt kako C++ razvija logike
izraze; C++ koristi razvoj kratkog spoja (eng. short-circuit). Kada raunar
zakljui da konjukcija (i != 0) && (i <= 10) daje true, on zna da konaan
rezultat disjunkcije sa uslov (i == 17) mora biti true. Zbog toga raunar ne
testira drugi uslov da vidi da li je promenljiva i jednaka 17.
Ugnjeene naredbe
Sledei karakter
cin.get();
employee_code = cin.get();
- 43 -
switch naredba
Najei celobrojni izraz je prosta int ili char varijabla. Telo switch
naredbe mora biti u velikim zagradama. Telo switch naredbe se sastoji od
skupa sluajeva. Svaki sluaj poinje oznakom case, nakon toga sledi case
vrednost i dvotaka. Vrednost sluaja je mogua vrednost koju celobrojni
izraz moe da dobije. Program izvrava naredbe ako je vrednost celobrojnog
izraza jednaka vrednosti sluaja koja je u case oznaci. Napomena, telo
naredbe moe biti bez naredbe.
Naredba default (opciona je) sadri naredbe koje program treba da
izvri ako vrednost celobrojnog izraza nije jednaka bilo kojoj vrednosti sa
oznakom case.
#include <iostream>
#include <iomanip>
#include <cstdlib>
int main()
{
- 44 -
const double RESIDENTIAL_RATE = 0.060;
const double MULTIDWELLING_RATE = 0.050;
const double COMMERCIAL_RATE = 0.045;
int property_code;
double sale_price,
commission_rate,
commission;
cout << setprecision(2)
<< setiosflags(ios::fixed)
<< setiosflags(ios::showpoint);
cin.get(); // Odbaci \n
property_code = cin.get();
switch (property_code)
{
case 'R':
case 'r':
commission_rate = RESIDENTIAL_RATE;
break;
case 'M':
case 'm':
commission_rate = MULTIDWELLING_RATE;
break;
case 'C':
case 'c':
commission_rate = COMMERCIAL_RATE;
break;
default:
cout << endl << endl
<<"Invalid Property Code! Try Again" << endl;
exit(1);
break;
}
- 45 -
commission = sale_price * commission_rate;
return 0;
}
Naredba break
#include <iostream>
int main()
{
int ch, // uneti karakter
count = 0; // broji karaktere pre pojave prvog @ karaktera
- 46 -
break;
++count;
}
if (ch == '\n')
{
cout << endl;
cout << "You did not enter a @ character." << endl;
cout << "You entered " << count << " characters." << endl;
}
else
{
cout << endl;
cout << "You entered " << count
<< " characters before the first @"
<< endl;
}
return 0;
}
Naredba continue
Naredba continue prekida tok kontrole unutar while, do-while, ili for
petlje. Meutim, umesto zavretka kao kod naredbe break, naredba continue
zavrava samo tekuu iteraciju. Sledea iteracija petlje poinje odmah nakon
toga.
// Ovaj program broji karaktere (velika slova) koje korisnik unese kao jednu liniju
#include <iostream>
using namespace std;
int main()
- 47 -
{
int ch, // uneti karakter
count = 0; // broj unetih velikih slova
return 0;
}
Ukucali ste " << count << " velika slova" << endl;
- 48 -
3. Koncept funkcije
Objasniemo prirodu funkcija i nauiti kako da deklariemo,
definiemo i koristimo proste funkcije.
- 49 -
Korienje void u deklaraciji
void Print_10_Xs();
int main()
{
int i;
cout << endl;
void Print_10_Xs()
{
int j;
return;
}
- 50 -
Argument/parametar
int main()
{
int i,
number_of_rows;
char ch;
- 51 -
3.2 Prosleivanje parametara po vrednosti
#include <iostream>
void PreInc(int);
int main()
{
int i;
// Promenljiva i je inicijalizovana na 5.
i = 5;
cout << "Pre poziva funkcije PreInc(), i = " << i << endl;
PreInc(i);
cout << "Nakon poziva funkcije PreInc(), i = " << i << endl;
- 52 -
++parm;
return;
}
#include <iostream>
using namespace std;
int main()
{
int midterm_exam,
final_exam,
final_grade;
- 53 -
cout << endl;
cout << "The Final Grade is " << final_grade << endl;
double grade;
int rounded_grade;
return rounded_grade;
}
- 54 -
se deklarie promenljiva. Na taj nain, svaka funkcija ija definicija dolazi
posle deklaracije globalne promenljive moe da promeni vrednost globalne
promenljive. Treba izbegavati korienje globalnih promenljivih deljenjem
podataka izmeu funkcija koristei argumente i povratne vrednosti.
Trajanje (duration)
- 55 -
Prikazaemo primere korienja dve proste matematike funkcije.
Funkcija pow(osnova, eksponent) stepenuje prvi argument osnovu sa
drugim argumentom tj. eksponentom. Oba argumenta moraju biti dvostruke
preciznosti. Funkcija vraa double tip. Dakle
p = be .
Naredba
- 56 -
4. Nizovi
4.1 Definicija niza
Deklarisanje niza
Primer niza ije je ime rate, iji su elementi tipa double, koji moe da
memorie 5 vrednosti je:
double rate[5];
- 57 -
double rate[5] = {0.075, 0.080, 0.082};
double rate[5];
rate[] = {0.075, 0.080, 0.082, 0.085, 0.088}; // pogresna dodela
- 58 -
#include <iostream>
#include <iomanip>
int Get_Valid_Region();
int main()
{
// Sledeca deklaracija definise niz rate[] sa 5 celobrojnih vrednosti
return 0;
} //Kraj "main()" funkcije
int Get_Valid_Region()
{
bool invalid_data;
int region;
do
{
cout << endl;
cout << "Enter shipping region (1-5): ";
cin >> region;
if (region < 1 || region > 5)
- 59 -
{
cerr << endl;
cerr << "Region in invalid - Please reenter.";
invalid_data = true;
}
else
invalid_data = false;
}
while(invalid_data);
return region;
}
#include <iostream>
#include <iomanip>
using namespace std;
int main()
{
const int NUM_QUIZZES = 10;
int grade[NUM_QUIZZES]; //Niz za skladistenje ocena sa kviza
int quiz, // Indeks niza
grade_sum = 0;
double grade_avg;
- 60 -
cout << setprecision(1)
<< setiosflags(ios::fixed)
<< setiosflags(ios::showpoint);
return 0;
}
- 61 -
Sortiranje niza
#include <iostream>
#include <iomanip>
using namespace std;
int main()
{
const int NUM_QUIZZES = 10;
// Unos ocena
- 62 -
cout << endl;
return 0;
}
- 63 -
4.2 Viedimenzionalni nizovi
int class_grades[5][10];
- 64 -
int class_grades[5][10] = {{50, 56, 87, 67, 98, 90, 68, 54, 67, 30},
{70, 68, 64, 78, 97, 57, 68, 90, 67, 74},
{64, 76, 87, 67, 95, 67, 56, 83, 60, 78},
{76, 65, 84, 47, 86, 65, 46, 66, 87, 65},
{76, 57, 65, 45, 90, 76, 76, 44, 67, 82}};
int array[BR_REDOVA][BR_KOLONA];
Spoljna for petlja ulazi u prvu iteraciju za prvi red niza (indeks 0).
Unutranja petlja procesira svaki elemenat niza reda odreenog indeksom
niza (u prvom sluaju 0), itd.
#include <iostream>
#include <iomanip>
int main()
{
- 65 -
const int NUM_QUIZZES = 10;
const int NUM_STUDENTS = 5;
int class_grades[NUM_STUDENTS][NUM_QUIZZES];
int student,
quiz,
quiz_sum;
double quiz_average;
return 0;
}
- 66 -
- 67 -
5. Pokazivai
U ovom poglavlju predstavljamo ideju pointera odnosno pokazivaa,
kako ih deklarisati, inicijalizovati itd. Takoe, objasniemo kako se moe
menjati vrednost promenljive.
- 68 -
da ste dali validnu vrednost pokazivau dodelom adrese promenljive na koju
on pokazuje. Unarni operator adresa od (&), vraa adresu promenljive na
koju je primenjen, na primer, ako je i celobrojna promenljiva, onda je &i
njena adresa.
Inicijalizacija pokazivaa
int i = 5;
double d = 3.14;
int* i_ptr = &i;
double* d_ptr = &d;
int i;
double* d_ptr = &i; // pogresna inicijalizacija pokazivaca
- 69 -
double* d_ptr = NULL;
char* c_ptr = NULL;
Operator indirekcije
Deklariimo i i i_ptr:
int i;
int* i_ptr = &i;
Direktna dodela je
i = 17;
*i_ptr = 17;
#include <iostream>
- 70 -
int main()
{
int i;
int* i_ptr = &i;
cout << "The address of i is " << &i << endl;
cout << "The value of i_ptr is " << i_ptr << endl << endl;
*i_ptr = 17;
cout << "The value of i is " << i << endl << endl;
cout << "The value of *i_ptr is " << *i_ptr << endl;
return 0;
}
- 71 -
Sledeu dodelu ne smete da uradite:
nums_ptr = nums;
- 72 -
Vano je napomenuti da je aritmetika pokazivaa unutar niza
skalirana na tip niza. Na primer, pretpostavimo sledeu deklaraciju
- 73 -
Treba voditi rauna da aritmetika pokazivaa ne pree broj
elemenata niza. C++ kompajler nee vas upozoriti ako napravite ovakvu
greku. Pristup takvim lokacijama moe da prouzrokuje run-time greku u
programu ili moe da prouzrokuje nekorektne rezultate.
#include <iostream>
#include <iomanip>
int main()
{
int nums[5] = {3, 4, 5, 6, 7};
int* nums_ptr;
int i;
return 0;
}
- 74 -
- 75 -
6. C-stringovi, pokazivai, nizovi, funkcije, korisniki
definisani tipovi podataka i tabele
Ova sekcija razmatra rad sa stringovima. Poinjemo sa osnovnim
idejama i tehnikama za rad sa stringovima.
greeting
H e l l o \0
- 76 -
zakljuak o veliini niza iz inicijalizovanih vreednosti. Sledi, ova
deklaracija je ekvivalentna prethodnoj deklaraciji.
char buffer[6];
cin.getline(buffer, 6);
#include <iostream>
#include <iomanip>
int main()
{
double const TAX_RATE = 0.0825;
- 77 -
char item_name[51];
double price,
tax,
total;
return 0;
}
item_name
C o m p u t e r \0
- 78 -
6.2 String konstante i pokazivai
// Ovaj program broji karaktere jedne linije sa ulaza koje unosi korisnik.
// Koristi se pointer za kretanje kroz string i while petlja za brojanje karaktera
#include <iostream>
int main()
{
char line[81];
char* ch_ptr = line;
int count = 0;
- 79 -
while ( *ch_ptr != '\0' )
{
++count;
++ch_ptr;
}
cout << endl;
cout << "The string you entered has " << count << " characters." << endl;
return 0;
}
#include <iostream>
- 80 -
cout << "Enter a line of characters:" << endl << endl;
cin.getline(line, 81);
- 81 -
#include <iostream>
int main()
{
char line[81];
char* ch_ptr;
int word_count = 0;
// Preskakanje reci
for ( ; (*ch_ptr != ' ') && (*ch_ptr != '\0'); ++ch_ptr)
;
// Preskakanje praznih pozicija nakon reci
for ( ; *ch_ptr == ' '; ++ch_ptr)
;
}
cout << "\nThe line you entered has " << word_count << " words."
<< endl;
return 0;
}
- 82 -
6.3 Nizovi stringova i pokazivaa
U jeziku C++ elementi niza mogu biti podaci bilo kog tipa. U ovom
poglavlju posmatraemo nizove stringova i nizove pokazivaa.
char dani_u_nedelji[7][10];
- 83 -
Korienje niza stringova - primer
#include <iostream>
#include <iomanip>
total_sales = 0;
max_day = 0;
max_sales = sales[0];
- 84 -
{
max_sales = sales[day];
max_day = day;
}
total_sales += sales[day];
}
cout << endl << endl;
cout << "The total sales for " << salesperson
<< " is " << total_sales << "." << endl << endl;
cout << "The highest sales was " << max_sales << "." << endl << endl;
cout << "The highest sales occurred on "
<< dani_u_nedelji[max_day]<< "." << endl;
return 0;
}
- 85 -
char* dani_u_nedelji [7] = {"Ponedeljak", "Utorak", "Sreda",
"Cetvrtak", "Petak", "Subota", "Nedelja"};
#include <iostream>
int Neg_By_Value(int);
int main()
{
int i = 4;
i = Neg_By_Value(i);
- 86 -
cout << "i = " << i << endl;
return 0;
}
int Neg_By_Value(int a)
{
return -a;
}
#include <iostream>
void Neg_By_Address(int*);
int main()
{
int i = 4;
Neg_By_Address(&i);
- 87 -
cout << "i = " << i << endl;
return 0;
}
Neg_By_Address(&i);
- 88 -
Prosleivanje adrese varijable funkcije se oznaava kao poziv po
adresi (eng. call by address).
#include <iostream>
int main()
{
int i = 3,
j = 5;
cout << "Before swapping: i = " << i<< " j = " << j << endl;
Swap_Int(&i, &j);
cout << "After swapping: i = " << i<< " j = " << j << endl;
return 0;
temp = *a_ptr;
*a_ptr = *b_ptr;
*b_ptr = temp;
}
- 89 -
Prototip funkcije Swap_Int() deklarie njenu povratnu vrednost da
bude tipa void zato to funkcija ne vraa vrednost. Umesto toga, Swap_Int()
zamenjuje vrednosti dve celobrojne promenljive u pozivajuoj funkciji
koristei pokazivae. Oba argumenta funkcije su deklarisana kao integer
pointeri. Sledi, mora da prosledimo adrese dve celobrojne promenljive
funkciji.
Deklaracija varijabli i i j u main() funkciji inicijalizuje varijable na 3 i
5, respektivno. Naredba cout prikazuje poetne vrednosti za i i j. Zatim main()
funkcija izvrava Swap_Int() funkciju izvravajui sledeu naredbu, koja
prosleuje adrese za i i j funkciji Swap_Int().
Swap_Int(&i, &j);
int i = 7;
double d = 1.2;
int& r = i;
double& s = d;
- 90 -
lokaciji. Sledi, moete pristupiti sadraju varijable ili preko originalnog
imena varijable ili preko reference.
Moemo da promenimo sadraje promenljive i koristei identifikator
i ili referencu r. Na primer, bilo koja od ovih naredbi promenie vrednost
promenljive i na 9.
i = 9;
r = 9;
Pokazivai i reference
- 91 -
kao argumente funkcija. U ovim sluajevima, prosleujemo argumente po
referenci ili koristei poziv po referenci. Kao primer poziva po referenci
posmatrajmo sledei program:
// Ovaj program prikazuje prosledjivanje argumenata po referenci
#include <iostream>
void Neg_By_Reference(int&);
int main()
{
int i = 4;
Neg_By_Reference(i);
return 0;
}
void Neg_By_Reference(int& a)
a = -a;
}
#include <iostream>
- 92 -
int main()
{
int i = 3,
j = 5;
cout << "Before swapping: i = " << i<< " j = " << j << endl;
Swap_Int(i, j);
cout << "After swapping: i = " << i<< " j = " << j << endl;
return 0;
}
temp = a;
a = b;
b = temp;
}
- 93 -
double Avg(int [], int);
Funkcija Avg() vraa vrednost tipa double i ima dva parametra. Prvi
parametar je niz promenljivih tipa int. Srednje zagrade [] kau kompajleru da
se radi o nizu. Definicija funkcije koja odgovara prethodnom prototipu je:
#include <iostream>
#include <iomanip>
int main()
{
const int NUM_QUIZZES = 10;
cout << "Please enter " << NUM_QUIZZES << " integer quiz grades."
<< endl << endl;
- 94 -
cout << "The average quiz grade is " << grade_avg << endl;
return 0;
return avg;
- 95 -
Sortiranje niza
#include <iostream>
#include <iomanip>
Get_Grades(grade, NUM_QUIZZES);
Bubble_Sort(grade, NUM_QUIZZES);
- 96 -
void Get_Grades(int arr[], int size)
{
int quiz;
return;
return;
- 97 -
return;
- 98 -
funkcijama. Takoe, prikazaemo kako se definie i koristi funkcija koja
vraa pokaziva.
int Len_String(char*);
// Ovaj program izracunava broj karaktera jedne linije koju korisnik unese sa
// tastature
// Za brojanje karaktera koristi se funkcija Len_String()
#include <iostream>
using namespace std;
int Len_String(char*);
int main()
{
char line[81];
return 0;
} // Kraj funkcije main()
- 99 -
return length;
} // Kraj funkcije Len_String()
#include <iostream>
void Reverse_String(char*);
int main()
{
char line[81];
- 100 -
Reverse_String(line);
cout << endl;
cout << "The string in reverse is as follows:" << endl;
cout << line << endl;
return 0;
}
void Reverse_String(char* ch_ptr)
{
char* front; // Pokazuje na pocetak stringa
char* end; // Pokazuje na kraj stringa
char temp; // Potrebno za zamenu karaktera
// inicijalizacija pokazivaca
front = end = ch_ptr;
--end;
// zamena karaktera
while (front < end)
{
temp = *front;
*front = *end;
*end = temp;
++front;
--end;
}
return;
}
- 101 -
Reverse_String(line);
#include <cstring>
int length;
char greeting[6] = "Hello";
length = strlen(greeting);
- 102 -
Biblioteka funkcija strcpy() dodeljuje jedan string drugom kopirajui
izvorni string, karakter po karakter u target string, ija veliina je
odgovarajua. Funkcija ima sledei format:
strcpy(target-string-name, source-string-name)
strcpy(greeting2, greeting1);
char* ch_ptr;
strcmp(string1, string2)
- 103 -
Poreenje karakter po karakter nastavlja se dok se ne naie na
razliite karaktere (funkcija vraa negativan ceo broj ako prvi string
prethodi drugom, a pozitivan ceo broj ako prvi string sledi drugi, prema
vrednostima karaktera u tabeli ASCII koda) ili dok se ne doe do kraja
karaktera koji su isti (funkcija vraa 0).
Pretpostavimo sledee deklaracije i inicijalizacije:
char string1[5] = "abcd";
char string2[5] = "abCd";
char string3[7] = "abcd ";
char string4[5] = "abCd";
strcat(target-string, source-string)
strcat(string1, string2);
- 104 -
Funkcije za klasifikaciju prema karakterima
- 105 -
Napisaemo program koji pita korisnika da ubaci string (do 80 karaktera) i
odluuje da li je string palindrom.
Veoma je prosto da se odlui da li je re palindrom. Proverava se da
se vidi da li su prvi i poslednji karakter isti. Ako nisu, string nije palindrom.
Ako su isti, proverava se sledei par karaktera. Kada se stigne do sredine
rei i ako su svi karakteri jednaki, re je palindrom.
String mora biti oien od praznih karaktera, sa malim slovima i
bez znakova interpunkcije.
Primer koristi string "Madam, I'm Adam!" i program skladiti string
u niz line[]. Da bi se oistio string od blanko znakova i znakova
interpunkcije, program kopira string u drugi niz buffer[], kopira samo slovne
karaktere. Program zatim menja sve karaktere u nizu buffer[] u mala slova.
Konano, program proverava da li je rezultujua re palindrom.
// Ovaj program koristi bibliotecke funkcije za rad sa stringovima i karakterima
// kako bi ocenio da li je string koji korisnik unosi palindrom.
// Palindrom je string koji se isto cita unapred i unazad
// String mora biti ociscen od praznih karaktera, sa malim slovima i bez znakova
// interpunkcije
#include <iostream>
#include <cctype>
int main()
{
char line[81];
char buffer[81];
// Unost stringa
Copy_Alpha(buffer, line);
- 106 -
Convert_To_Lower(buffer);
// Testira se rezultat da li je palindrom
if ( Palindrome(buffer) )
{
cout << endl;
cout <<"The string you entered is a palindrome." << endl;
}
else
{
cout << endl;
cout <<"The string you entered is not a palindrome." <<endl;
}
return 0;
return;
return;
- 107 -
{
char* start;
char* end;
--end;
return true;
} // Kraj Palindrome() funkcije
- 108 -
Dinamika alokacija memorije
Hip (heap) memorija
char client[5][81];
int* i_ptr;
i_ptr = new int;
int* arr_ptr;
arr_ptr = new int [20];
- 109 -
Memorija za statike i automatske promenljive i hip memorija
Naredba typedef
Na primer:
- 110 -
Ako je:
Naredba enum
RESPONSE result;
result = 1;
- 111 -
U deklaraciji tipa nabrajanja ne treba da se da lista identifikatora
vrednosti koje su uzastopne od 0 pa navie. U deklaraciji
6.8 Strukture
struct PART_STRUCT
{
char part_no[8];
int quantity_on_hand;
double unit_price;
};
- 112 -
PART_STRUCT promenljive. Kao i kod enum, naredba struct ustvari definie
drugi tip podatka, sama po sebi ne deklarie promenljivu. Takoe, part_no,
quantity_on_hand, i unit_price lanovi strukture su prosto imena strukture i nisu
promenljive.
Struktura PART_STRUCT je podeljena na tri dela odnosno tri lana,
part_no, quantity_on_hand, i unit_price, po tom redosledu.
PART_STRUCT
part_no quantity on_hand unit_price
PART_STRUCT part;
PART_STRUCT
part_no quantity on_hand unit_price
part.quantity_on_hand = 62;
- 113 -
Sledei program prikazuje kako pristupiti lanu strukture:
// Ovaj program ilustruje deklaraciju i koriscenje promenljive tipa strukture
// i operatora clan za pristup varijablama koje su clanovi strukture.
#include <iostream>
#include <iomanip>
struct PART_STRUCT
{
char part_no[8];
int quantity_on_hand;
double unit_price;
};
int main()
{
PART_STRUCT part;
return 0;
}
- 114 -
Nakon dobijanja podataka sa tastature od korisnika, moemo da
oznaimo sadraj promenljivih part tipa strukture kao na slici:
part
Sloene strukture
struct NAME_STRUCT
{
char first_name[31];
char mid_initial;
- 115 -
char last_name[31];
};
struct ADDRESS_STRUCT
{
char st_adress[31];
char city[31];
char state[3];
char zip[6];
};
struct EMPLOYEE_STRUCT
{
NAME_STRUCT name;
ADDRESS_STRUCT address;
char soc_sec_no[10];
double pay_rate;
};
EMPLOYEE_STRUCT employee;
Promenljiva employee tipa struktura ima etiri lana, kao na slici. Prvi
lan name je struktura tipa NAME_STRUCT. Drugi lan address je struktura tipa
ADDRESS_STRUCT, trei lan soc_sec_no je niz kraktera. etvrti lan je tipa
double.
Ako elimo da inicijalizujemo kod za dravu od dva karaktera za
promenljivu employee na "NY", treba da koristimo operator lana dva puta:
employee.address.state
strcpy(employee.address.state, "NY");
employee.address.state[0]
- 116 -
6.9 Nizovi struktura: tabele
struct PART_STRUCT
{
char part_no[8];
int quantity_on_hand;
double unit_price;
};
PART_STRUCT part_table[10];
- 117 -
part_table[4].quantity_on_hand = 102;
- 118 -
7. Uvod u klase i objekte
7.1 Objekti, klase i objektno orijentisani sistemi
- 119 -
isti metod (niz akcija) kao to je podizanje novca sa vaeg rauna. Ono to
se razlikuje su stanja, odnosno vrednosti podataka koji se nalaze u objektu.
Stanje savings account objekta moe da ukljui korisnikov ID lan, balance
stanje i interest rate - kamatnu stopu.
Ovo je princip skrivanja informacija poiljalac poruke ne treba da
zna nain na koji se primalac brine o zahtevu.
Koja je razlika izmeu objektno orijentisanog pristupa slanja poruka
i proceduralnog pristupa koji koristi funkcije? Prvo, kod objektno
orijentisanog programiranja, poruke imaju prijemnik. Funkcije nemaju
prijemnik. Funkcije obino rade na neemu. Na primer, proceduralna verzija
ATM sistema za podizanje 100 izvrava poziv funkcije na sledei nain:
Withdraw(your_account, 100.00);
- 120 -
cout << "The value is " << price;
ch = cin.get();
cin.getline(name, 81);
C-string smo definisali kao niz karaktera. Objekti klase string su laki
za rad, bezbedniji i prirodniji za korienje od C-stringova. Nije vano da
znate kako su string objekti ili operacije na njima implementirani. Vano je
da znate kako da koristite string objekte.
Klasa string je ugraena u C++, tako da je nije potrebno deklarisati na
bilo koji nain osim ukljuenjem direktive
#include <string>
- 121 -
podacima kao to je duina stringa. Ovi podaci ukljuuju stanje string
objekta. Obratite panju da je string objekat vie nego njegova vrednost.
Treba napomenuti da re string nije C++ kljuna re, to je ime klase.
U C++, bilo koja klasa, ukljuujui i string, je validan tip podatka.
Sledi, mogu se deklarisati string objekti skoro na isti nain kao to se
deklariu numeriki tipovi podataka. Posmatrajmo sledee deklaracije:
string str1;
string str2 = "Hello";
string str3("Hello");
string str4(50, '*');
#include <iostream>
#include <string>
using namespace std;
int main()
{
- 122 -
string str1;
string str2 = "Hello";
string str3("Hello");
string str4(50, '*');
String Input
Moete ubaciti vrednosti string objekata koristei cin >> operator, kao
u primeru:
string first_name;
cout << "Enter your first name: ";
cin >> first_name;
#include <iostream>
#include <string>
- 123 -
int main()
{
string first_name;
string last_name;
return 0;
}
- 124 -
podatak cin koristi white space (blank, ili enter, ili tab) da odvoji stringove.
Sledi cin moe da se iskoristi za ulaz samo jedne rei u jednom trenutku.
Za unos stringa sastavljenog od vie rei, mora da koristimo funkciju
getline(). Na primer:
string state;
getline(cin, state);
Funkcija getline() pita cin da uzme jednu liniju iz ulaznog strima tj.
sve to korisnik ukuca dok ne pritisne taster enter. Tekst koji je ukucan (bez
enter karaktera) se predaje string objektu state, koji uzima tekst kao njegovu
vrednost. Funkcija getline() nije metod string klase.
//Ovaj program ilustruje koriscenje funkcije getline() za unos stringa sastavljenog
//iz vise reci
#include <iostream>
#include <string>
int main()
{
string full_name;
string state_name;
return 0;
}
- 125 -
//Program izracunava srednju vrednost rezultata sa tri testa
#include <iostream>
#include <iomanip>
#include <string>
int main()
{
int quiz1, // Ocena sa prvog testa
quiz2, // Ocena sa drugog testa
quiz3; // Ocena sa treceg testa
- 126 -
average = double (quiz1 + quiz2 + quiz3) / 3;
Dodela stringova
str2 = str1;
- 127 -
string str1 = "Hello";
string str2(str1);
Moete spojiti dva stringa koristei operator +, isti operator koji smo
koristili za sabiranje brojeva. Na primer, sledea deklaracija smeta string
"Hello, World" na kraj vrednosti string objekta str3:
str3 += "World!";
Duina stringa
str1.length()
- 128 -
odnosno,
class_object.method_name()
#include <iostream>
#include <string>
using namespace std;
int main()
{
string first_name;
string last_name;
string full_name;
int name_length;
return 0;
}
- 129 -
Pristup odreenim karakterima u stringu
0 1 2 3 4
H e l l o
Prvi karakter ima indeks 0, dok poslednji karakter ima indeks koji je
jednak duini stringa -1.
Dobiti ili promeniti individualni karakter u string objektu moemo
koristei metod at() string klase. Ako je str1 string objekat, onda izvravanjem
str1.at(i) pitamo string objekat str1 da vrati karakter sa indeksom i u stringovoj
vrednosti.
Posmatrajmo sledei kd:
str.at(0) = 'X';
#include <iostream>
#include <string>
- 130 -
int main()
{
string str = "Hippopatamus";
cout << "The first character in the string is " << str.at(0) << endl;
cout << "The last character in the string is " << str.at(last_index)
<< endl;
str.at(0) = 'X';
cout << "The new string is " << str << endl;
return 0;
}
Jednakost
Onda test
if (str1 == str2)
daje true.
- 131 -
Nejednakost
#include <iostream>
#include <string>
int main()
{
string first_name;
string last_name;
string full_name;
string full_name_chk;
cout << "Now please enter your first and last names" << endl;
- 132 -
cout << "separated by one space: ";
getline(cin, full_name_chk);
if (full_name == full_name_chk)
{
cout << endl << endl;
cout << "Congratulations! You followed the instructions." << endl;
}
else
{
cout << endl;
cout << "You did not follow the instructions!" << endl;
cout << "Please try the program again." << endl;
}
return 0;
}
string str1;
- 133 -
gde string objekat nije inicijalizovan, prazan je, odnosno ima vrednost
0. Sledi, str1.empty() daje true. Ako imamo sledeu deklaraciju:
#include <iostream>
#include <string>
string Get_Name(string);
int main()
{
string first_name;
string last_name;
string full_name;
string full_name_chk;
string first_initial;
string last_initial;
first_name = Get_Name("Please enter your first name: ");
- 134 -
<< " characters in it." << endl << endl;
cout << "Your initials are " << first_initial + last_initial
<< endl << endl;
cout << "Now please enter your first and last names" << endl;
cout << "separated by one space: ";
getline(cin, full_name_chk);
if (full_name == full_name_chk)
{
cout << endl << endl;
cout << "Congratulations! You followed the instructions." << endl;
}
else
{
cout << endl;
cout << "You did not follow the instructions!" << endl;
cout << "Please try the program again." << endl;
}
return 0;
}
bool invalid_data;
do
{
cout << endl << prompt;
getline(cin, name);
cout << endl;
if (name.empty())
{
cerr << "You did not enter a name - Please try again." << endl;
invalid_data = true;
}
else
invalid_data = false;
}
while(invalid_data);
return name;
}
- 135 -
Prototip funkcije Get_Name() je:
string Get_Name(string);
- 136 -
#include <iostream>
#include <string>
int main()
{
string str1;
string str2;
Swap_Strings(str1, str2);
return 0;
}
void Swap_Strings(string& s1, string& s2)
{
string temp;
temp = s1;
s1 = s2;
s2 = temp;
}
- 137 -
Funkciji se moe proslediti i pokaziva na string objekat.
T h i s i s a n e x a m p l e s t r i n g
position = str1.find("an");
- 138 -
Druga verzija metoda find() dozvoljava da se startuje pretraivanje
lokacije podstringa nakon date pozicije. Na primer, pronai lokaciju prve
blanko pozicije u str1 na ili nakon 11 pozicije.
Naredba
str2.find_first_of(punctuation);
str2.find_first_of(punctuation, 7);
- 139 -
Izvlaenje podstringa iz stringa
str1.replace(0, 4, "Here");
- 140 -
String metod erase() brie podstring iz stringa. Na primer, brisanje rei
"is" iz str1
str1.erase(5, 3);
str1. erase(10);
#include <iostream>
#include <string>
int main()
{
string str1 = "This is an example string";
string str2 = "sample";
string str3;
string punctuation = ".,:;!?";
int position;
- 141 -
// Nadji prvo pojavljivanje dela stringa "is" u str1 nakon pozicije 3
position = str1.find("is", 3);
cout << "The first occurrence of \"is\" from the end of str1 is "
<< "at position " << position << endl << endl;
if (position == -1)
cerr << "The substring \"Hello\" was not found in str1."
<< endl << endl;
cout << "After replacing the word \"example\" " << endl
<< "by the word \"sample\", in str1 the string is: "
<< str1 << endl << endl;
cout << "After erasing the word \"sample \", in str1 the string is: "
<< str1 << endl << endl;
cout << "After putting back the word \"example \", in str1 the string is: "
<< endl << str1 << endl << endl;
- 142 -
cout << "After appending a period, the string str1 is: "
<< str1 << endl << endl;
#include <iostream>
#include <string>
int main()
{
string the_string;
- 143 -
string word;
int space_location;
cout << "Enter a string. Separate words by spaces: " << endl << endl;
getline(cin, the_string);
//Ukloni rec
the_string.erase(0, word.length());
}
//Nadji sledecu blanko poziciju
space_location = the_string.find(" ", 0);
- 144 -
Problem palindroma
// Ovaj program koristi bibliotecke funkcije koje rade sa string objektima
// i karakterima i odredjuje da li je uneti string palindrom
#include <iostream>
#include <cctype>
#include <string>
int main()
{
string line;
string buffer;
Copy_Alpha(buffer, line);
Convert_To_Lower(buffer);
- 145 -
if ( Palindrome(buffer) )
cout <<"\nThe string you entered is a palindrome.";
else
cout <<"\nThe string you entered is not a palindrome.";
return;
} // Kraj funkcije Copy_Alpha()
return;
} // Kraj funkcije Convert_To_Lower()
- 146 -
7.6 Nizovi stringova
- 147 -
8. Programerski definisane klase i objekti
8.1 Deklarisanje objekata i klasa
class Savings_Account
{
private:
string id_no;
double balance;
double rate;
public:
Savings_Account(string, double, double);
double Calc_Interest();
};
double Savings_Account::Calc_Interest()
{
return balance * rate;
}
- 148 -
Postoje dve nove rezervisane rei u definiciji klase. Specifikatori
pristupa private i public odreuju vidljivost lanova klase. lanovima klase
koji su deklarisani posle oznake private mogu da pristupe samo metodi te
klase. Ako su id_no, balance, i rate, privatne instance varijabli, njima
pristupaju samo metodi Savings_Account() i Calc_Interest(). Ni jedna druga
funkcija nema pristup id_no, balance, ili rate. Ako deklariemo jedan Account
objekat u funkciji main(), ne moemo direktno da referenciramo te objektove
privatne instance varijabli zato to main() nije metod klase Savings_Account.
Zbog toga je sledea naredba u funkciji main() neispravna.
class Account
{
string id_no; //Ovo su privatni clanovi po defaultu
double balance;
double rate;
public:
Savings_Account(string, double, double);
double Calc_Interest();
};
- 149 -
Uobiajeno je da se dre svi public lanovi zajedno i svi private
lanovi zajedno. Ali, to nije neophodno.
Svi metodi klase mora da budu deklarisani unutar definicije klase,
ukljuujui one metode koji su definisani izvan deklaracije klase.
Metodi klase
return-type ClassName::MethodName(parameter-list)
void main()
{
- 150 -
int id;
double bal;
double rt;
Naredba
Metodi
- 151 -
primenjuju na klase koje smo deklarisali u naim programima. Jednom kada
deklariemo Savings_Account objekat, moemo da koristimo dot operator sa
metodima klasa za rad sa objektima.
U naredbi
cout << "The interest on the account is " << acc1.Calc_Interest() << endl;
#include <iostream>
#include <iomanip>
#include <string>
using namespace std;
class Savings_Account
{
private:
string id_no;
double balance;
double rate;
public:
Savings_Account(string, double, double);
double Calc_Interest();
};
double Savings_Account::Calc_Interest()
{
return balance * rate;
}
- 152 -
int main()
{
cout << setprecision(2)
<< setiosflags(ios::fixed)
<< setiosflags(ios::showpoint);
return 0;
}
//Pretprocesorske direktive
//Deklaracije klasa
- 153 -
//Definicije metoda
//Definicija funkcije main()
- 154 -
class Savings_Account
{
private:
string id_no;
double balance;
double rate;
public:
Savings_Account(string, double, double);
double Calc_Interest();
double Get_Balance();
void Deposit(double);
bool Withdraw(double);
};
double Savings_Account::Calc_Interest()
{
double interest;
- 155 -
double Savings_Account::Get_Balance()
{
return balance;
}
cout << "The balance in the account is " << acc1.Get_Balance() << endl;
acc1.Deposit(55.42);
- 156 -
balance -= amount;
result = true;
}
else
result = false;
return result;
}
#include <iostream>
#include <iomanip>
#include <string>
class Savings_Account
{
private:
string id_no;
double balance;
double rate;
public:
Savings_Account(string, double, double);
double Calc_Interest();
double Get_Balance();
string Get_ID();
void Deposit(double);
bool Withdraw(double);
};
Savings_Account::Savings_Account(string id, double bal, double rt)
{
id_no = id;
balance = bal;
rate = rt;
}
double Savings_Account::Get_Balance()
{
return balance;
}
- 157 -
string Savings_Account::Get_ID()
{
return id_no;
}
double Savings_Account::Calc_Interest()
{
double interest;
return interest;
}
void Savings_Account::Deposit(double amount)
{
balance += amount;
}
int main()
{
cout << setprecision(2)
<< setiosflags(ios::fixed)
<< setiosflags(ios::showpoint);
string id;
double bal;
double rt;
double amount;
- 158 -
cout << endl;
cout << "Enter Balance: ";
cin >> bal;
cout << "The balance in the account is now " << acc1.Get_Balance()
<< endl << endl;
acc1.Deposit(amount);
acc1.Calc_Interest();
if (acc1.Withdraw(amount))
{
cout << endl << endl;
cout << "A withdrawal of " << amount << " was made.";
}
else
{
cout << endl << endl;
cout << "WITHDRAWAL NOT MADE: Insufficient funds.";
}
cout << endl;
- 159 -
cout << "The balance in the account is now " << acc1.Get_Balance() << endl;
return 0;
}
- 160 -
class Savings_Account
{
.
.
.
public:
Savings_Account(string, double, double);
Savings_Account(string, double);
Savings_Account(string);
.
.
.
};
Savings_Account::Savings_Account(string id)
{
id_no = id;
balance = 0.0;
rate = 0.02;
}
Savings_Account acc1("1111");
- 161 -
U jeziku C++ kompajler razlikuje tri konstruktora po broju i tipu
argumenata obezbeenih u deklaraciji objekta. Prva deklaracija koristi
konstruktor sa tri argumenta i kreira raun 3333 sa stanjem 100.00 i
kamatom 0.06. Druga deklaracija kreira raun 2222 sa otvorenim stanjem od
200.00 i unapred datom kamatom od 0.02. Trea deklaracija koristi
konstruktor sa jednim argumentom i kreira raun 1111 sa unapred
definisanim stanjem 0.00 i kamatom 0.02.
Sledei program prikazuje preklapanje konstruktora. Dodali smo cout
naredbu za svaki konstruktor da bismo verifikovali da se odgovarajui
konstruktori izvravaju. Treba obratiti panju da funkcija main() ima samo
jednu cout naredbu koja objavljuje kraj programa. Drugi izlazi potiu od
konstruktora.
#include <iostream>
#include <iomanip>
#include <string>
class Savings_Account
{
private:
string id_no;
double balance;
double rate;
public:
Savings_Account(string, double, double);
Savings_Account(string, double);
Savings_Account(string);
double Calc_Interest();
double Get_Balance();
string Get_ID();
void Deposit(double);
bool Withdraw(double);
};
Savings_Account::Savings_Account(string id, double bal, double rt)
{
id_no = id;
balance = bal;
rate = rt;
- 162 -
cout << "Three-arg constuctor for " << id_no << endl;
}
cout << "Two-arg constuctor for " << id_no << endl;
}
Savings_Account::Savings_Account(string id)
{
id_no = id;
balance = 0.0;
rate = 0.02;
cout << "One-arg constuctor for " << id_no << endl;
}
double Savings_Account::Get_Balance()
{
return balance;
}
string Savings_Account::Get_ID()
{
return id_no;
}
double Savings_Account::Calc_Interest()
{
double interest;
return interest;
}
void Savings_Account::Deposit(double amount)
{
balance += amount;
}
- 163 -
bool Savings_Account::Withdraw(double amount)
{
bool result;
if (amount <= balance)
{
balance -= amount;
result = true;
}
else
result = false;
return result;
}
int main()
{
Savings_Account acc3("3333", 100.00, 0.06);
Savings_Account acc2("2222", 200.00);
Savings_Account acc1("1111");
return 0;
}
8.4 Destruktori
- 164 -
karakterom "tilde" ~. Destruktor ne moe imati argumente, ne moe imati
povratni tip i mora biti public. Ne moe biti preklopljen.
#include <iostream>
#include <iomanip>
#include <string>
class Savings_Account
{
private:
string id_no;
double balance;
double rate;
public:
Savings_Account(string, double, double);
Savings_Account(string, double);
Savings_Account(string);
~Savings_Account();
double Calc_Interest();
double Get_Balance();
string Get_ID();
void Deposit(double);
bool Withdraw(double);
};
cout << "Three-arg constuctor for " << id_no << endl;
}
- 165 -
rate = 0.02;
cout << "Two-arg constuctor for " << id_no << endl;
}
Savings_Account::Savings_Account(string id)
{
id_no = id;
balance = 0.0;
rate = 0.02;
cout << "One-arg constuctor for " << id_no << endl;
}
Savings_Account::~Savings_Account()
{
cout << "Destructor executed for " << id_no << endl;
}
double Savings_Account::Get_Balance()
{
return balance;
}
string Savings_Account::Get_ID()
{
return id_no;
}
double Savings_Account::Calc_Interest()
{
double interest;
return interest;
}
- 166 -
bool result;
if (amount <= balance)
{
balance -= amount;
result = true;
}
else
result = false;
return result;
}
int main()
{
Savings_Account acc3("3333", 100.00, 0.06);
Savings_Account acc2("2222", 200.00);
Savings_Account acc1("1111");
return 0;
}
Default argumenti
- 167 -
naina. Ponekad moemo postii efekat preklapanja konstruktora koristei
jedan konstruktor sa default argumentima. Potrebno je da specificirate
default argumente u deklaraciji konstruktora, a ne u definiciji. Sledi, u
deklaraciji klase treba da napiete sledei kd:
public:
Savings_Account(string id, double bal = 0.00, double rt = 0.02);
//konstruktor sa default veliinama
//koji slui kao konstruktor sa jednim argumentom
//i kao konstruktor sa dva argumenta
Savings_Account acc1("1111");
#include <iostream>
#include <iomanip>
#include <string>
class Savings_Account
{
private:
string id_no;
double balance;
double rate;
public:
- 168 -
Savings_Account(string id, double bal = 0.00, double rt = 0.02);
~Savings_Account();
double Calc_Interest();
double Get_Balance();
string Get_ID();
void Deposit(double);
bool Withdraw(double);
};
cout << "Default-argument constuctor for " << id_no << endl;
cout << "Value of balance is " << balance << endl;
cout << "Value of rate is " << rate << endl << endl;
}
Savings_Account::~Savings_Account()
{
cout << "Destructor executed for " << id_no << endl;
}
double Savings_Account::Get_Balance()
{
return balance;
}
string Savings_Account::Get_ID()
{
return id_no;
}
double Savings_Account::Calc_Interest()
{
double interest;
- 169 -
balance += amount;
}
int main()
{
cout << setprecision(2)
<< setiosflags(ios::fixed)
<< setiosflags(ios::showpoint);
return 0;
}
- 170 -
Default argumenti u deklaraciji konstruktora nam dozvoljavaju da
deklariemo objekat Savings_Account na isti nain kao ranije, gde smo imali
tri preklopljena konstruktora. Dodali smo cout naredbe u konstruktoru da
bismo verifikovali vrednosti primeraka promenljivih.
acc2 = acc1;
class Savings_Account
{
private:
string id_no;
double balance;
double rate;
public:
Savings_Account(string id, double bal = 0.00, double rt = 0.02);
- 171 -
double Calc_Interest();
double Get_Balance();
double Get_Rate();
string Get_ID();
void Deposit(double);
bool Withdraw(double);
};
double Savings_Account::Get_Balance()
{
return balance;
}
string Savings_Account::Get_ID()
{
return id_no;
}
double Savings_Account::Get_Rate()
{
return rate;
}
double Savings_Account::Calc_Interest()
{
double interest;
interest = balance * rate;
balance += interest;
return interest;
}
- 172 -
bool result;
if (amount <= balance)
{
balance -= amount;
result = true;
}
else
result = false;
return result;
}
int main()
{
cout << setprecision(2)
<< setiosflags(ios::fixed)
<< setiosflags(ios::showpoint);
acc2 = acc1;
cout << "The new values for acc2 are: " << endl << endl;
cout << "ID = " << acc2.Get_ID() << endl;
cout << "Balance = " << acc2.Get_Balance() << endl;
cout << "Rate = " << acc2.Get_Rate() << endl;
return 0;
}
- 173 -
8.5 Opte preklapanje funkcija i abloni funkcija
temp = i;
i = j;
j = temp;
}
- 174 -
Definicija poinje rezervisanom rei template za kojom sledi
rezervisana re class i jedan identifikator Type. Re template kae kompajleru
da napravi definiciju ablona. Identifikator Type se koristi kao ime
proizvoljne klase ili tipa podatka. Type se ponaa kao varijabla ija vrednost
moe biti bilo koja klasa ili tip podatka.
Nakon deklaracije ablona sledi definicija funkcije. Jedino pravilo
koga treba da se drite kada piete funkciju je da koristite identifikator Type
kad god elite da referencirate na tip podatka parametra ili kada deklariete
varijablu. U primeru koji sledi u hederu funkcije imamo Swap(Type& x, Type&
y) deklarisanje parametara bilo kog tipa. Takoe, u telu funkcije
deklariemo promenljivu temp kao to sledi
Type temp;
#include <iostream>
using namespace std;
- 175 -
Type t = 0;
int main()
{
int i = 3,
j = 5;
double d = 8.62,
e = 4.14;
cout << "i = " << i << " and j = " << j << endl;
cout << "d = " << d << " and e = " << e << endl << endl;
cout << "The larger of i and j is " << Max(i, j) << endl;
cout << "The larger of d and e is " << Max(d, e) << endl << endl;
Swap(i, j);
Swap(d, e);
cout << "i = " << i << " and j = " << j << endl;
cout << "d = " << d << " and e = " << e << endl << endl;
cout << "Func() applied to i and d is " << Func(i, d) << endl;
cout << "Func() applied to d and i is " << Func(d, i) << endl << endl;
cout << "The sum of f_arr[] is " << Sum(f_arr, 6) << endl;
cout << "The sum of i_arr[] is " << Sum(i_arr, 4) << endl;
return 0;
}
- 176 -
abloni funkcija su definisani pre funkcije main(), to zahteva veina
kompajlera. Ako pokuate da iskoristite ablon funkcije za primer u kome
kompajler ne moe da podesi tipove, program se nee kompajlirati.
- 177 -
9. Rad sa objektima
9.1 Korienje nizova, pokazivaa i dinamika alokacija memorije
char id_no[5];
char* name;
class Savings_Account
{
private:
char id_no[5];
char* name;
double balance;
double rate;
- 178 -
public:
Savings_Account(char id[], char* n_p, double bal = 0.00, double rt = 0.04);
~Savings_Account();
double Calc_Interest();
double Get_Balance();
void Deposit(double);
int Withdraw(double);
void Display_ID();
void Display_Name();
};
balance = bal;
rate = rt;
}
- 179 -
String funkcija strlen(), vraa broj karaktera u drugom argumentu, plus 1 za
null karakter. Nakon izvrenja dodele, name pokazuje na niz karaktera koji je
tano toliko velik da dri string koji je drugi argument konstruktora. Druga
naredba kopira drugi argument, na koji pokazuje n_p, u prostor na koji
pokazuje name.
Savings_Account::~Savings_Account()
{
cout << "\nAccount " << id_no << " terminated.";
delete [] name;
}
- 180 -
#include <iostream>
#include <iomanip>
#include <string>
using namespace std;
class Savings_Account
{
private:
char id_no[5];
char* name;
double balance;
double rate;
public:
Savings_Account(char id[], char* n_p, double bal = 0.00, double rt = 0.04);
~Savings_Account();
double Calc_Interest();
double Get_Balance();
void Deposit(double);
bool Withdraw(double);
void Display_ID();
void Display_Name();
};
balance = bal;
rate = rt;
}
Savings_Account::~Savings_Account()
{
cout << endl << endl;
cout << "Account " << id_no << " terminated." << endl;
delete [] name;
}
double Savings_Account::Get_Balance()
{
return balance;
}
double Savings_Account::Calc_Interest()
{
- 181 -
double interest;
return interest;
}
return result;
}
void Savings_Account::Display_ID()
{
cout << id_no;
}
void Savings_Account::Display_Name()
{
cout << name;
}
int main()
{
cout << setprecision(2)
<< setiosflags(ios::fixed)
<< setiosflags(ios::showpoint);
char id[5];
char buffer[81]; //Privremeno skladisti ime
- 182 -
double bal;
double rt;
double amount;
acc1.Deposit(amount);
cout << endl << endl;
cout << "A deposit of " << amount << " was made." << endl;
cout << "The balance in the Account is now "
<< acc1.Get_Balance() << endl;
acc1.Calc_Interest();
- 183 -
<< acc1.Get_Balance() << endl << endl;
if (acc1.Withdraw(amount))
{
cout << endl <<endl;
cout << "A withdrawal of " << amount << " was made.";
}
else
{
cout << endl << endl;
cout << "WITHDRAWAL NOT MADE: Insufficient funds.";
}
cout << endl;
cout << "The balance in the Account is now " << acc1.Get_Balance() << endl;
return 0;
}
- 184 -
9.2 Konstruktor kopije
int i = 7,
j;
j = i;
Posmatrajmo primer:
//Ovaj program ilustruje dodelu jednog objekta drugom objektu.
//Treba obratiti paznju da inicijalizacija jednog objekta ne koristi
//konstruktor sa jednim argumentom
#include <iostream>
- 185 -
class Test_Class
{
private:
int n;
public:
Test_Class(int);
~Test_Class();
int Get_Value();
};
Test_Class::Test_Class(int i)
{
n = i;
Test_Class::~Test_Class()
{
cout << endl;
cout << "Destructor Executed for object with data member " << n << endl;
}
int Test_Class::Get_Value()
{
return n;
}
int main()
{
Test_Class tc_object1(4);
Test_Class tc_object2(0);
tc_object2 = tc_object1;
- 186 -
cout << "After initializing object 3:" << endl << endl;
cout << "Object 3: " << tc_object3.Get_Value() << endl;
return 0;
}
- 187 -
Zato to se operacija inicijalizacije razlikuje od dodele, specijalan
konstruktor se koristi u C++ za inicijalizaciju konstruktora kopije (copy
constructor). Kao i kod obinog konstruktora, ako eksplicitno ne napiete
kd za konstruktor kopije, klasi se daje default konstruktor kopije. Default
konstruktor kopije kopira podatke lanove iz tc_object1 i inicijalizuje ih, na
bazi lan po lan, u odgovarajue podatke lanove objekta tc_object3.
Kod konstruktora kopije koji ste vi kreirali za Test_Class je:
class Test_Class
{
.
.
.
public:
Test_Class(Test_Class&); // Deklaracija konstruktora kopije
.
.
.
};
Test_Class::Test_Class(Test_Class& tc_r)
{
n = tc_r.n; //Kopira podatak n clan objekta sa desne strane operatora dodele
// u inicijalizaciji u podatak n clana objekta koji se kreira
- 188 -
cout << "Copy Constructor executed: "
<< "Data member initialized to " << n << endl;
}
#include <iostream>
class Test_Class
{
private:
int n;
public:
Test_Class(int); //Konstruktor sa jednim argumentom
Test_Class(Test_Class&); //Konstruktor kopije
~Test_Class();
int Get_Value();
};
Test_Class::Test_Class(int i)
{
n = i;
- 189 -
cout << endl;
cout << "Constructor Executed: Data member initialized to " << n << endl;
}
Test_Class::Test_Class(Test_Class& tc_r)
{
n = tc_r.n;
Test_Class::~Test_Class()
{
cout << endl << endl;
cout << "Destructor Executed for object with data member " << n << endl;
}
int Test_Class::Get_Value()
{
return n;
}
int main()
{
Test_Class tc_object1(4);
Test_Class tc_object2(0);
tc_object2 = tc_object1;
cout << "After object assignment:" << endl << endl;
cout << "Object 1: " << tc_object1.Get_Value() << endl;
cout << "Object 2: " << tc_object2.Get_Value() << endl << endl;
cout << "After initializing object 3:" << endl << endl;
cout << "Object 3: " << tc_object3.Get_Value() << endl;
return 0;
}
- 190 -
Obratite panju da se konstruktor kopije izvrava kada se program
kreira i inicijalizuje objekat tc_object3.
- 191 -
Zato to je default konstruktor kopije korien pri inicijalizaciji, acc2
je "lan-po-lan" kopija od acc1. Zbog toga, pointer acc1.name koji pokazuje
na string "Maxwell Larrabee" biva kopiran u pointer acc2.name. Obratite
panju da se pokaziva, koji je adresa, kopira, a ne kopira se string na koji
pokaziva pokazuje. Na taj nain, imamo name pokaziva dva razliita
objekta koji pokazuje na istu zonu hip memorije.
Sa slike sledi da promena cilja jednog od ovih pokazivaa kao
rezultat daje promenu oba. Na taj nain ako promenimo string na koji
pokazuje name lan objekta acc2, takoe menjamo string na koji pokazuje
name lan objekta acc1. Ovo je upravo ono to nismo eleli da se desi!
Savings_Account::Savings_Account(Savings_Account& acc_r)
{
strcpy(id_no, acc_r.id_no); // kopira prvi argument u id_no[]
balance = acc_r.balance;
rate = acc_r.rate;
}
- 192 -
Obratite panju na slinost izmeu koda konstruktora sa etiri
argumenta i konstruktora kopije. Prvo, id_no lan objekta koji se kopira,
kopira se u id_no lana objekta koji se kreira. Zatim se prostor alocira iz hip
memorije za string dovoljno velik da dri kopiju od name lana objekta koji
se kopira. Nakon kopiranja name u novi hip prostor, stanje i kamatna stopa
lanovi objekta koji se kopira se kopiraju u odgovarajue lanove objekta
koji se kreira. Na taj nain, ako napravimo prethodni konstruktor kopije
lana od Savings_Account, sledee deklaracije kao rezultat daju situaciju
oznaenu na slici:
#include <iostream>
#include <iomanip>
#include <string>
class Savings_Account
{
private:
char id_no[5];
- 193 -
char* name;
double balance;
double rate;
public:
Savings_Account(char id[], char* n_p, double bal = 0.00, double rt = 0.04);
Savings_Account(Savings_Account&);
~Savings_Account();
double Calc_Interest();
double Get_Balance();
void Deposit(double);
bool Withdraw(double);
void Display_ID();
void Display_Name();
};
balance = bal;
rate = rt;
Savings_Account::Savings_Account(Savings_Account& acc_r)
{
strcpy(id_no, acc_r.id_no); // kopira prvi argument u id_no[]
balance = acc_r.balance;
rate = acc_r.rate;
- 194 -
Savings_Account::~Savings_Account()
{
cout << endl << endl;
cout << "Account " << id_no << " terminated." << endl;
delete [] name;
}
double Savings_Account::Get_Balance()
{
return balance;
}
double Savings_Account::Calc_Interest()
{
double interest;
return interest;
}
return result;
}
void Savings_Account::Display_ID()
{
cout << id_no;
}
- 195 -
void Savings_Account::Display_Name()
{
cout << name;
}
int main()
{
cout << setprecision(2)
<< setiosflags(ios::fixed)
<< setiosflags(ios::showpoint);
char id[5];
char buffer[81]; //Privremeno skladisti ime
double bal;
double rt;
cout << "Enter Account ID: ";
cin.getline(id, 5);
- 196 -
cout << endl;
cout << "\n and owner name ";
acc2.Display_Name();
return 0;
}
- 197 -
#include <iostream.h>
using namespace std;
class Test_Class
{
private:
int n;
public:
Test_Class(int i = 0); //Konstruktor sa jednim argumentom i default vrednoscu
int Get_Value();
void Change_Value(int);
};
Test_Class::Test_Class(int i)
{
n = i;
int Test_Class::Get_Value()
{
return n;
}
void Test_Class::Change_Value(int i)
{
n = i;
}
Suppose we declare the following in main().
Test_Class tc_object2(7);
- 198 -
razliku izmeu aksesor metoda (koji ne menja vrednost instance varijable) i
mutator metoda (koji menja vrednost instance promenljive). Kompajler e
izbaciti poruku: ili warning ili error, ako primenimo bilo koji od metoda klase
Test_Class na objekat tc_object1.
Konstantni metodi
Bilo koji metod klase koji je accessor (znai, ne menja vrednost bilo
koje instance promenljive) treba da bude deklarisan kao konstantan. Ovo je
dato dodavanjem rezervisane rei const nakon zagrada koje slede nakon
imena metoda i u deklaraciji i u definiciji. Ovo dozvoljava da takav metod
bude primenjen na konstantan objekat.
Sledi korektna verzija deklaracije Test_Class.
#include <iostream.h>
class Test_Class
{
private:
int n;
public:
Test_Class(int i = 0); // Konstruktor sa jedim argumentom koji ima default
// vrednost
int Get_Value() const; //Accessor funkcija deklarisana kao konstanta - const
void Change_Value(int);
};
- 199 -
Test_Class::Test_Class(int i)
{
n = i;
cout << "\n\nConstructor Executed: Data member initialized to " << n;
}
void Test_Class::Change_Value(int i)
{
n = i;
}
#include <iostream>
class Test_Class
{
private:
int n;
public:
Test_Class(int i = 0); // Konstruktor sa jedim argumentom koji ima default
// vrednost
int Get_Value() const;
void Change_Value(int);
};
Test_Class::Test_Class(int i)
{
n = i;
- 200 -
cout << "Constructor Executed: Data member initialized to "
<< n << endl << endl;
}
int Test_Class::Get_Value() const
{
return n;
}
void Test_Class::Change_Value(int i)
{
n = i;
}
int main()
{
const Test_Class tc_object1(4);
cout << "The value of the object is " << tc_object1.Get_Value() << endl;
return 0;
}
int i = 4,
j = 7;
int* const i_p = &i; //pointer i_p je konstantan, zato, njegova vrednost &i, ne moze
//da se menja. Ona mora uvek da pokazuje na i.
- 201 -
i_p
i_p.
deklaracije:
int n = 3,
m = 5;
n_p
konstantu; tj. n_p
n_p n_p kao o "read-
- 202 -
Meutim, moemo jo uvek promeniti vrednost m kao to sledi:
m = 6;
int i = 9;
int* i_p = &i;
const int* j_p = i_p; //ispravno
int n = 8;
- 203 -
Konstantni argumenti u funkciji
#include <iostream>
#include <iomanip>
cout << "Please enter " << NUM_QUIZZES << " integer quiz grades."
<< endl << endl;
- 204 -
cout << endl;
cout << "The average quiz grade is " << grade_avg << endl;
return 0;
return avg;
} // Kraj funkcije Avg()
- 205 -
konstruktor kopije treba samo da kopira i nita drugo. Slede deklaracija i
definicija za konstruktor kopije za tedni raun Savings_Account sa
bezbednijim kodom:
Deklaracija:
Savings_Account(const Savings_Account&);
Definicioni heder:
Savings_Account::Savings_Account (const Savings_Account& acc_r)
char* Savings_Account::Get_Name()
{
return name;
}
#include <iostream>
#include <iomanip>
#include <string>
using namespace std;
class Savings_Account
{
private:
char id_no[5];
- 206 -
char* name;
double balance;
double rate;
public:
Savings_Account(char id[], char* n_p, double bal = 0.00, double rt = 0.04);
Savings_Account(const Savings_Account &);
~Savings_Account();
double Calc_Interest();
double Get_Balance();
char* Get_Name();
void Deposit(double);
bool Withdraw(double);
};
balance = bal;
rate = rt;
balance = acc_r.balance;
rate = acc_r.rate;
Savings_Account::~Savings_Account()
{
- 207 -
cout << endl << endl;
cout << "Account " << id_no << " terminated." << endl;
delete [] name;
}
double Savings_Account::Get_Balance()
{
return balance;
}
char* Savings_Account::Get_Name()
{
return name;
}
double Savings_Account::Calc_Interest()
{
double interest;
return interest;
}
return result;
}
int main()
{
- 208 -
cout << setprecision(2)
<< setiosflags(ios::fixed)
<< setiosflags(ios::showpoint);
char id[5];
char buffer[81]; //Privremeno skladisti ime
double bal;
double rt;
cout << "Account Owner: " << acc1.Get_Name() << endl << endl;
return 0;
}
- 209 -
Da bismo napisali siguran kod za aksesor metod koji vraa
pokaziva, treba da napravimo da metod vraa konstantan pokaziva. Ovo
obezbeuje da objekat na koji se pokazuje ne moe biti promenjen kroz
pokaziva od strane pozivajue funkcije.
Na primer, u klasi Savings_Account, bezbedan metod koji vraa
vrednost ID broja je:
- 210 -
//Ovaj program ilustruje koriscenje konstruktora kopije
//u klasi koja ima pokazivac kao podatak clan.
//Klasa sadrzi accessor funkcije koje vracaju konstantan pokazivac.
#include <iostream>
#include <iomanip>
#include <string>
class Savings_Account
{
private:
char id_no[5];
char* name;
double balance;
double rate;
public:
Savings_Account(char id[], char* n_p, double bal = 0.00, double rt = 0.04);
Savings_Account(const Savings_Account&);
~Savings_Account();
double Calc_Interest();
double Get_Balance();
const char* Get_Id();
const char* Get_Name();
void Deposit(double);
bool Withdraw(double);
};
balance = bal;
rate = rt;
- 211 -
strcpy(id_no, acc_r.id_no); // kopira prvi argument u id_no[]
balance = acc_r.balance;
rate = acc_r.rate;
Savings_Account::~Savings_Account()
{
cout << endl << endl;
cout << "Account " << id_no << " terminated." << endl;
delete [] name;
}
double Savings_Account::Get_Balance()
{
return balance;
}
double Savings_Account::Calc_Interest()
{
double interest;
return interest;
}
void Savings_Account::Deposit(double amount)
{
- 212 -
balance += amount;
}
return result;
}
int main()
{
cout << setprecision(2)
<< setiosflags(ios::fixed)
<< setiosflags(ios::showpoint);
char id[5];
char buffer[81]; //Privremeno skladisti ime
double bal;
double rt;
- 213 -
Savings_Account acc1(id, buffer, bal, rt);
return 0;
}
- 214 -
9.4 Objekti, funkcije i pokazivai
Savings_Account Get_Account()
{
char id[5];
char buffer[81];
double bal;
double rt;
return acc;
}
- 215 -
Ova funkcija sadri vei deo koda koji se pojavljuje u glavnoj
funkciji main() u programima koji koriste Savings_Account.
Get_Account() kreira lokalni Savings_Account objekat, acc, koristei
korisnikove ulazne podatke. Zato, name lan objekta acc pokazuje na prostor
koji je alociran na hipu od strane Savings_Account konstruktora. Naredba return
alje privremenu kopiju objekta acc pozivajuoj funkciji. Kada se funkcija
zavri, lokalni objekat acc izlazi iz dosega i, zbog toga, se unitava. Ovo
prouzrokuje da se Savings_Account destruktor izvrava, i on dealocira prostor
na koji je name lan objekta acc pokazivao. Sada, ako je naredba return poslala
lan-po-lan kopiju objekta acc nazad pozivajuoj funkciji, name lan te
kopije pokazivae na nealocirani prostor. Ovaj pogrean pokaziva moe da
prouzrokuje da se program srui. Da bismo obezbedili da se ovo ne desi,
C++ koristi Savings_Account konstruktor kopije da bi napravio privremenu
kopiju objekta acc. Zbog toga, name lan privremene kopije pokazuje na
razliito mesto na hipu od onoga koje je bilo za name lan objekta acc.
#include <iostream>
#include <iomanip>
- 216 -
#include <string>
class Savings_Account
{
private:
char id_no[5];
char* name;
double balance;
double rate;
public:
Savings_Account(char id[], char* n_p, double bal = 0.00, double rt = 0.04);
Savings_Account(const Savings_Account&);
~Savings_Account();
double Calc_Interest();
double Get_Balance();
void Deposit(double);
bool Withdraw(double);
};
balance = bal;
rate = rt;
balance = acc_r.balance;
- 217 -
rate = acc_r.rate;
double Savings_Account::Get_Balance()
{
return balance;
}
double Savings_Account::Calc_Interest()
{
double interest;
return interest;
}
return result;
}
- 218 -
Savings_Account Get_Account(); //Prototip za Get_Account()
int main()
{
cout << setprecision(2)
<< setiosflags(ios::fixed)
<< setiosflags(ios::showpoint);
return 0;
}
Savings_Account Get_Account()
{
char id[5];
char buffer[81];
double bal;
double rt;
- 219 -
return acc;
}
- 220 -
Prosleivanje objekta po vrednosti
Display_Account(Savings_Account acc)
#include <iostream>
#include <iomanip>
#include <string>
class Savings_Account
{
private:
char id_no[5];
char* name;
double balance;
double rate;
public:
Savings_Account(char id[], char* n_p, double bal = 0.00, double rt = 0.04);
~Savings_Account();
Savings_Account(const Savings_Account&);
const char* Get_Id()
const; const char* Get_Name() const;
- 221 -
double Calc_Interest();
double Get_Balance();
void Deposit(double);
bool Withdraw(double);
};
balance = bal;
rate = rt;
}
balance = acc_r.balance;
rate = acc_r.rate;
cout << endl << endl;
cout << "Copy constructor executed." << endl;
}
Savings_Account::~Savings_Account()
{
cout << endl << endl;
cout << "Account " << id_no << " terminated." << endl;
delete [] name;
}
- 222 -
return name;
}
double Savings_Account::Get_Balance()
{
return balance;
}
double Savings_Account::Calc_Interest()
{
double interest;
return interest;
}
return result;
}
int main()
{
cout << setprecision(2)
<< setiosflags(ios::fixed)
<< setiosflags(ios::showpoint);
- 223 -
char id[5];
char buffer[81]; //privremeno skladisti ime
double bal;
double rt;
double amount;
Display_Account(acc1);
acc1.Deposit(amount);
Display_Account(acc1);
acc1.Calc_Interest();
Display_Account(acc1);
- 224 -
cout << endl << endl;
cout << "Enter an amount to withdraw: ";
cin >> amount;
if (acc1.Withdraw(amount))
{
cout << endl << endl;
cout << "A withdrawal of " << amount << " was made.";
}
else
{
Display_Account(acc1);
- 225 -
- 226 -
Treba obratiti panju da odmah pre nego to Display_Account() prikae
liniju, program prikazuje poruku iz konstruktora kopije. Konstruktor kopije
se izvrava kada se parametar u Display_Account() inicijalizuje na vrednost
rauna koji se prosleuje funkciji. Kada se funkcija zavrava, parametri
funkcije, koji su Savings_Account objekti, izlaze iz dosega. Sledi, parametri se
unitavaju i destruktori klase izvravaju, to prouzrokuje prikaz poruke
destruktora.
ta se dogaa ako programer ne obezbedi konstruktor kopije i
umesto toga se osloni na difolt konstruktor kopije? Kada se funkcija
Display_Account() poziva po prvi put, difolt konstruktor e napraviti kopiju
(lan po lan) argumenta i smestiti je u parametar funkcije. Zbog toga e
name lan parametra pokazivati na isti hip prostor argumenta. Problem
nastaje kada se funkcija zavrava zbog toga to se destruktor klase izvrava.
Ovo prouzrokuje da se prostor na koji pokazuje parametrov name lan
dealocira. Ali ovo je isti prostor na koji pokazuje argumentov name lan.
Rezultat je da argumentov name lan pokazuje na nezatieni hip prostor - tj.
prostor koji moe biti ponovo korien od strane sistema.
- 227 -
Kada se konstruktor kopije ne koristi:
-Kada se objekat dodeljuje drugom objektu iste klase.
Pokazivai na objekte
class Test_Class
{
private:
int n;
public:
Test_Class(int i = 0); //konstruktor sa jednim argumentom sa
//default-nom vrednosu
int Get_Value() const;
void Change_Value(int);
};
Test_Class tc_object(5);
- 228 -
Sledei kod prikazuje vrednost cilja tc_p pokazivaa, menja vrednost
cilja na 7, i prikazuje novu vrednost
cout << "The value of the object is " << tc_p -> Get_Value();
cout << "\nThe new value of the object is " << tc_p -> Get_Value();
#include <iostream>
class Test_Class
{
private:
int n;
public:
Test_Class(int i = 0); //Konstruktor sa jednim argumentom i
//default-nom vrednoscu
int Get_Value() const;
void Change_Value(int);
};
Test_Class::Test_Class(int i)
{
n = i;
- 229 -
void Test_Class::Change_Value(int i)
{
n = i;
}
int main()
{
Test_Class tc_object(5);
Test_Class* tc_p = &tc_object;
cout << "The value of the object is " << tc_p -> Get_Value();
cout << "The new value of the object is " << tc_p -> Get_Value();
#include <iostream>
- 230 -
#include <iomanip>
#include <string>
class Savings_Account
{
private:
char id_no[5];
char* name;
double balance;
double rate;
public:
Savings_Account(char id[], char* n_p, double bal = 0.00, double rt = 0.04);
~Savings_Account();
const char* Get_Id() const;
const char* Get_Name() const;
double Calc_Interest();
double Get_Balance();
void Deposit(double);
bool Withdraw(double);
};
balance = bal;
rate = rt;
}
Savings_Account::~Savings_Account()
{
cout << endl << endl;
cout << "Account " << id_no << " terminated." << endl;
delete [] name;
}
- 231 -
return id_no;
}
double Savings_Account::Get_Balance()
{
return balance;
}
double Savings_Account::Calc_Interest()
{
double interest;
return interest;
}
return result;
}
int main()
{
- 232 -
cout << setprecision(2)
<< setiosflags(ios::fixed)
<< setiosflags(ios::showpoint);
char id[5];
char buffer[81]; //Privremeno skladisti ime
double bal;
double rt;
double amount;
Display_Account(&acc1);
acc1.Deposit(amount);
Display_Account(&acc1);
acc1.Calc_Interest();
- 233 -
cout << endl << endl;
cout << "Name: " << acc1.Get_Name();
if (acc1.Withdraw(amount))
{
Display_Account(&acc1);
cout << "Data for Account# " << acc_p -> Get_Id() << endl << endl;
cout << "Owner's Name: " << acc_p -> Get_Name() << endl << endl;
- 234 -
Reference na objekte
- 235 -
acc_r.Deposit(50.00);
#include <iostream>
#include <iomanip>
#include <string>
class Savings_Account
{
private:
char id_no[5];
char* name;
double balance;
double rate;
public:
Savings_Account(char id[], char* n_p, double bal = 0.00, double rt = 0.04);
~Savings_Account();
const char* Get_Id() const;
const char* Get_Name() const;
double Calc_Interest();
double Get_Balance();
void Deposit(double);
bool Withdraw(double);
};
- 236 -
name = new char[strlen(n_p) + 1]; //kreira prostor za ime
balance = bal;
rate = rt;
}
Savings_Account::~Savings_Account()
{
cout << endl << endl;
cout << "Account " << id_no << " terminated." << endl;
delete [] name;
}
double Savings_Account::Calc_Interest()
{
double interest;
return interest;
}
- 237 -
bool result;
return result;
}
int main()
{
cout << setprecision(2)
<< setiosflags(ios::fixed)
<< setiosflags(ios::showpoint);
char id[5];
char buffer[81]; //Privremeno skladisti ime
double bal;
double rt;
double amount;
cout << "Enter Account ID: ";
cin.getline(id, 5);
Display_Account(acc1);
- 238 -
cout << "Enter an amount to deposit: ";
cin >> amount;
acc1.Deposit(amount);
Display_Account(acc1);
acc1.Calc_Interest();
Display_Account(acc1);
if (acc1.Withdraw(amount))
{
cout << endl << endl;
cout << "A withdrawal of " << amount << " was made." << endl;
}
else
{
cout << endl << endl;
cout << "WITHDRAWAL NOT MADE: Insufficient funds." << endl;
}
cout << endl << endl;
Display_Account(acc1);
cout << "Owner's Name: " << acc.Get_Name() << endl << endl;
- 239 -
cout << "Account Balance: " << acc.Get_Balance();
}
- 240 -
9.5 Dinamika alokacija objekata
- 241 -
Sledi program koji ilustruje korienje niza pokazivaa na objekte.
//Ovaj program ilustruje koriscenje dinamicki alociranih objekata.
#include <iostream>
#include <iomanip>
#include <string>
#include <cctype>
class Savings_Account
{
private:
char id_no[5];
char* name;
double balance;
double rate;
public:
Savings_Account(char id[], char* n_p, double bal = 0.00, double rt = 0.04);
~Savings_Account();
const char* Get_Id() const;
const char* Get_Name() const;
double Calc_Interest();
double Get_Balance();
void Deposit(double);
bool Withdraw(double);
};
balance = bal;
rate = rt;
}
Savings_Account::~Savings_Account()
{
cout << endl << endl;
cout << "Account " << id_no << " terminated." << endl;
- 242 -
delete [] name;
}
double Savings_Account::Get_Balance()
{
return balance;
}
double Savings_Account::Calc_Interest()
{
double interest;
return interest;
}
return result;
}
- 243 -
void Display_Account(Savings_Account&); //prototipovi funkcija
Savings_Account* Create_Account();
int main()
{
cout << setprecision(2)
<< setiosflags(ios::fixed)
<< setiosflags(ios::showpoint);
Savings_Account* account_table[10];
int count = 0;
char response;
//Brisanje
- 244 -
cout << "Owner's Name: " << acc.Get_Name() << endl << endl;
Savings_Account* acc_ptr;
cout << endl;
cout << "Enter Account ID: ";
cin.getline(id, 5);
return acc_ptr;
}
- 245 -
Identifikator account_table[i] je pokaziva na Savings_Account objekat.
Funkcija Display_Account() zahteva ime Savings_Account objekta kao argument
zato to je njegov argument Savings_Account referenca.
- 246 -
9.6 Statiki podaci lanovi i funkcije
class Savings_Account
{
private:
char id_no[5];
char* name;
- 247 -
double balance;
static double rate; //rate se deklarise kao staticka promenljiva
public:
Savings_Account(char id[], char* n_p, double bal = 0.00);
~Savings_Account();
double Calc_Interest();
double Get_Balance();
void Deposit(double);
int Withdraw(double);
};
Statiki metodi
class Savings_Account
{
private:
- 248 -
char id_no[5];
char* name;
double balance;
static double rate;
static int number_accounts;
public:
Savings_Account(char id[], char* n_p, double bal = 0.00);
~ Savings_Account();
const char* Get_Id() const;
const char* Get_Name() const;
double Calc_Interest();
double Get_Balance();
void Deposit(double);
bool Withdraw(double);
balance = bal;
++number_accounts;
}
Savings_Account::~ Savings_Account()
{
cout << endl << endl;
cout << "Account " << id_no << " terminated." << endl;
delete [] name;
--number_accounts;
- 249 -
int Savings_Account::Total_Accounts()
{
return number_accounts;
}
class Savings_Account
{
private:
char id_no[5];
char* name;
double balance;
static double rate; //static clan
static int number_accounts; //static clan
public:
Savings_Account(char id[], char* n_p, double bal = 0.00);
~Savings_Account();
const char* Get_Id() const;
const char* Get_Name() const;
double Calc_Interest();
double Get_Balance();
void Deposit(double);
bool Withdraw(double);
static int Total_Accounts(); //deklaracija metoda kao static
};
- 250 -
//Static data member definitions
balance = bal;
++number_accounts;
}
Savings_Account::~Savings_Account()
{
cout << endl << endl;
cout << "Account " << id_no << " terminated." << endl;
delete [] name;
--number_accounts;
double Savings_Account::Get_Balance()
{
return balance;
}
double Savings_Account::Calc_Interest()
- 251 -
{
double interest;
interest = balance * rate;
balance += interest;
return interest;
}
return result;
}
int Savings_Account::Total_Accounts()
{
return number_accounts;
}
int main()
{
cout << setprecision(2)
<< setiosflags(ios::fixed)
<< setiosflags(ios::showpoint);
Savings_Account* account_table[10];
int count = 0;
char response;
cout << endl;
- 252 -
cout << "Do you want to create an account?(Y/N): ";
response = cin.get();
cin.get(); //Prazni ulazni bafer
//Brisanje
cout << "Owner's Name: " << acc.Get_Name() << endl << endl;
Savings_Account* acc_ptr;
- 253 -
cin.getline(id, 5);
- 254 -
- 255 -
10. Nasleivanje
Jedan od najvanijih koncepata u objektno orijentisanom
programiranju je nasleivanje. Nasleivanje dozvoljava da definiemo klasu
u odnosu na druge klase, to ini lakim kreiranje i odravanje jedne
aplikacije. Poinjemo sa nekoliko primera.
- 256 -
Interest_Bearing_Account je poznata kao osnovna klasa (roditelj klasa ili super
klasa). Klase ispod osnovne u hijerarhiji su izvedene klase (dete klase ili
podklase). Klase mogu biti direktno i indirektno izvedene.
- 257 -
class Test_Class
{
private:
int n;
public:
Test_Class(int i = 0); //Konstruktor sa jednim argumentom
Test_Class(Test_Class&); //Konstruktor kopije
~Test_Class(); //Destruktor
};
- 258 -
Prema tome, ako elimo da metodi klase Derived_Test_Class imaju
pristup primerku varijable n klase Test_Class, mora da promenimo kategoriju
pristupa za n na protected.
class Test_Class
{
protected: //Podaci kojima se moe pristupiti u izvedenim klasama
int n;
public:
Test_Class(int i = 0); //Konstruktor sa jednim argumentom
Test_Class(Test_Class&); //Konstruktor kopije
~Test_Class();
};
public:
Derived_Test_Class(int j = 0);
Derived_Test_Class(Derived_Test_Class&);
~Derived_Test_Class();
};
U ovom sluaju kljuna re public znai da smo javno izveli ovu
klasu iz osnovne klase. Javno izvoenje znai da se protected i public lanovi
osnovne klase posmatraju kao protected i public lanovi izvedene klase.
Default tip izvoenja je private, a ne public. Sledi, ako zanemarimo
rezervisanu re public, izvedena klasa bie privatno izvedena iz osnovne
klase. Dobra je praksa da ukljuujemo re public ili private a da ne koristimo
default.
Koristimo public izvoenje ako elimo da korisnici izvedene klase
imaju pristup public metodima osnovne klase. Koristimo private izvoenje,
ako elimo da blokiramo korisnike izvedene klase od korienja public
metoda osnovne klase. Da biste izveli klasu iz osnovne klase, u deklaraciji
izvedene klase, nakon imena izvedene klase sledi zapeta pa onda kljuna re
- 259 -
public ili private, i ime osnovne klase. Tabela prikazuje mogunost pristupa
pri public i private izvoenju.
- 260 -
Treba obratiti panju da smo primerak promenljive m izvedene klase
Derived_Test_Class definisali kao protected. Ovo omoguava da, ako smo izveli
klasu iz Derived_Test_Class, lanu m moi e da se pristupi kao protected lanu
svih javno izvedenih klasa.
Derived_Test_Class dtc_object1(7);
Derived_Test_Class::Derived_Test_Class(int j) : Test_Class(j+1)
{
m = j;
- 261 -
cout << endl;
cout << "Derived_Test_Class Constructor Executed: "
<< "Data member initialized to "
<< m << endl;
}
Test_Class::Test_Class(int i)
{
n = i;
Test_Class::Test_Class(int i) : n(i)
{
- 262 -
cout << endl;
cout << "Test_Class Constructor Executed: Data member initialized to "
<< n << endl;
}
- 263 -
#include <iostream>
class Test_Class
{
protected:
int n;
public:
Test_Class(int i = 0); //Konstruktor sa jednim argumentom
~Test_Class();
};
Test_Class::Test_Class(int i) : n(i)
{
cout << endl;
cout << "Test_Class Constructor Executed: Data member initialized to "
<< n << endl;
}
Test_Class::~Test_Class()
{
cout << endl;
cout << "Test_Class Destructor Executed for object with data member "
<< n << endl;
}
public:
Derived_Test_Class(int j = 0);
~Derived_Test_Class();
};
- 264 -
Derived_Test_Class::~Derived_Test_Class()
{
cout << endl;
cout << "Derived_Test_Class Destructor Executed "
<< "for object with data member "
<< m << endl;
}
int main()
{
cout << "Test_Class object being created:" << endl;
Test_Class tc_object1(4);
cout << endl;
cout << "Derived_Test_Class object being created:" << endl;
Derived_Test_Class dtc_object1(7);
return 0;
}
- 265 -
Test_Class izvrava. Konano, Test_Class objekat tc_object1 se unitava,
Test_Class destruktor za ovaj objekat se izvrava.
#include <iostream>
using namespace std;
class Test_Class
{
protected:
int n;
public:
Test_Class(int i = 0); //Konstruktor sa jednim argumentom
Test_Class(const Test_Class &); //Konstruktor kopije
~Test_Class();
};
Test_Class::Test_Class(int i) : n(i)
{
cout << endl;
cout << "Test_Class Constructor Executed: Data member initialized to "
<< n << endl;
}
Test_Class::~Test_Class()
{
cout << endl;
cout << "Test_Class Destructor Executed for object with data member "
<< n << endl;
}
- 266 -
class Derived_Test_Class : public Test_Class
{
protected:
int m;
public:
Derived_Test_Class(int j = 0);
Derived_Test_Class(const Derived_Test_Class &);
~Derived_Test_Class();
};
Derived_Test_Class::~Derived_Test_Class()
{
cout << endl;
cout << "Derived_Test_Class Destructor Executed "
<< "for object with data member "
<< m << endl;
}
int main()
{
Derived_Test_Class dtc_object1(7);
Derived_Test_Class dtc_object2 = dtc_object1;
cout << endl;
return 0;
}
- 267 -
Kd za konstruktor kopije slian je kodu za konstruktor. Treba
obratiti panju da u definiciji konstruktora kopije za Test_Class, koristimo
izraz n(tc_r.n) u inicijalizacionoj listi. Ovo inicijalizuje n primerak
promenljive objekta koja je inicijalizovana na vrednost n primerka
promenljive objekta koji je na desnoj strani inicijalizacije. Definicija
konstruktora kopije za Derived_Test_Class poziva konstruktor kopije,
Test_Class(dtc_r), na svojoj inicijalizacionoj listi i inicijalizuje m primerak
varijable objekta koji je bio incijalizovan na vrednost m primerka
promenljive na desnoj strani inicijalizacije, m(dtc_r.m).
Vaan je redosled izvrenja konstruktora i destruktora. Program prvo
deklarie Derived_Test_Class objekat dtc_object1. Zatim se konstruktor za
Test_Class izvrava. Nakon toga izvrava se konstruktor za Derived_Test_Class.
Sledee, program deklarie i inicijalizuje Derived_Test_Class objekat
dtc_object2. Kako je objekat inicijalizovan, konstruktor kopije se koristi. Kao
i kod obinog konstruktora, konstruktor kopije osnovne klase se izvrava
prvo. Odnosno, konstruktor kopije za Test_Class, nakon ega sledi izvrenje
konstruktora kopije za Derived_Test_Class.
Kada se program zavri, destruktori se pozivaju po obrnutom
redosledu od kreiranja objekata. Prvo se izvrava destruktor za dtc_object2,
zatim se automatski izvrava destruktor za osnovnu klasu Test_Class.
- 268 -
Nasleivanje funkcija
int Test_Class::Get_Value()
{
return n;
}
Derived_Test_Class dtc_object(7);
#include <iostream>
- 269 -
using namespace std;
class Test_Class
{
protected:
int n;
public:
Test_Class(int i = 0); //Konstruktor sa jednim argumentom
~Test_Class();
int Get_Value();
};
Test_Class::Test_Class(int i) : n(i)
{
cout << endl;
cout << "Test_Class Constructor Executed: Data member initialized to "
<< n << endl;
}
Test_Class::~Test_Class()
{
cout << endl;
cout << "Test_Class Destructor Executed for object with data member "
<< n << endl;
}
int Test_Class::Get_Value()
{
return n;
}
public:
Derived_Test_Class(int j = 0);
~Derived_Test_Class();
};
- 270 -
<< "Data member initialized to " << m << endl;
}
Derived_Test_Class::~Derived_Test_Class()
{
cout << endl;
cout << "Derived_Test_Class Destructor Executed "
<< "for object with data member " << m << endl;
}
int main()
{
Derived_Test_Class dtc_object(7);
#include <iostream>
- 271 -
class Test_Class
{
protected:
int n;
public:
Test_Class(int i = 0); //Konstruktor sa jednim argumentom
Test_Class(Test_Class &); //Konstruktor kopije
~Test_Class();
int Get_Value();
};
Test_Class::Test_Class(int i) : n(i)
{
cout << endl;
cout << "Test_Class Constructor Executed: Data member initialized to "
<< n << endl;
}
Test_Class::~Test_Class()
{
cout << endl;
cout << "Test_Class Destructor Executed for object with data member "
<< n << endl;
}
int Test_Class::Get_Value()
{
return n;
}
public:
Derived_Test_Class(int j = 0);
Derived_Test_Class(Derived_Test_Class &);
- 272 -
~Derived_Test_Class();
int Get_Value();
};
Derived_Test_Class::~Derived_Test_Class()
{
cout << endl;
cout << "Derived_Test_Class Destructor Executed "
<< "for object with data member " << m << endl;
}
int Derived_Test_Class::Get_Value()
{
return m;
}
int main()
{
Test_Class tc_object(3);
Derived_Test_Class dtc_object(7);
- 273 -
Primenjujemo Get_Value() na dva objekta u razliitim klasama. C++
kompajler zna koji Get_Value() metod da koristi po objektu na koji je metod
primenjen. U prvom sluaju, Get_Value() se primenjuje na Test_Class objekat.
Iz tog razloga, Get_Value() metod iz Test_Class se koristi. U drugom sluaju,
Get_Value() se primenjuje na Derived_Test_Class objekat. Zato, Get_Value()
metod iz Derived_Test_Class se koristi. Ovo je method overriding; kada se
metod primenjuje na objekat u izvedenoj klasi, metod u izvedenoj klasi
overrides (nadjaa-pokrije) metod sa istim imenom i potpisom (tj. isti broj
i tipovi argumenata) u osnovnoj klasi.
Ako su imena metoda ista i potpisi razliiti, overriding se ne
izvrava. Na primer, pretpostavimo da je metod Get_Value() izvedene klase
Derive_Test_Class definisan kao to sledi:
int Get_Value(int i)
{
return m + i;
}
- 274 -
Da biste primenili Get_Value() metod osnovne klase na objekat u
izvedenoj klasi, mora da kvalifikujete ime metoda sa imenom klase nakon
koje sledi operator razreenja dosega "::". Tako, izraz
dtc_object.Test_Class::Get_Value()
#include <iostream>
class Test_Class
{
protected:
int n;
public:
Test_Class(int i = 0); //Konstruktor sa jednim argumentomr
Test_Class(const Test_Class &); //Konstruktor kopije
~Test_Class();
int Get_Value();
};
Test_Class::Test_Class(int i) : n(i)
{
cout << endl;
cout << "Test_Class Constructor Executed: Data member initialized to "
<< n << endl;
}
Test_Class::~Test_Class()
{
- 275 -
cout << endl;
cout << "Test_Class Destructor Executed for object with data member "
<< n << endl;
}
int Test_Class::Get_Value()
{
return n;
}
public:
Derived_Test_Class(int j = 0);
Derived_Test_Class(const Derived_Test_Class &);
~Derived_Test_Class();
int Get_Value();
};
Derived_Test_Class::~Derived_Test_Class()
{
cout << endl;
cout << "Derived_Test_Class Destructor Executed "
<< "for object with data member " << m << endl;
}
int Derived_Test_Class::Get_Value()
{
- 276 -
return m;
}
int main()
{
Test_Class tc_object(3);
Derived_Test_Class dtc_object(7);
return 0;
}
- 277 -
klase, kvalifikujte ime metoda sa imenom osnovne klase za
kojim sledi operator razreenja dosega :: .
10.2 Polimorfizam
Hijerarhija klasa
- 278 -
Problem: pretpostavimo da elimo da omoguimo korisniku da
kreira seriju geometrijskih slika prema sopstvenom izboru. Na taj nain,
korisnik moe prvo da odlui da kreira pravougaonik odreenih dimenzija,
zatim krug odreenog poluprenika itd. Nakon kreiranja geometrijskih slika,
elimo da program prikae povrine svih geometrijskih slika. Kako da
uradimo ovo? Moemo da kreiramo niz geometrijskih slika. Meutim svi
elementi niza mora da budu istog tipa. Ne moemo da smestimo objekat
pravougaonik i objekat krug u isti niz, zato to su razliitog tipa. Odgovor
je, kao to emo videti, u korienju niza pokazivaa Shape i primena
koncepta polimorfizma.
Definicija klasa
class Shape
{
protected:
string figure_type;
public:
Shape(string ft = "Default Figure") : figure_type(ft)
{cout << endl << "Shape Constructor" << endl;}
string Get_Type() {return figure_type;}
~Shape() {cout << endl << "Shape Destructor" << endl;}
double Area() {return 0.0;}
};
- 279 -
class Circle : public Shape
{
protected:
double radius;
public:
Circle(double r) : Shape("Circle"), radius(r)
{cout << endl << "Circle Constructor" << endl;}
~Circle() {cout << endl << "Circle Destructor" << endl;}
double Area() {return 3.1416 * radius * radius;}
};
- 280 -
Pokazivai u hijerarhiji klasa
Shape* s_p1;
Shape* s_p2;
Shape* s_p3;
s_p1 = &r1;
s_p2 = &c1;
s_p3 = &t1;
cout << "The area of the rectangle is " << s_p1 -> Area() << endl;
- 281 -
//Ovaj program prikazuje koriscenje pokazivaca i metoda u hijerarhiji klasa.
#include <iostream>
#include <iomanip>
#include <string>
using namespace std;
class Shape
{
protected:
string figure_type;
public:
Shape(string ft = "Default Figure") : figure_type(ft)
{cout << endl << "Shape Constructor" << endl;}
string Get_Type() {return figure_type;}
~Shape() {cout << endl << "Shape Destructor" << endl;}
double Area() {return 0.0;}
};
- 282 -
Trapezoid(double b1, double b2, double h)
: Shape("Trapezoid"), base1(b1), base2(b2), height(h)
{cout << endl << "Trapezoid Constructor" << endl;}
~Trapezoid() {cout << endl << "Trapezoid Destructor" << endl;}
double Area() {return 0.5 * height * (base1 + base2);}
};
int main()
{
cout << setprecision(4)
<< setiosflags(ios::fixed)
<< setiosflags(ios::showpoint);
Shape* s_p1;
Circle* c_p1;
Circle c1(5);
- 283 -
povrinu 78.5400. Meutim, Area() metod koji je primenjen na Circle objekat
kroz Shape pokaziva je Area() metod iz Shape klase. Mada s_p1 pokazuje na
Circle objekat, metod osnovne klase se poziva kada je on primenjen na
objekat kroz pokaziva osnovne klase. Sledi, "nadjaavanje" metoda
(overriding) ne radi u ovom sluaju.
#include <iostream>
#include <iomanip>
#include <string>
using namespace std;
class Shape
{
protected:
string figure_type;
public:
Shape(string ft = "Default Figure") : figure_type(ft)
{cout << endl << "Shape Constructor" << endl;}
string Get_Type() {return figure_type;}
~Shape() {cout << endl << "Shape Destructor" << endl;}
virtual double Area() {return 0.0;}
};
- 284 -
~Rectangle() {cout << endl << "Rectangle Destructor" << endl;}
double Area() {return height * width;}
};
int main()
{
cout << setprecision(4)
<< setiosflags(ios::fixed)
<< setiosflags(ios::showpoint);
Shape* s_p1;
Circle* c_p1;
Circle c1(5);
- 285 -
<< s_p1 -> Area() << endl << endl;
Ovoga puta, druga cout naredba izvrava Area() metod cilja Shape
pointera s_p1. Ona radi ovo zato to smo deklarisali Area() metod u osnovnoj
klasi Shape kao virtuelni metod.
Polimorfizam dozvoljava da izbor metoda zavisi od tipa podatka
cilja pointera radije nego od tipa podatka pointera. Da bi polimorfizam
radio, objektima u hijerarhiji klasa mora se pristupati kroz pokazivae.
Samo metodi klase mogu biti virtuelni. Da bi metod u izvedenoj klasi
nadjaao virtuelni metod u osnovnoj klasi, metod u izvedenoj klasi mora da
ima isto ime i potpis (broj i tip argumenata) kao metod osnovne klase.
Metod u izvedenoj klasi sa istim imenom i potpisom kao i virtuelni metod u
osnovnoj klasi je takoe virtuelan, bez obzira da li se ili ne virtual kljuna re
pojavljuje u njegovoj deklaraciji (Zato su, Area() metodi u izvedenim
klasama iz prethodnog programa takoe virtuelni)
Funkcije lanice osnovne klase koje se u izvedenim klasama mogu
realizovati specifino za svaku izvedenu klasu, nazivaju se virtuelne
funkcije.
Virtuelni destruktori
- 286 -
//Program prikazuje nekorektno koriscenje destruktora u hijerarhiji klasa
#include <iostream>
#include <iomanip>
#include <string>
class Shape
{
protected:
string figure_type;
public:
Shape(string ft = "Default Figure") : figure_type(ft)
{cout << endl << "Shape Constructor" << endl;}
string Get_Type() {return figure_type;}
~Shape() {cout << endl << "Shape Destructor" << endl;}
virtual double Area() {return 0.0;}
};
- 287 -
public:
Trapezoid(double b1, double b2, double h)
: Shape("Trapezoid"), base1(b1), base2(b2), height(h)
{cout << endl << "Trapezoid Constructor" << endl;}
~Trapezoid() {cout << endl << "Trapezoid Destructor" << endl;}
double Area() {return 0.5 * height * (base1 + base2);}
};
int main()
{
cout << setprecision(4)
<< setiosflags(ios::fixed)
<< setiosflags(ios::showpoint);
delete s_p1;
return 0;
}
- 288 -
Napomena: Poto se konstruktor poziva pre nego to je objekat
nastao, nema smisla da bude virtuelan, jezik C++ to ne dozvoljava.
#include <iostream>
#include <iomanip>
#include <string>
class Shape
{
protected:
string figure_type;
public:
Shape(string ft = "Default Figure") : figure_type(ft)
{cout << endl << "Shape Constructor" << endl;}
string Get_Type() {return figure_type;}
virtual ~Shape() {cout << endl << "Shape Destructor" << endl;}
virtual double Area() {return 0.0;}
};
- 289 -
class Trapezoid : public Shape
{
protected:
double base1, base2, height;
public:
Trapezoid(double b1, double b2, double h)
: Shape("Trapezoid"), base1(b1), base2(b2), height(h)
{cout << endl << "Trapezoid Constructor" << endl;}
virtual ~Trapezoid() {cout << endl << "Trapezoid Destructor" << endl;}
double Area() {return 0.5 * height * (base1 + base2);}
};
int main()
{
cout << setprecision(4)
<< setiosflags(ios::fixed)
<< setiosflags(ios::showpoint);
cout << "Area() for the " << s_p1 -> Get_Type()
<< " applied through Shape pointer: "
<< s_p1 -> Area() << endl;
delete s_p1;
return 0;
}
- 290 -
Sada se destruktori za target pointer s_p1 izvravaju korektno. Prvo
se destruktor za izvedenu klasu izvrava a onda destruktor osnovne klase.
Obratite panju da smo takoe koristili aksesor metod Get_Type(), koji je
takoe primenjen kroz pokaziva.
#include <iostream>
#include <iomanip>
#include <string>
class Shape
{
protected:
string figure_type;
public:
Shape(string ft = "Default Figure") : figure_type(ft) {}
string Get_Type() {return figure_type;}
virtual ~Shape() {}
virtual double Area() {return 0.0;}
};
- 291 -
class Circle : public Shape
{
protected:
double radius;
public:
Circle(double r) : Shape("Circle"), radius(r) {}
virtual ~Circle() {}
double Area() {return 3.1416 * radius * radius;}
};
Shape* Get_Shape();
int main()
{
cout << setprecision(4)
<< setiosflags(ios::fixed)
<< setiosflags(ios::showpoint);
Shape* shapes[num_shapes];
- 292 -
cout << endl;
return 0;
}
Shape* Get_Shape()
{
Shape* s_p; //funkcija vraca pointer s_p
double height,
width,
radius,
base1,
base2;
int response;
switch (response)
{
case 1:
cout << endl << endl;
cout << "Enter the height of the rectangle: ";
cin >> height;
cout << endl << endl;
cout << "Enter the width of the rectangle: ";
cin >> width;
break;
case 2:
- 293 -
s_p = new Circle(radius);
break;
case 3:
cout << endl << endl;
cout << "Enter the first base of the trapezoid: ";
cin >> base1;
cout << endl << endl;
cout << "Enter the second base of the trapezoid: ";
cin >> base2;
cout << endl << endl;
cout << "Enter the height of the trapezoid: ";
cin >> height;
break;
default:
cout << endl << endl;
cout << "Invalid selection. Creating default object.";
break;
}
return s_p;
}
- 294 -
Svi destruktori su deklarisani kao virtual metodi. Takoe metod Area()
u klasi Shape je deklarisan kao virtual. Ovo dozvoljava da se odgovarajui
- 295 -
metod Area() primeni kroz Shape pokaziva. U glavnoj funkciji main(),
deklarisali smo niz shapes[] Shape pokazivaa. Prva for petlja dodeljuje
svakom elementu niza shapes[] Shape pokaziva koji vraa funkcija
Get_Shape().
Kada se Get_Shape() izvrava, prikazuje se korisniku meni sa
opcijama Rectangle, Circle, ili Trapezoid kreiranja geometrijskih slika. Naredba
switch odreuje akcije nakon korisnikove odluke. Ako, na primer, korisnik
eli da kreira objekat pravougaonik Rectangle, funkcija pita za visinu i irinu
pravougaonika. Zatim se kreira novi objekat Rectangle, dinamiki
korienjem operatora new. Mada ovo vraa pokaziva na objekat Rectangle,
ispravno je dodeliti ga s_p, koji je Shape pokaziva. Ako korisnik ukuca broj
koji nije 1, 2 ili 3, default sluaj iz naredbe switch kreira default Shape
objekat.
Prva for petlja inicijalizuje Shape pointere u nizu shapes[] da pokazuju
na neku kombinaciju Rectangle, Circle, Trapezoid i default objekata. Svi
elementi niza mora da budu istog tipa, kao to su elementi niza shapes[] - oni
su svi pointeri tipa Shape. Meutim, elementi niza shapes[] pokazuju na
objekte razliitog tipa. Zbog ovog razloga takvi nizovi se ponekad zovu
heterogeni nizovi.
Druga for petlja koristi polimorfizam. U svakoj iteraciji ove for petlje,
metod Area() se primenjuje kroz pointer shapes[i]. Metod Area() koji petlja
koristi zavisi potpuno od tipa oblika shape na koji pokaziva pokazuje
(polimorfizam). Suprotno, metod Get_Type() nije primenjen preko
polimorfizma. Postoji samo jedan metod Get_Type(), koji je lan klase Shape i
koji druge klase nasleuju.
Veoma je vano shvatiti da kada se program kompajlira, kompajler
ne zna koji Area() metod e se u petlji koristi kada se program bude
izvravao. U stvari, u svakoj iteraciji, razliit Area() metod se moe
primeniti. C++ odluuje koji metod da koristi kada se petlja izvrava, a ne
kada se program kompajlira. Ovo je kasno (late ili dynamic binding) ili
dinamiko vezivanje: koji metod koristiti pri pozivu shapes[i] -> Area() se ne
odluuje sve dok se kod ne izvrava. Ovo je suprotno u odnosu na rano
(early ili static binding) ili statiko vezivanje, compiler zna koja e funkcija
biti izvrena u compile time.
Konano, trea for petlja u glavnoj funkciji main() "isti" memoriju
brisanjem objekata koji su kreirani u prvoj for petlji.
- 296 -
10.3 Apstraktne osnovne klase
class Shape
{
protected:
string figure_type;
public:
Shape(string ft = "Default Figure") : figure_type(ft) {}
const char* Get_Type() {return figure_type;}
virtual ~Shape() {}
virtual double Area() = 0;
};
- 297 -
Shape Func(); //neispravna povratna vrednost
Shape& s_ref = r;
double Func(Shape*);
- 298 -
11. Fajlovi
11.1 Ulazno/izlazni tokovi
- 299 -
roditelj klasa, je primer viestrukog nasleivanja (multiple inheritance).
Kod viestrukog nasleivanja, izvedena klasa nasleuje sve lanove iz svih
klasa iz kojih je izvedena. Na taj nain klasa iostream nasleuje sve lanove
iz istream, ostream i takoe, indirektno, iz klase ios, iz koje su i istream i ostream
izvedene.
Klasa istream rukuje ulazom i ukljuuje definiciju operatora
extraction >> (koji je preklopljen). Objekat cin je lan klase istream. Metodi
get() i getline() su lanovi klase istream. Zbog toga se mogu primeniti na istream
objekat kao to je cin. Na sledei nain smo koristili ove metode:
ch = cin.get();
cin.getline(buffer, 81);
Tekstualni fajlovi
- 300 -
Korisniki deklarisani fajlovi
- 301 -
Da biste koristili fajl deklariite objekat file odgovarajueg tipa, kao
u sledeim deklaracijama:
Otvaranje fajla
outdata.dat.
out_file.open("outdata.dat");
- 302 -
program izvrava. Ime fajla moe da ukljui putanju do fajla. Na primer,
sledea naredba otvara fajl outdata.dat u root direktorijumu C: drajva.
out_file.open("C:\outdata.dat");
ofstream out_file("outdata.dat");
Kada otvorite fajl objekat ifstream, to je ulazni fajl, fajl koji ste
pridruili objektu mora ve da postoji. Ako ne postoji javlja se greka. Kako
da rukujemo sa ovom grekom?
- 303 -
Pretpostavimo da fajl koji se otvara postoji, njegov FPI se postavlja
na 0. Prvi podatak koji iitavamo iz fajla je na poziciji 0. Ako proitamo 5
karaktera iz fajla, FPI se povea za 5. Sledi, sledee itanje podataka iz fajla
poinje sa pomerajem 5.
Procesiranje fajla
Zatvaranje fajla
out_file.close();
#include <fstream>
#include <iostream>
- 304 -
using namespace std;
int main()
{
char buffer[81];
ofstream out_file("outdata.dat");
out_file.close();
return 0;
}
- 305 -
Podsetimo se da je insertion operator nasleen od ofstream klase.
Znai, da biste primenili operator na ofstream objekat kao to je out_file,
koristite insertion operator << da prosledite podatke u fajl. Smetamo
podatke u out_file tok na isti nain kao to smetamo podatke u standardni
izlazni tok, cout.
Treba obratiti panju da koristimo C-stringove (tj. nizove karaktera)
u ovom i u sledeim programima u ovom poglavlju, a ne string objekte.
Moete u prethodnom primeru da deklariete bafer kao string objekat i
program e raditi na isti nain. Meutim, uzdraemo se od korienja
objekata sa cout zato to ne elimo da stvorimo utisak da moete da uradite
tako sa proizvoljnim objektima. Na primer, ne moete da napiete kod za
Savings_Account objekat acc1:
#include <fstream>
#include <iostream>
#include <cstdlib>
int main()
{
char buffer[81];
char file_name[81];
- 306 -
cout << "Enter the name of the file you want to write to: ";
cin.getline(file_name, 81);
ofstream out_file(file_name);
if (!out_file)
{
cerr << endl;
cerr << "ERROR: File could not be opened." << endl;
cerr << "Program Terminated" << endl;
exit(1);
}
cout << endl;
cout << "Enter your name: ";
cin.getline(buffer, 81);
out_file.close();
return 0;
}
- 307 -
U ovom programu, dozvoljavamo korisniku da ukuca ime fajla u koji
e ime i adresa da budu upisani. Program dobija ime fajla od korisnika i
smeta ga u polje file_name[]. Kada je fajl objekat out_file deklarisan,
koristimo kao argument konstruktora polje sa imenom file_name, koje je
character pointer, ili string.
Kada se fajl otvara provera greaka se izvodi na sledei nain:
if (!out_file)
{
cerr << endl;
cerr << "ERROR: File could not be opened.";
cerr << "Program Terminated" << endl;
exit(1);
}
23 145 24.95
15 46 67.99
65 230 11.95
- 308 -
Prethodni fajl je primer sekvencijalnog fajla, koji je fajl iji su zapisi
snimljeni sekvencijalno jedan za drugim. Sledei program kreira
sekvencijalni tekstualni parts inventory fajl. On pita korisnika da unese
podatke za zapise u fajl. Onda program upisuje zapis u delove fajla.
//Ovaj program prikazuje kreiranje fajla sa obicnim tekstualnim podacima
//inventara u kome su podaci odvojeni praznim prostorom.
#include <fstream>
#include <iostream>
#include <cstdlib>
#include <iomanip>
int main()
{
char file_name[81];
int id_no;
int qoh;
double price;
int response;
cout << "Enter the name of the new inventory file: ";
cin.getline(file_name, 81);
ofstream inventory_file(file_name);
if (!inventory_file)
{
cerr << endl;
cerr << "ERROR: File could not be opened." << endl;
cerr << "Program Terminated" << endl;
exit(1);
}
inventory_file << setprecision(2)
<< setiosflags(ios::fixed)
<< setiosflags(ios::showpoint);
while (response)
- 309 -
{
// Uzima podatke za inventarski zapis
inventory_file << id_no << " " << qoh << " " << price << endl;
inventory_file.close();
return 0;
}
- 310 -
Program prvo pita korisnika da ukuca ime inventar fajla. Nakon
dobijanja imena, program otvara fajl kao ofstream fajl objekat inventory_file i
testira ga da vidi da li je fajl otvoren propisno. Sledee, program alje u
inventory_file setprecision() i setiosflags() naredbe koje obino alje u cout. Ovo
obezbeuje da svaka vrednost za polje cena zadrava decimalnu taku i ima
dve cifre sa desne strane decimalne take kada se upisuje u output fajl.
- 311 -
Program zatim izvrava while petlju koja kreira output fajl. U telu
petlje, program pita redom za identifikacioni broj, koliinu i cenu svakog
uzorka. Zatim se upisuje inventarski zapis u fajl.
inventory_file << id_no << " " << qoh << " " << price << endl;
Izlazni fajl
ifstream in_file;
in_file.open("outdata.dat");
ifstream in_file("outdata.dat");
#include <fstream>
#include <iostream>
- 312 -
#include <cstdlib>
int main()
{
char buffer[81];
char file_name[81];
cout << "Enter the name of the file you want to display: ";
cin.getline(file_name, 81);
ifstream in_file(file_name);
if (!in_file)
{
cerr << endl;
cerr << "ERROR: File could not be opened." << endl;
cerr << "Program Terminated" << endl;
exit(1);
}
while (!in_file.eof())
{
in_file.getline(buffer, 81);
cout << buffer << endl;
}
in_file.close();
return 0;
}
- 313 -
Proveru greke kada otvaramo fajl radimo na isti nain kao to smo
radili za izlazni fajl, proveravajui vrednost 0 za objekat klase ifstream, tj.
in_file. Kopija i displej fajla su dati u while petlji. Uslov petlje proverava
uslov za kraj ulaznog fajla. Ako nije kraj fajla, tj. ako je !in_file.eof() uslov
ispunjen (true), program izvrava telo petlje. U telu petlje getline() metod ita
liniju iz ulaznog fajla na potpuno isti nain kao to ita linije ubaene sa
tastature koristei standardni ulazni strim cin. Podsetimo se da je metod
getline() nasleen iz klase istream. Naredba cout zatim prikazuje liniju na
monitoru.
#include <fstream>
#include <iostream>
#include <iomanip>
#include <cstdlib>
using namespace std;
int main()
{
char file_name[81];
int id_no;
int qoh;
double price;
double total;
ifstream inventory_file(file_name);
- 314 -
if (!inventory_file)
{
cerr << endl;
cerr << "ERROR: File could not be opened." << endl;
cerr << "Program Terminated" << endl;
exit(1);
}
while (!inventory_file.eof())
{
total = qoh * price;
inventory_file.close();
- 315 -
Program poinje dobijanjem imena fajla sa inventarom od korisnika i
otvaranjem fajla kao fajl objekta inventory_file klase ifstream. Zatim, program
prikazuje liniju zaglavlja po kolonama.
Kada program ita iz fajla zapise sekvencijalno, tj. u jednom
trenutku jedan karakter, mora da vodite rauna da se procesira poslednji
zapis u fajlu i da se zapis procesira samo jednom.
Sledi opis koraka za itanje svih zapisa u sekvencijalnom ulaznom
fajlu:
1. Uitaj prvi zapis fajla odmah nakon otvaranja fajla.
2. Uitaj ulazni fajl ponovi odmah nakon to program
kompletira procesiranje ulaznih podataka.
Tako, tipian program koji procesira takav fajl i koristi eof() da bi
odredio kraj fajl treba da ima sledei format napisan u pseudokodu:
koja ita prva tri broja u fajlu, identifikacioni broj, koliinu i cenu i smeta
ih u tri varijable. Zatim, program ulazi u petlju za procesiranje ...
Ulazno/izlazni fajl
- 316 -
otvaranja koristei konstante moda pristupa koje su definisane u klasi ios i
zbog toga su na raspolaganju fstream, ifstream i ofstream.
Konstante moda pristupa:
ios::in Otvara fajl za ulaz (ili itanje). Ovaj mod moe takoe
da se koristi i sa ifstream fajl objektima.
ios::out Otvara fajl za izlaz (ili upisivanje). Ovaj mod moe
takoe da se koristi i sa ofstream fajl objektima.
ios::app Otvara fajl za izlaz i poinje na kraju fajla
(dodavanje). Ovaj mod se moe koristiti samo sa
ofstream objektima.
Da bismo otvorili fajl outdata.dat za ulaz, treba da napiemo kd:
Kada se otvara fajl u ios::in modu ili u ios::out modu, FPI se postavlja
na 0. Kada se otvara izlazni fajl u ios::app, ili modu dodavanja, FPI se
postavlja na broj bajtova u fajlu.
Sledei program dozvoljava korisniku da ukuca ime i adresu i smesti
ih u tekstualni fajl. Program zatim prikazuje sadraj fajla.
//Ovaj program prikazuje jednostavan rad sa fajlom (ulaz i izlaz).
//Fajl je otvoren u ios::in modu i ios::out modu.
#include <fstream>
#include <iostream>
#include <cstdlib>
int main()
{
char buffer[81];
char file_name[81];
cout << "Enter the name of the file you want to write to: ";
cin.getline(file_name, 81);
fstream file(file_name, ios::out);
if (!file)
{
cerr << endl;
cerr << "ERROR: File could not be opened." << endl;
cerr << "Program terminated" << endl;
- 317 -
exit(1);
}
cout << endl;
cout << "Enter your name: ";
cin.getline(buffer, 81);
file.close();
return 0;
}
- 318 -
Program prvo pita za ime fajla koji korisnik eli da kreira. Prvi put
kada otvorimo fajl, kreiramo fstream fajl objekat u deklaraciji i otvaramo fajl
u modu ios::out. Program zatim pita za korisnikovo ime i adresu, koje
program upisuje u fajl. Program zatim zatvara fajl i otvara isti fajl u ios::in
modu. Naredba while zatim prikazuje sadraj fajla.
Sledei program otvara fajl kreiran ranije i dodaje jednu liniju fajlu.
Da bismo otvorili fajl u ios::app modu, fajl objekat koji predstavlja fajl
file_app u programu, treba da bude ofstream objekat. Nakon dodavanja linije
fajlu, program zatvara fajl a zatim ga otvara ponovo kao ifstream fajl, file_in u
programu, tako da se moe sadraj fajla prikazati.
//Ovaj program prikazuje jednostavan fajl kao ulaz i izlaz.
//Fajl je otvoren u in, out i app modu.
#include <fstream>
#include <iostream>
#include <cstdlib>
int main()
{
char buffer[81];
char file_name[81];
cout << "Enter the name of the file you want to append to: ";
cin.getline(file_name, 81);
- 319 -
cout << "The information will be appended to your file." << endl;
if (!file_app)
{
cerr << endl;
cerr << "ERROR: File could not be opened in append mode." << endl;
cerr << "Program terminated" << endl;
exit(1);
}
file_app << buffer << endl;
file_app.close();
ifstream file_in(file_name);
if (!file_in)
{
cerr << endl;
cerr << "ERROR: File could not be opened." << endl;
cerr << "Program terminated" << endl;
exit(1);
}
while (!file_in.eof())
{
file_in.getline(buffer, 81);
cout << buffer << endl;
}
file_in.close();
cout << endl;
cout << "Program Terminated" << endl;
return 0;
}
- 320 -
11.2 Procesiranje fajla karakter po karakter
- 321 -
Uz to, get() metod uvek detektuje uslov za kraj fajla, dok extraction
operator >> ne. Podsetimo se da smo koristili eof() metod za detekciju uslova
za kraj fajla. Metod get() vraa EOF, konstanta definisana u iostream header
fajlu, ako je program doao do kraja fajla u ulaznom fajlu.
Ako je out_file otvoren, onda out_file.put(ch) smeta kopiju karaktera
uskladitenog u varijabli ch na poziciju koju odreuje FPI, i tada put() metod
poveava FPI za jedan. Sledei program kopira jedan tekstualni fajl u drugi
karakter po karakter.
//Ovaj program kopira jedan fajl u drugi koristeci get() i put()
#include <fstream>
#include <iostream>
#include <cstdlib>
int main()
{
char file_name[81];
char ch;
if (!source_file)
{
cout << endl;
cout << "ERROR: File cannot be opened.";
exit(1);
}
ofstream target_file(file_name);
if (!target_file)
{
cout << endl;
cout << "ERROR: File cannot be opened.";
exit(1);
}
- 322 -
while ( (ch = source_file.get()) != EOF )
target_file.put(ch);
source_file.close();
target_file.close();
return 0;
}
ch = source_file.get()
nije jednak EOF ako get() metod nije stigao do kraja fajla. Kada je
stigao do kraja fajla izraz je jednak EOF i petlja se zavrava.
Izlaz na printer
- 323 -
otvorili printer za izlaz, deklariite ofstream objekat i pridruite objekat
printeru. Na primer, sledea naredba deklarie ofstream objekat printer_file i
dodeljuje ga printeru:
ofstream printer_file("prn");
printer_file.put('A');
#include <fstream>
#include <iostream>
#include <cstdlib>
using namespace std;
int main()
{
char file_name[81];
char ch;
ifstream source_file(file_name);
if (!source_file)
{
cout << endl;
cout << "ERROR: File cannot be opened.";
exit(1);
}
ofstream printer_file("prn");
- 324 -
if (!printer_file)
{
cout << endl;
cout << "ERROR: Printer could not be opened.";
exit(1);
}
printer_file << "Contents of the Source File - Double Spaced."
<< endl << endl;
source_file.close();
printer_file.close();
- 325 -
se fiziki skladiti kao dva karaktera: carriage return i line feed (CR+LF).
Slino, kada program proita CRLF par iz tekstualnog fajla, sistem ih
konvertuje u jedan newline karakter. Mada program "vidi" samo jedan znak,
newline znak, operativni sistem ustvari procesira CRLF par.
Kada procesiramo fajl na sluajan nain, program mora da zna
njegovu tanu poziciju u fajlu. Ako pokuamo da procesiramo sluajno fajl
koji je otvoren kao tekstualni fajl (to je po difoltu kada koristimo mod
otvaranja) program moe da izgubi poziciju u fajlu. Ovo moe da nastane
zbog konverzije newline karaktera u par CRLF. Zbog toga kada procesiramo
fajl sluajno, ne treba da otvorimo fajl kao tekstualni.
Kada program otvori fajl kao binarni fajl, ni jedan karakter se ne
menja kada se ita ili upisuje u fajl. Program e procesirati newline karakter
koji je memorisan kao par CRLF, kao par karaktera umesto jednog
karaktera.
Za otvaranje fajla binarno, mora da koristite mod otvaranja ios::binary
zajedno sa jednim od modova koje smo ranije objasnili. Da biste ovo uradili
zahteva se korienje operatora ili |, bitwise OR operatora. Nemojte da ga
zamenite sa logikim operatorom OR, ||. Bitwise OR radi na nivou bitova
izmeu operanada. Ako je jedan od dva bita 1, onda bitwise OR daje 1. Ako
su oba bita 0, bitwise OR kao rezultat daje 0.
Na primer:
1010 1010 Prvi operand
0010 0111 Drugi operand
-------------
1010 1111 Bitwise OR
- 326 -
Bez obzira koja je bit vrednost drugog operanda, trei bit sa leve
strane mora biti 1 u rezultatu. Preostalih sedam bitova se kopira u rezultat.
Modovi otvaranja za fajlove, na primer ios::in i ios::binary, ustvari
ukazuju na specifine bitove stanja varijable definisane u klasi ios.
Ilustracije radi, pretpostavimo da otvaranje fajla u ios:: in modu kao
rezultat daje postavljanje drugog bita varijable na 1.
0100 0000
0000 1000
- 327 -
Indicator, FPI. Podsetimo se da metodi getc() i putc() odreuju gde da pristupe
fajlu koristei FPI. Zbog toga, ako radimo sa FPI, moemo da itamo ili
upisujemo karaktere na bilo kojoj eljenoj lokaciji u fajlu.
Sledei metodi koji rade sa strim objektima su na raspolaganju za
sluajan pristup fajlu:
- 328 -
Otvaranje fajla u ios::in modu postavlja njegov FPI na 0 (slika a).
Karet je iznad znaka na koji FPI pokazuje.
Slika b prikazuje FPI nakon izvrenja in_file.seekg(3L, ios::cur). Sufiks L
prouzrokuje da raunar uskladiti integer 3 kao long umesto default tip int.
Kako je drugi argument seekg() - ios::cur, metod inicijalno ne menja vrednost
FPI. Poto je prvi argument 3L, seekg() dodaje 3 vrednosti FPI. Tako da je
vrednost FPI = 3 i karakter na koji pokazuje je "d".
Slika c prikazuje kako pomeriti FPI na kraj fajla izvravajui
in_file.seekg(0L, ios::end).
Slika d prikazuje da prvi argument u seekg() moe biti negativan.
Naredba in_file.seekg(-2L, ios::cur) oduzima 2 od trenutne vrednosti FPI. Zato,
naredba "vraa" FPI na karakter 'g'.
Konano, slika e, naredba in_file.seekg (0L, ios::beg) postavlja FPI nazad
na 0, to ini da FPI pokazuje na prvi karakter u fajlu.
Moete da koristite metod tellg() da naete vrednost FPI u bilo kojoj
taki programa. Na primer, sledee naredbe izraunavaju veliinu fajla u
bajtovima:
- 329 -
long file_size;
in_file.seekg(0L, ios::end);
file_size = in_file.tellg();
int main()
{
char file_name [51];
char ch;
if (!file)
{
cout << endl;
cout << "ERROR: Could not open file.";
exit(1);
}
while ( (ch = file.get()) != EOF)
{
ch = toupper(ch);
file.seekg(-1L, ios::cur);
file.put(ch);
cout << file.tellg() << setw(6) << ch << endl;
}
file.close();
- 330 -
return 0;
}
- 331 -
smeta karakter nazad na njegovu originalnu poziciju u fajlu. Napomena,
izvrenje file.put(ch) ponovo poveava FPI za jedan, tako sledei file.get() e
vratiti sledei karakter u fajl. Poslednja naredba u telu petlje prikazuje
trenutnu vrednost FPI koristei file.tellg() i trenutnu vrednost ch.
struct Part_Record
{
char id_no[3];
int qoh;
double price;
};
- 332 -
23 145 24.95
15 46 67.99
65 230 11.95
56 37 73.95
59 1074 3.95
12 26 104.99
84 19 55.95
03 81 18.95
44 39 31.95
Part_Record part;
ifstream input_file(input_file_name);
Read_Part_Record(input_file, part);
- 333 -
Sada kada moemo da itamo podatke iz ulaznog fajla, elimo da ih
upiemo u binarni fajl kao strukturu. Da bismo ovo uradili zahteva se metod
write().
Kastujemo pokaziva na strukturu kao (char*) iz sledeeg razloga.
Programeri koji su pisali kod za metod write() nisu mogli da znaju tip
podatka prvog argumenta. Prvi argument moe da bude pokaziva na bilo
koju strukturu koju izaberete. Da biste dozvolili da metod write() bude
korien sa bilo kojim pokazivaem, metod pretpostavlja da njegov prvi
argument bude karakter pointer. Onda, da bi koristio metod, programer
prosto kastuje prvi argument kao karakter pointer.
Operator sizeof() (nije funkcija) vraa broj bajtova koji su potrebni za
skladitenje promenljive tipa koji je njegov argument. Koristite operator
sizeof() na isti nain kao to koristite funkciju. Smestite ime tipa podatka
(kao jedan od ugraenih C++ tipova ili korisniki definisanih tipova) u
zagrade nakon sizeof(). Vrednost koju vraa operator je broj bajtova
potrebnih za skladitenje varijable tog tipa. Na primer, sizeof(int) je broj
bajtova potrebnih da uskladiti ceo broj u sistem u kome je funkcija
odreena. Na Windows ili UNIX/Linux sistemu, sizeof(int) je 4.
Metod write(), koji moe da se primeni na bilo koji objekat izlaznog
fajla otvoren u binarnom modu, ima sledeu sintaksu:
- 334 -
//Ovaj program kreira sekvencijalni fajl od struktura iz tekstualnog fajla podataka
//On koristi operator >> za dobijanje podataka iz tekstualnog fajla i koristi write()
//metod za upis struktura u izlazni fajl.
#include <iostream>
#include <fstream>
#include <cstdlib>
struct Part_Record
{
char id_no[3];
int qoh;
double price;
};
void Read_Part_Record(ifstream&, Part_Record&);
int main()
{
int record_count = 0;
char input_file_name[51];
char output_file_name[51];
Part_Record part;
ifstream input_file(input_file_name);
if (!input_file)
{
cout << endl;
cout << "ERROR: Could not open text file.";
exit(1);
}
if (!output_file)
{
- 335 -
cout << endl;
cout << "ERROR: Could not open sequential file: ";
exit(1);
}
Read_Part_Record(input_file, part);
while (!input_file.eof())
{
output_file.write( (char *)&part, sizeof(Part_Record) );
++record_count;
Read_Part_Record(input_file, part);
}
cout << endl << endl << record_count << " records written.";
input_file.close();
output_file.close();
return 0;
}
- 336 -
U programu prvo deklariemo broja record_count, koji broji zapise
koje program procesira. Dva niza karaktera memoriu sistemska imena
ulaznog i izlaznog fajla. Deo part strukture Part_Record je deo gde program
smeta podatke. Program zatim dobija imena ulaznog i izlaznog fajla i
otvara pridruene fajl objekte. Obratite panju da se ulazni fajl otvara, po
default-u, kao tekstualni fajl, a izlazni se otvara kao binarni fajl.
Kada se ita fajl sekvencijalno, morate da vodite rauna da va
program procesira poslednji ulazni zapis, i da ga procesira samo jednom.
Programski kd prethodnog primera sledi ove napomene. Nakon
otvaranja ulaznog fajla, program ita prvi zapis koristei funkciju
Read_Part_Record(). Program prosleuje kao reference argumente funkciji ime
fajla i deo part strukture Part_Record. U telu funkcije, operator ekstrakcije
dobija tri polja i smeta svako u odgovarajui podatak lan strukture. Petlja
while zatim testira uslov za kraj fajla. Ako nije kraj fajla, telo petlje izvrava
i procesira zapis. Procesiranje je prosto upis kopije zapisa u sekvencijalni
izlazni fajl i poveanje brojaa zapisa. Zatim se fajl ita ponovo. Program
naputa petlju kada se ispuni uslov za kraj fajla. Program na kraju prikazuje
broj zapisa koji su procesirani i zatvara fajlove.
- 337 -
12. Specijalne teme: Prijateljske funkcije, preklapanje
operatora, makroi i inline funkcije
acc1.Transfer_Method(acc2, 100.00);
Drugi pristup bio bi definisanje funkcije koja nije lan Transfer1() koja
ima tri argumenta: prvi je prijemna sredstva, drugi sredstva koja se predaju i
trei sredstva za transfer. Tako bismo za transfer 100.00 sa acc2 na acc1,
napisali sledeu naredbu:
acc1.Deposit(amount);
- 338 -
return true;
}
class Savings_Account
{
friend bool Transfer(Savings_Account&, Savings_Account&, double);
private:
.
.
.
public:
.
.
.
};
- 339 -
Treba obratiti panju da smetamo deklaraciju friend funkcije pre
svakog specifikatora pristupa. Prosleujemo dva tedna rauna funkciji po
referenci zato to funkcija mora da promeni oba Account objekta koji su
prosleeni kao argumenti. Ako prosledimo Savings_Account objekte po
vrednosti, promene koje funkcija napravi bie uraene na parametrima
funkcije (to su kopije argumenata) a ne na samim argumentima. Sledi kod
za funkciju:
return true;
}
#include <iostream>
#include <iomanip>
#include <string>
- 340 -
using namespace std;
class Savings_Account
{
friend bool Transfer(Savings_Account&, Savings_Account&, double);
private:
char id_no[5];
char* name;
double balance;
double rate;
public:
Savings_Account(char id[], char* n_p, double bal = 0.00, double rt = 0.04);
~Savings_Account();
const char* Get_Id() const;
const char* Get_Name() const;
double Get_Balance();
};
balance = bal;
rate = rt;
}
Savings_Account::~Savings_Account()
{
cout << endl << endl;
cout << "Account " << id_no << " terminated." << endl;
delete [] name;
}
const char* Savings_Account::Get_Id() const
{
return id_no;
}
const char* Savings_Account::Get_Name() const
{
return name;
}
double Savings_Account::Get_Balance()
{
- 341 -
return balance;
}
bool Transfer(Savings_Account& acc_r1, Savings_Account& acc_r2, double
amount)
{
//Ako iznos prelazi stanje na racunu acc_r2, ne radi nista i vrati 0
return true;
}
int main()
{
cout << setprecision(2)
<< setiosflags(ios::fixed)
<< setiosflags(ios::showpoint);
double amount;
- 342 -
cout << endl;
cout << "Transfer could not be made." << endl;
}
return 0;
}
cout << "Owner's Name: " << acc.Get_Name() << endl << endl;
cout << "Account Balance: " << acc.Get_Balance() << endl << endl;
}
- 343 -
izvrenje programa u kome traimo transfer vie novca sa prvog rauna
nego to je na raunu.
- 344 -
class Test_Class
{
private:
int n;
public:
Test_Class(int i = 0); //Konstruktor sa jednim argumentom
Test_Class(Test_Class&); //Konstruktor kopije
~Test_Class();
int Get_Value();
};
Test_Class::Test_Class(int i)
{
n = i;
Test_Class::Test_Class(Test_Class& tc_r)
{
n = tc_r.n;
cout << endl << endl;
cout << "Copy constructor executed: "
<< "Data member initialized to " << n << endl;
}
Test_Class::~Test_Class()
{
cout << endl << endl;
cout << "Destructor Executed for object with data member "
<< n << endl;
}
int Test_Class::Get_Value()
{
return n;
}
Test_Class tc_object1(4);
Test_Class tc_object2(7);
- 345 -
Test_Class tc_object3;
dodela (=), funkcijski poziv (()), indeksi nizova ([]), operator indirekcije lana (->).
- 346 -
Dva argumenta u funkciji predstavljaju dva operanda (respektivno) u
binarnoj operaciji sabiranja. Kod preklapanja binarnog operatora kao friend
funkcije, prvi argument preklapanja uvek predstavlja levi operand a drugi
argument uvek predstavlja desni operand.
Sledi kd preklopljenog operatora sabiranja:
return temp_obj;
}
Test_Class tc_object1(4);
Test_Class tc_object2;
- 347 -
Test_Class operator + (const Test_Class& left_op, const int right_op)
{
Test_Class temp_obj;
return temp_obj;
}
tc_object2 = 7 + tc_object1;
#include <iostream>
class Test_Class
{
private:
int n;
public:
Test_Class(int i = 0); //Konstruktor sa jednim argumentom
Test_Class(Test_Class&); //Konstruktor kopije
~Test_Class();
int Get_Value();
};
Test_Class::Test_Class(int i)
{
n = i;
- 348 -
//cout << endl;
//cout << "Constructor Executed: Data member initialized to "
// << n << endl;
}
Test_Class::Test_Class(Test_Class& tc_r)
{
n = tc_r.n;
Test_Class::~Test_Class()
{
//cout << endl << endl;
//cout << "Destructor Executed for object with data member "
// << n <<endl;
}
int Test_Class::Get_Value()
{
return n;
}
return temp_obj;
}
return temp_obj;
}
int main()
{
- 349 -
Test_Class tc_object1(4);
Test_Class tc_object2(7);
Test_Class tc_object;
return 0;
}
Program Output
Prior to adding the objects, the value of tc_object is 0
- 350 -
Prvo sabiranje kao rezultat daje privremeni objekat Test_Class, koji se
onda dodaje objektu tc_object3, gde se opet stvara objekat Test_Class. Tree
sabiranje onda dodaje ovaj privremeni objekat celom broju 6 i kao rezultat
daje novi privremeni objekat, koji se dodeljuje objektu tc_object.
- 351 -
by-member). Ovaj tip dodele je odgovarajui za objekte Test_Class, koji
imaju jednu celobrojnu instancu promenljive. Meutim member-by-member
kopiranje nije odgovarajue za klasu koja ima jedan ili vie pokazivaa kao
instance promenljivih. Na primer, neka su acc1 i acc2 objekti klase
Savings_Account, koji imaju name instancu promenljive koja pokazuje na ime
osobe koja je vlasnik tednog rauna. Pretpostavimo da je dodela acc1 = acc2.
Kako je kopija nainjena na osnovu member-by-member, ime lanova oba
objekta pokazuju sada na ime pridrueno objektu acc2. Na taj nain oba
pokazuju na isti fiziki prostor u hip memoriji. Sledi da promena imena ili
tednog rauna e prouzrokovati da se ta promena pojavi u oba. Da bismo
izbegli ovo mora da preklopimo operator dodele.
Treba da napiete kod za preklapanje operatora na takav nain da se
preklopljeni operator ponaa kao odgovarajui tipovi podataka. Za
preklopljen operator dodele, ovo znai da sledee dodele imaju smisla za
objekte klase Savings_Account.
- 352 -
Kada preklapamo binarni operator kao metod klase, objekat na koji
se funkcija primenjuje predstavlja levi operand i jedan argument operatora
predstavlja desni operand.
Sledi deklaracija operatora. Jedan argument preklopljenog operatora
je desna strana operatora dodele. Leva strana operatora dodele je objekat na
koji je dodela primenjena.
Pokaziva this
Test_Class::Test_Class(int i)
{
n = i;
Test_Class::Test_Class(int i)
{
this -> n = i;
- 353 -
Sledi kd za preklopljeni operator dodele.
#include <iostream>
#include <iomanip>
#include <string>
- 354 -
double balance;
double rate;
public:
Savings_Account(char id[], char* n_p, double bal = 0.00, double rt = 0.04);
Savings_Account(const Savings_Account &);
~Savings_Account();
double Calc_Interest();
double Get_Balance();
const char* Get_Id() const;
const char* Get_Name() const;
void Deposit(double);
bool Withdraw(double);
balance = bal;
rate = rt;
}
Savings_Account::Savings_Account(const Savings_Account& acc_r)
{
strcpy(id_no, acc_r.id_no); //kopira prvi argument u id_no[]
balance = acc_r.balance;
rate = acc_r.rate;
}
Savings_Account::~Savings_Account()
{
delete [] name;
}
double Savings_Account::Get_Balance()
{
return balance;
}
- 355 -
double Savings_Account::Calc_Interest()
{
double interest;
return interest;
}
const char* Savings_Account::Get_Name() const
{
return name;
}
const char* Savings_Account::Get_Id() const
{
return id_no;
}
void Savings_Account::Deposit(double amount)
{
balance += amount;
}
bool Savings_Account::Withdraw(double amount)
{
bool result;
return result;
}
Savings_Account & Savings_Account::operator = (const Savings_Account &
right_op)
{
if (&right_op == this)
; //ne radi nista
else
{
strcpy(id_no, right_op.id_no); //kopira id desnog operanda right_op u id_no[]
delete [] name;
name = new char[strlen(right_op.name) + 1]; //kreira prostor za name
- 356 -
strcpy(name, right_op.name); //kopira drugi argument u novi prostor
balance = right_op.balance;
rate = right_op.rate;
}
return *this;
}
Savings_Account Get_Account(); //Prototip za funkciju Get_Account()
int main()
{
cout << setprecision(2)
<< setiosflags(ios::fixed)
<< setiosflags(ios::showpoint);
Savings_Account acc1 = Get_Account();
Display_Account(acc1);
Display_Account(acc2);
acc1 = acc2;
Display_Account(acc1);
Display_Account(acc2);
return 0;
}
Savings_Account Get_Account()
{
char id[5];
char buffer[81];
double bal;
double rt;
- 357 -
cout << endl;
cout << "Enter Account ID: ";
cin.getline(id, 5);
return acc;
}
void Display_Account(Savings_Account& acc_r)
{
cout << endl;
cout << "Data for Account# " << acc_r.Get_Id() << endl << endl;
cout << "Owner's Name: " << acc_r.Get_Name() << endl << endl;
- 358 -
Program kreira dva tedna rauna koristei funkciju Get_Account() i
prikazuje sadraje oba rauna koristei Display_Account(). Zatim program
dodeljuje objekat acc2 objektu acc1 i prikazuje sadraje oba tekua rauna da
bi pokazao da su tekui rauni zaista isti.
- 359 -
direktivu #define. Moete koristiti pretprocesorsku direktivu #define da biste
definisali makroe, koji mogu ponekad da zamene funkcije.
Definicija makroa
#define SQ(x) x * x
- 360 -
Makro koji se definie je SQ(x), a njegova definicija je x * x. Kada
C++ pretrocesor vidi ovakav #define, on pretrauje program da bi pronaao
sva pojavljivanja makroa sa imenom SQ. Pretpostavimo, na primer, da
pretprocesor pronae SQ(count) u programu. Pretprocesor tada zamenjuje
makro SQ(count) izrazom dobijenim zamenom parametra x u definiciji
makroa sa count. Tako e pretprocesor zameniti izraz
s = SQ(count);
sa
s = count * count;
#define SQ (x) x * x
s = SQ(count);
s = (x) x * x(count);
int i = 2,
j = 4,
k;
k = SQ(i + j);
- 361 -
Operator dodele ne dodeljuje vrednost 36 promenljivoj k kako prvo
moe da se pomisli. Pretprocesor ekspanduje makro u dodeli, zamenjujui
svaku pojavu parametra x stringom i + j, na sledei nain.
k = i + j * i + j;
sledi:
k = (i + j) * (i + j);
- 362 -
Inline funkcije
double d1 = 4.8,
d2 = 9.6
d;
d = Max(d1, d2);
- 363 -
Inline funkcije takoe igraju vanu ulogu kada su metodi definisani
u deklaraciji klase. Razlika izmeu definisanja metoda unutar ili izvan
deklaracije klase je da je metod klase koji je definisan unutar deklaracije
klase, po default, inline. Ako definiete metod izvan deklaracije klase, tada
inline metod, mora da smestite da prethodi definiciji odnosno kljunoj rei
inline.
- 364 -
Dodatak A:
Integrisano razvojno okruenje Microsoft Visual C++
1.1 Uvod
1.2 Pojmovi
- 365 -
Izvorni fajl (eng. source file) sadri implementaciju programskog
modula.
Resursni fajl (eng. resource file) sadri definicije elemenata
grafikog interfejsa koje koristi Windows kada izvrava dati program (bit
mape, meniji, dijalozi itd.). Pravljenje novog programa poinje stvaranjem
novog radnog prostora i projekta. Otvaranje prethodno kreiranog projekta
(nastavak rada sa zapoetim projektom) omogueno je otvaranjem fajla sa
nastavkom dsw.
- 366 -
1.4 Radno okruenje
- 367 -
1.4.1 Prozor radnog prostora
- 368 -
2. OPTE MANIPULACIJE PROJEKTIMA
- 369 -
Slika 2.1.2: Project:
1. Project name
2. Location
- 370 -
Slika 2.1.3: Files:
1. Project name
2. Location
- 371 -
Kreiranje novog projekta (korak-po-korak) vri se na sledei nain:
- Odabrati File->New
- Odabrati stranu Projects
- Odabrati Win 32 Dynamic-Link Library
- U polje Projects upisati Figure
- Pritisnuti dugme pored polja Location da be se izabralo gde e se
smestiti novi projekat ili se lokacija moe direktno upisati u polje
predvieno za to
- Pritisnuti OK
- U dijalogu koji se pojavi odabrati An empty DLL project i pritisnuti
Finish
- Pritisnuti OK u dijalogu koji prikazuje informacije o projektu koji
e biti napravljen
- 372 -
Slika 2.2.1: Ubacivanje novog projekta
- 373 -
Konfiguracije se mogu dodati ili obrisati biranjem komande
Configurations iz menija Build. Odreena konfiguracija se podeava
biranjem komande Settings iz menija Project.
Podeavanje konfiguracija vri se na sledei nain:
- 374 -
Slika 2.3.3: Add Project Configuration
3. UREIVANJE PROGRAMA
- 375 -
CPravougaonik();
virtual -CPravougaonik();
private:
UINT visina;
UINT sirina;
};
- 376 -
Slika 3.1.2: Ubacivanje fajlova u projekat
- Odabrati File->New
- Odabrati stranu Files i C+ + Source File (slika 3.1.3)
- U polje File name uneti Pravougaonik i odabrati istu lokaciju kao
za Pravougaonik.h
- Potvrditi Add to project i u listi ispod, odabrati projekat Figure
- Uneti sledei kod u Pravougaonik.cpp:
#include "Pravougaonik.h"
CPravougaonik::CPravougaonik()
{
sirina=8;
visina=5;
}
CPravougaonik:: ~CPravougaonik()
{
sirina=0;
visina=0;
}
- 377 -
Slika 3.1.3: Dijalog za dodavanje novog fajla
- 378 -
3.2.1 Class Wizard
- 379 -
- U dijalogu Add Member Function (slika 3.2.1.4) uneti void u polje
Function Type, a u polje Function Declaration uneti: setVelicina(UINT a, UINT
b)
- 380 -
Slika 3.2.1.4: Tip i deklaracija funkcije
- 381 -
podeavanja koja budu promenjena sa desne strane odrazie se na oba
projekta:
- 382 -
3.2.2 Ureivanje koda
- 383 -
3.2.3 Sintaksno bojenje
3.2.4 Veba
//Pravougaonik.h
public:
CPravougaonik{};
virtual -CPravougaonik();
UINT getObim();
UINT getPovrsina();
void setVelicina(UINT a, UINT b);
private:
UIXT visina;
UTNT sirina;
};
//Pravougaonik.cpp
((include "Pravougaonik. h"
CPravougaonik::CPravougaonik()
{
sirina = 8 ;
visina = 5;
}
CPravougaonik::~CPravougaonik ()
{
sirina = 0;
visina = 0;
}
- 384 -
void CPravougaonik::setVelicina(UINT a, UINT b)
{
sirina = a;
visina = b;
}
UINT CPravougaonik::getPovisina()
{
return sirina*visina;
}
UINT CPravougaonik::getObim()
{
return 2*(sirina+visina);
}
// Kvadrat.h
// Kvadrat.cpp
#include "Kvadrat.h"
CKvadrat::CKvadrat()
setVelicina(5);
CKvadrat::~CKvadrat()
{
};
void CKvadrat::setVelicina(UINT a);
CPravougaonik::setVelicina(a,a);
// MojProgram.cpp
- 385 -
cout << "Obim pravougaonika: "<<pravougaonik.getObim()<<endl;
cout << "Povrsina pravougaonika: "<<pravougaonik.getPovrsina()<<endl;
cout << endl;
cout << "Obim kvadrata: "<<kvadrat.getObim()<<endl;
cout << "Povrsina kvadrata: 11 < <kvadrat. getPovrsina ()< <endl;
a=12 ;
b=9;
pravougaonik.setVelicina(a,b);
kvadrat.setVelicina(a);
return 0;
4. PREVOENJE PROGRAMA
- 386 -
prekida prevoenje), na izlaznom panou se pojavljuje broj greaka i
upozorenja. Ako je program sintaksno ispravan, a MSVC ga smatra i
semantiki korektnim, javie: 0 greaka, 0 upozorenja.
4.1 Veba
- 387 -
4.3 Pomo u radu
4.4 Podeavanja
- 388 -
5. DEBAGOVANJE
Korak po korak:
- 389 -
Odabrati stranu Link i potvditi Generate debug info i Link
incrementally
Pritisnuti OK
- 390 -
Strana This prikazuje podatke lanove objekta na koji pokazuje
this pokaziva tekue funkcije lanice.
- 391 -
5.4 Take prekida
- 392 -
Korak po korak:
- 393 -
Dodatak B: Integrisano razvojno okruenje Microsoft Visual
C++ 2008
1. Uvod
- 394 -
podataka. Datoteke sa reenjima koje su generisane alatom Expression
mogu se otvoriti i ureivati u programu Visual Studio. Dizajneri i
programeri su u mogunosti da izgrade biblioteke opteg dizajna
korisnikog interfejsa, formata i elemenata kojima se moe lako upravljati i
koji se mogu ponovo koristiti.
Visual Studio 2008 je jedinstven skup alata koji omoguava
pravljenje kvalitetnih aplikacija na Microsoft-ovim platformama. Podrka za
razvoj operativnog sistema Windows Vista i sistema Microsoft Office
pomae kreiranju efektne i bogate aplikacije. Uz ukljuenu podrku za
ASP.NET AJAX i programski dodatak Silverlight za Visual Studio 2008,
mogua je izgradnja velikog broja bogatih interaktivnih aplikacija za Web.
Visual Studio omoguava razvoj WPF aplikacija (za programiranje u
C#) u cilju direktnog ureivanja XAML (sa IntelliSense podrkom) ili
kreiranja korisnikog interfejsa kroz nove vizuelne dizajnere. Promena koja
je nainjena u prikazu aplikacije jednom od ovih alatki odmah se oslikava
na drugoj. Pored toga, program Visual Studio nudi podrku za vie od 8.000
novih osnovnih API-ja u operativnom sistemu Windows Vista.
Lako korienje znai da Visual Studio u velikoj meri asistira
korisniku i umesto njega radi mnotvo poslova koji su dobro definisani. U
prevodu, umesto korisnika pravi kostur aplikacije i time oslobaa korisnika
od tog posla, kao i od uenja kako se to radi.
- 395 -
Slika 1.1.1 Odabir programskog jezika
- 396 -
Slika 1.1.2 Import i Export Settings
- 397 -
Slika 1.1.3 Import i Export Settings
- 398 -
Naravno, ovu inicijalnu konfiguraciju radnog okruenja mogue je
proizvoljno menjati prema eljama korisnika. Iako je izgled radnog
okruenja identian, unapreeni IDE navigator omoguava lake kretanje
izmeu delova okruenja, doking prozora u okruenju je unapreen i
olakan, kao i mogunost podeavanja default fonta za okruenje.
- 399 -
unapreeno je debagovanje postavljanje breakpoint-a u JavaScript pre
izvravanja ASP.NET stranica, reorganizovanje breakpoint-a dok se stranice
jo izvravaju, poboljan prikaz sadraja objekata i jo mnogo detalja koji u
svakodnevnom radu puno znae. Kada je rad sa podacima u pitanju, Visual
Basic i Visual C# nude mogunost dobijanje podataka iz baza, XML fajlova
ili ak objekata, korienjem LINQ, specijalnih query operatora koji su
integrisani u ove jezike.
Excell Add-in
Workbook
Word Add-in
Document
Visio Add-in
- 400 -
Tehnologija koja stoji iza ovih template-ova je Visual Studio Tools
for Office (VSTO) i ona omoguava korienje otvorenih funkcija bilo koje
od Office aplikacija za kreiranje samostalnih aplikacija ili dokumenata
zasnovanih na Office aplikacijama.
- 401 -
Slika 1.2.1 IntelliSence ikonice
- 402 -
Slika 2.1 MFC Application
- 403 -
Slika 2.2 MFC Application Wizard
- 404 -
Slika 2.3 Application Type
- 405 -
Slika 2.4 User Interface Features
- 406 -
Na kraju MFC Application Wizard generie klase i daje prikaz
njihovih imena (slika 2.6). Klikom na Finish otvara se novo radno okruenje
sa podeenim opcijama i praznim dijalogom za dalje kreiranje aplikacije
(slika 2.7).
- 407 -
Slika 2.7 Radno okruenje nakon kreiranja kostura grafike aplikacije
- 408 -
Slika 3.1 Kreiranje kostura konzolne aplikacije
- 409 -
Slika 3.2 Kreiranje praznog projekta
- 410 -
3.1 Dodatak MSDN Subscriptions Comparison Chart
- 411 -
Reference:
- 412 -
Odlukom Senata Univerziteta Singidunum, Beogrd, broj 636/08 od 12.06.2008,
ovaj udbenik je odobren kao osnovno nastavno sredstvo na studijskim programima koji
se realizuju na integrisanim studijama Univerziteta Singidunum.
CIP -
,
004.432.2C++
, , 1956-
Programski jezik C++ : sa reenim
zadacima / Ranko Popovi, Zona Kosti. -
Beograd : Univerzitet Singidunum, 2010
(Loznica : Mladost grup). - 412 str. :
ilustr. ; 25 cm
ISBN 978-86-7912-286-5
1. , , 1983- []
a) C++
COBISS.SR-ID 178203916
2010.
Sva prava zadrana. Ni jedan deo ove publikacije ne moe biti reprodukovan u bilo kom
vidu i putem bilo kog medija, u delovima ili celini bez prethodne pismene saglasnosti
izdavaa.