Fujitsu-Siemens
 
M A G A Z I N
 
PROGRAMIRANJE 
  Davor Đošan

C++ - predstavljanje

C++ je programski jezik sa mnoštvom odličnih osobina. Cilj ovog članka je da upoznamo programere početnike sa nekima od njih, kao i da ljudima koji se već bave programiranjem skrenemo pažnju na neke aspekte o kojima možda nisu razmišljali.


Malo istorije


C++ je razvio Bjarne Stroustrop i možemo da ga posmatramo kao bolji C

Programski jezik C, prethodnik jezika C++, je postao jedan od najpopularnijih programskih jezika. Njegova prvenstvena namena je bila za sistemsko programiranje. C kao jezik omogućava programerima pisanje veoma efikasnog koda.
U toku 80-tih i 90-tih dolazi do velike ekspanzije u razvoju objektno orijentisanih tehnologija i u to vreme se pojavljuje programski jezik SmallTalk. Objektno orijentisano programiranje (OOP) je počelo da zamenjuje strukturirano. Sve ovo je dovelo do razvoja mnogobrojnih objektno orijentisanih programskih jezika (Object-Pascal, Modula-2, Mesa, Cedar, Neon, Objective-C) od kojih je većina nestala u toku 80-tih.
C++ je razvio Bjarne Stroustrop i možemo da ga posmatramo kao bolji C. To je možda i najtačnija definicija ovog programskog jezika. Iako C++ nije sasvim novi programski jezik, on ipak predstavlja značajno proširenje mogućnosti C-a. Možemo smatrati da je C podskup C++-a. Od svog prethodnika je nasledio sve njegove dobre osobine kao i većinu loših, ali obezbeđuje i jezička unapređenja, a dodate su mu i objektne mogućnosti. Treba napomenuti da korištenje C++ ne znači automatski i OOP. Mi možemo pisati u C++-u regularne strukturirane programe.


Bolji C


Cilj je da predstavimo te nove osobine da bi se uvidele njihove prednosti.

Dizajneri C++-a su hteli da dodaju objektne mehanizme a da se pri tome ništa ne izgubi od jednostavnosti i efikasnosti koje su učinile C tako popularnim.
C++ sadrži C kao podskup što praktično znači da on nasleđuje sve dobre osobine koje ima C kao sto su na primer efikasnost i veliki broj ugrađenih tipova. Dodate su takođe i nove osobine koje su učinile jezik još robustnijim, ali se mnoge od njih ne koriste od strane programera početnika. Cilj je da predstavimo te nove osobine da bi se uvidele njihove prednosti. Neke od osobina koje ćemo predstaviti su: konstante, inline funkcije, reference, deklaracije, klase, preklapanje funkcija i operatora i dinamičko alociranje memorije.
C++ omogućava programerima ugrađivanje novih tipova podataka korišćenjem klasa. Klasa je tip podataka definisan od strane korisnika. Kompajler tretira nove tipove na isti način kao i ugrađene. Ovo je veoma moćna osobina. Klase omogućavaju apstrakciju podataka a to je ključna osobina OOP.


Nova forma komentara


Komentari su veoma poželjni unutar programa da bi program bio čitljiviji i razumljiviji drugima. U C-u komentari su sledećeg oblika:
/* Ovo je tradicionalni C komentar */

C++ takođe podržava tradicionalne C komentare, ali takođe i omogućava lakši mehanizam za komentare. Taj mehanizam ima sledeći izgled:
// Ovo je C++ komentar
Sve iza // i kraja linije je komentar.
Ono što je preporučljivo je da, iako C++ podržava komentare iz C-a, ipak koristimo njegov mehanizam komentara. Time bismo mogli izbeći greške tipa:
/* int i = 10 /* i inicijalizujemo sa 10 */

………….
*/
Vidimo da će u ovom slučaju biti prijavljena greška jer ćemo naići na */ unutar linije i to će se smatrati za kraj komentara.


Konstante


U C-u, konstante se često definišu korišćenjem #define. #define je u stvari makro. To znači sledeće. Ukoliko imamo definiciju:
#define PI 3.14159265358979323846
Prilikom prevođenja programa svako pojavljivanje PI u programu biće zamenjeno sa 3.14159265358979323846. C++ nam dozvoljava da svaku promenljivu deklarišemo kao konstantu dodavanjem const ključne reči prilikom njene deklaracije. Definicija konstante za ovaj prethodni slučaj bi izgledala:
const double PI = 3.14159265358979323846;
Konstantan objekat se moze biti inicijalizovan, ali se njegova vrednost nikada ne može promeniti. Činjenica da konstantan objekat ne može biti promenjen omogućava kompajleru da generiše efikasniji kod.
Veoma moćan način korišćenja konstanti je u kombinaciji sa pokazivačima. Ako dafinišemo pokazivač na konstantu on se neće moći koristiti za promenu objekta na koji pokazuje. Na primer:
int i = 10;
const int *pi = &i;
*pi = 15; // GRESKA! pi je konsantan pokazivac!

Nije moguće promeniti vrednost i preko pokazivača *pi. Ovakav tip pokazivača se koristi u funkcijama koje vraćaju pokazivač na privatni član klase. On bi korisniku omogućio da čita privatni član ali ne i da ga menja.
Na žalost, korisnik ipak moze da menja ove podatke korišćenjem eksplicitne konverzije tipa podataka. Mogli bismo da uradimo menjanje i iz prethodnog primera kada bismo uradili sledeće:
*((int*) pi) = 15;
Međutim, mi vraćanjem konstantnih pokazivača iz funkcija upozoravamo korisnika da postoji opasnost ukoliko menja te podatke, a on može da ih menja ali na spostveni rizik.
Postoje dva načina da stavimo const pri deklaraciji pokazivača. Jedan način smo već videli a drugi bi bio:
int i = 10;
int j = 11;
int* const ptr = &i;

Na ovaj način, sam pokazivač postaje konstantan. To znači da pokazivač ne može biti promenjen, tj. ne može da pokazuje na neki drugi objekat osim onog koji mu je inicijalno naveden te je nemoguće napisati nešto tipa:
ptr = &j;
Treba zapamtiti da će dodavanjem const ključne reči izazivati duze vreme kompajliranja ali time neće doći do generisanja dodatnog koda od strane kompajlera.


Inline funkcije


Drugi uobičajen način korišćenja #define makroa je u slučajevima kada hoćemo da izbegnemo pozivanje funkcija. To su slučajevi kada je funkcija toliko mala da vreme izvršavanja tela funkcije traje kraće nego poziv funkcije. C++ nam obezbeđuje inline ključnu reč koja informiše kompajler da tu funkciju treba da ugradi u kod, a ne da generiše kod za pozivanje rutine. Na primer makro:
#define max (x, y) ((x)>(y)?(x):(y))
može u C++-u da bude zamenjen za celobrojne vrednosti inline funkcijom:
inline int max (int x, int y)
{
return (x > y ? x : y);
}

Upotreba makroa može da bude problematična u nekim slučajevima. Zamislimo da smo imali sledeći izraz:
max (f(x), z++);
To bi nam u slučaju upotrebe makroa postalo:
((f(x)) > (z++) ? (f(x) : (z++));
Upotrebom inline funkcija bismo ove probleme izbegli.
Prilikom definisanja klasa moguće je unutar njene definicije navesti telo funkcije. Ovakve funkcije će takođe biti tretirane kao inline funkcije. Na primer:
class A {
int a;

public:
A() { }
// inline
int Value()
{
return a;
}
// inline
}


Reference


Za razliku od C-a, C++ nam omogućava korišćenje referenci. Referenca je u stvari ime već postojećeg objekta. Reference su slične pokazivačima i moraju biti deklarisane pre nego što ih koristimo. Definišimo jedan podatak tipa int i jednu referencu na njega:
int n = 10;
int& r= n;

U ovom slučaju r nam je alias za n. I jedno i drugo se odnose na isti objekat. Tako izraz:
r = -10;
menja i r i n u -10.
Veoma je važno primetiti da su inicijalizacija i dodela vrednosti dve različite stvari za reference.
Više o referencama se može pročitati u članku “Prenošenje podataka po referenci”.


Deklaracije


U C++-u deklaracije za promenljive se mogu staviti bilo gde u kodu, tj. bilo gde u programskom bloku. Ako pretpostavimo da pretražujemo neku linkovanu listu da bismo pronašli neki ključ funkcija bi mogla izgledati kao:
int IsMember (const int key)
{
int found = 0;
if (NotEmpty())
{
List* ptr = head;
// Declaration
while (ptr && !found)
{
int item = ptr->data;
// Declaration
ptr = ptr->next;

if (item == key)
found = 1;
}
}
return found;
}

Stavljanjem deklaracija promenljivih bliže mestima gde se one koriste kod postaje mnogo čitljiviji.


Preklapanje funkcija i operatora


Jedna od mnogih odličnih osobina jezika C++ je svakako i mogućnost preklapanja imena funkcija i operatora. Pod tim se podrazumeva da za jedno ime funkcije ili simbol operatora možemo da navedemo više različitih definicija. Broj argumenata i njihov tip pri pozivu funkcije govori kompajleru koju definiciju treba da uzme na tom mestu.
Uzmimo na primer da hoćemo da napravimo funkciju koja pretražuje po nekom ključu niz koji može da sadrži int, float ili double vrednosti. Definicija te funkcije bi bila:
int Search ( const int* data,
const int key);
int Search ( const float* data,
const float key);
int Search ( const double* data,
const double key);

Kompajler će osigurati da se prava funkcija pozove na osnovu argumenata koje prosledimo funkciji. Ukoliko neki od argumenata ne odgovara kompajler će pokušati implicitnu konverziju da bi dobio odgovarajuci tip.
Preklapanje se najčešće koristi za funkcije članice klasa i operatore koje definišemo u klasama. Većina klasa ima preklopljene konstruktore, jer obično postoji više načina da se kreira objekat nekog tipa. Takođe se vrlo često preklapaju i operatori definisani unutar funkcija.


Alociranje memorije


C++ nam obezbeđuje operatore new i delete koji mogu da alociraju ne samo ugrađene tipove, nego i sve ostale tipove podataka koje smo definisali. Ovo nam omogućava jedinstven mehanizam za alociranje i oslobađanje memorije.
Na primer za alociranje jednog integer-a i niza integer-a bismo koristili sledeće:
int *pi;
pi = new int;
*pi = 1;
int *array = new int [10];
for (int i=0;i < 10; i++)
array[i] = i;

Treba napomenuti da memorija koju alociramo sa new nije inicijalizovana. Sva memorija koju alociramo sa new treba da bude oslobođena sa delete. Delete poziva destruktor za objekat koji se uništava. Takođe, potrebno je eksplicitno naglasiti brisanje niza podataka i to na sledeći način:

delete [] array;
Kompajler čuva informacije o tome koliko članova ima neki niz, a sa parom uglastih zagrada mi ga samo informišemo da je u pitanju brisanje niza. Inače bi bio pobrisan samo prvi član niza. Takođe, treba naglasiti da ukoliko pokusamo delete na pokazivač koji nije alociran sa new ponašanje programa biće nedefinisano.
new i delete su globalni C++ operatori i oni mogu biti redefinisani ukoliko za to postoji potreba.


Klase


Mehanizam klasa omogućava korisnicima da definišu sopstvene tipove podataka. Klase se obično koriste za definisanje apstrakcija koje se ne preslikavaju prirodno na ugrađene tipove podataka. Objekat nije ništa drugo do intanca neke klase. Uprošćena definicija za klasu Vector bi bila:
class Vector
{
public:
Vector(double new_x=0.0,double new_y=0.0);
Vector operator + ( const Vector & v);
void PrintOn (ostream& os);
…………….
private:
double x, y;
};

Kada se u programu definiše objekat tipa vektor imamo sledeće:
Vector v1, v2, v3(0.0,0.0);
Vektori v1 i v2 u ovom slučaju imaju neinicijalizovane vrednosti i potrebno ih je naknadano inicijalizovati, dok je v3 inicijalizovan na pravi način.

 

VRH STRANE

(c) 2003 OMEGA - sva prava zadržana