Svaki objekat ima jedan specijalni pokazivač pod nazivom this koji pokazuje na sam objekat. Članovima objekta klase Box se može pristupiti pomoću ovog pokazivača, kao npr:
this->length; this->width; this->height;
Svaki objekat u C++-u ima pristup svojoj adresi (adresi na kojoj je smešten u memoriji) pomoću pokazivač this. Pokazivač this je jedan implicitni parametar za sve funkcije članice klase. Stoga, unutar tela funkcije članice, pokazivač this se može koristiti za objekat nad kojim je funkcija članica i pozvana.
Korišćenje pokazivača this može biti korisno kod definisanja pristupnih funkcija, gde argument često može da ima isto ime kao i član klase. Onda pokazivač this može da omogući razliku između argumenta i člana klase. Pokazivač this se primenjuje u sledećem primeru:
void Box::setLenght(int lenght) { this -> lenght = lenght; } void Box::setWidth(int width) { this -> width = width; } void Box::setHeight(string height) { this -> height = height; }
Ako ime člana i ime argumenta u pristupnoj funkciji nisu u suprotnosti, pokazivač this nije potreban. Primer:
void Friend::setLenght(int len) { length = len; }
Pogledajmo i isprobajmo još jedan primer da bismo bolje razumeli korišćenje pokazivača this:
#include <iostream> using namespace std; class Box { public: Box(double l=2.0, double b=2.0, double h=2.0) { cout << "Konstruktor pozvan." << endl; length = l; breadth = b; height = h; } double Volume() { return length * breadth * height; } int compare(Box box) { return this->Volume() > box.Volume(); } private: double length; // Duzina kutije double breadth; // Sirina kutije double height; // Visina kutije };
Glavni program možemo napisati na sledeći način:
int main(void) { Box Box1(3.3, 1.2, 1.5); // Deklaracija objekta box1 Box Box2(8.5, 6.0, 2.0); // Deklaracija objekta box2 if(Box1.compare(Box2)) { cout << "Box2 je manji od Box1" << endl; } else { cout << "Box2 je veci ili jednak od Box1" << endl; } return 0; }
Rezultat programa će biti:
Konstruktor pozvan. Konstruktor pozvan. Box2 je veci ili jednak od Box1
Objektima neke klase je moguće pristupiti korišćenjem pokazivača. Jednom deklarisana, klasa postaje validni tip podatka pa se za pristup adresama na kojima su smešteni objekti mogu koristiti pokazivači. Deklarisanje pokazivača na klasu vršimo na sledeći način:
Rectangle * prect;
gde će prect biti pokazivač na objekat klase Rectangle. Pokazivač na klase se koristi na isti način kao i pokazivač na strukture.
Da bismo pristupili članu klase korišćenjem pokazivača na klasu, koristimo operator pristupa -> na isti način kao kod pokazivača na strukturu. Naravno, neophodno je inicijalizovati pokazivač pre samog korišćenja. U nastavku je main funkcija u kojoj testiramo klasu Box:
void main(void) { Box Box1(3.3, 1.2, 1.5); // Deklaracija objekta box1 Box *ptrBox; // Declaracija pokazivaca na klasu. ptrBox = &Box1; cout << "Zapremina od Box1: " << ptrBox->Volume() << endl; }
Nakon izvršavanja programa dobiće se sledeći rezultat:
Konstruktor pozvan. Zapremina od Box1: 5.94
Operatore new i delete možemo koristiti na isti način i kod dinamičkog alociranja memorije neophodnog za kreiranje objekata. Uzmimo u obzir sledeću deklaraciju i iskaz:
Time *timePtr; timePtr = new Time;
Operator new alocira odgovarajući memorijski prostor neophodan za smeštanje objekta tipa Time, poziva podrazumevajući konstruktor koji inicijalizuje podatke objekta i kao rezultat vraća pokazivač na tip podatka sa desne strane operatora new (tj. tip je Time*).
Ukoliko operator new nije u stanju da odvoji odgovarajući memorijski prostor nastaće greška, i izbaciće se izuzetak (exception). Da bi se oslobodio odvojeni memorijski prostor, koristi se operator delete:
delete timePtr;
Kreiraćemo sada klasu Rectangle da bi demonstrirali korišćenje dinamičkog alociranja memorije:
class Rectangle { int width, height; public: Rectangle(int x, int y) : width(x), height(y) {} int area(void) { return width * height; } };
U narednom main programu vršimo testiranje pokazivača:
int main() { Rectangle obj (3, 4); Rectangle * foo, * bar; foo = &obj; bar = new Rectangle (5, 6); cout << "Povrsina od obj: " << obj.area() << '\n'; cout << "Povrsina od *foo: " << foo->area() << '\n'; cout << "Povrsina od *bar: " << bar->area() << '\n'; delete bar; return 0; }
U ovom primeru je korišćeno nekoliko operatora nad objektima i pokazivačima (*, &, ., ->, []). Njih interpretiramo na sledeći način:
*x // pokazivač na x &x // adresa promenljive x x.y // član y objekta x x->y // član y objekta na koji pokazuje x (*x).y // član y objekta na koji pokazuje x (isto kao prethodno) x[0] // prvi objekat na koji pokazuje x x[1] // drugi objekat na koji pokazuje x x[n] // (n+1)-vi objekat na koji pokazuje x
Konstruktor kopiranja je konstruktor koji kreira objekat i inicijalizuje ga vrednostima objekta iste klase, koji je prethodno kreiran.
Ukoliko konstruktor kopiranja nije definisan u okviru klase, kompajler ga automatski sam definiše. Ukoliko klasa ima pokazivačku promenljivu članicu, i ukoliko se ta promenljiva koristi za dinamičko alociranje memorije onda je neophodno da postoji konstruktor kopiranja. Najuobičajeniji oblik konstruktora kopiranja je prikazan u sledećem primeru:
classname (const classname &obj) { // telo konstuktora }
gde je obj referenca objekta koji se koristi za inicijalizaciju drugog objekta. U nastavku je dat primer definicije klase Line i definisanja osnovnog i konstruktora kopiranja:
#include <iostream> using namespace std; class Line { public: int getLength( void ); Line( int len ); // uobicajeni konstruktor Line( const Line &obj); // konstruktor kopiranja ~Line(); // destructor private: int *ptr; }; // Definicija funkcija clanica klase, ukljucujuci konstruktor Line::Line(int len) { cout << "Normalni konstruktor alocira ptr" << endl; // alociraj memoriju za pokazivac; ptr = new int; *ptr = len; } Line::Line(const Line &obj) { cout << "Konstruktor kopiranja alocira ptr." << endl; ptr = new int; *ptr = *obj.ptr; // kopiraj vrednost } Line::~Line(void) { cout << "Oslobadjanje memorije!" << endl; delete ptr; } int Line::getLength( void ) { return *ptr; } void display(Line obj) { cout << "Duzina linije : " << obj.getLength() << endl; }
Pretpostavimo da je glavni program napisan na sledeći način:
int main( ) { Line line(10); display(line); return 0; }
Nakon kompajliranja i izvršavanja prethodnog programa dobiće se sledeći izlaz:
Normalni konstruktor alocira ptr Konstruktor kopiranja alocira ptr. Duzina linije : 10 Oslobadjanje memorije! Oslobadjanje memorije!
Pogledajmo sada primer sa malim izmenama u cilju kreiranja novog objekta korišćenjem već napravljenog objekta istog tipa:
#include <iostream> using namespace std; /* definicija klase i funkcija klase je ostala ista*/ int main( ) { Line line1(10); Line line2 = line1; // Takodje pozica konstruktor kopiranja display(line1); display(line2); return 0; }
Rezultat programa će sada biti:
Normalni konstruktor alocira ptr Konstruktor kopiranja alocira ptr. Konstruktor kopiranja alocira ptr. Duzina linije : 10 Oslobadjanje memorije! Konstruktor kopiranja alocira ptr. Duzina linije : 10 Oslobadjanje memorije! Oslobadjanje memorije! Oslobadjanje memorije!