#include<iostream>
using namespace std;
class C {
int i;
public:
C(int j) { i = j; } //constructor
int da() {
return i;
}
};
void main()
{
C ob[4] = {1, 2, 3, 4}; //aici se face initializarea
#include<iostream>
using namespace std;
class C {
int a, b;
public:
C(int j, int k) { //constructor
a = j;
b = k;
}
int da_a() {return a;}
int da_b() {return b;}
};
void main()
{
C ob[3] = { C(1, 2), C(3, 4), C(5, 6) }; //initializare
Pentru a declara matrici de obiecte care sa poata fi initializate trebuie definit un constructor cu parametri
care sa faca posibila initializarea.
Pentru a declara matrici de obiecte care sa nu fie initializate trebuie definit un constructor fara parametri.
Pentru a declara matrici de obiecte care sa fie cand initializate cand neinitializate se supraincarca functia
constructor.
#include<iostream>
using namespace std;
class C {
int i;
public:
C() { i = 0; } //apelare ptr. matrice neinitializate
C(int j) { i = j; } //apelare ptr. matrici initializate
int da() {return i; }
};
void main()
{
C ob1[3] = {1, 2, 3}; //initializat
C ob2[34]; //neinitializat
}
Atunci cand este incrementat un pointer, el indica spre urmatorul element de acelasi tip cu al sau. De
exemplu, un pointer de tip intreg va indica urmatorul intreg. Tot asfel se intampla in cazul pointerului la obiecte.
#include<iostream>
using namespace std;
class C {
public:
int i, j;
C(int k, int m) {i = k; j = m;}
};
void main()
{
C ob(1, 2);
int *p = NULL, *q = NULL;
Deoarece p indica spre un intreg, el este declarat ca un pointer de tip intreg. In aceasta situatie este
irelevant ca i este un membru al obiectului ob.
Pointerul this
Cand este apelata o functie membru, i se paseaza un argument implicit, care este un pointer catre obiectul
care a generat apelarea (obiectul care a invocat functia). Acest pointer este numit this.
La membrii unei class se poate capata acces direct dintr-o functie membru. Instructiunea b = j; ar comanda
ca valoarea continuta in baza sa fie atribuita unei copii a lui b asociata obiectului care a generat apelarea. Totusi,
aceeasi intructiune poate fi scrisa si astfel:
this->b = j;
Pointerul this indica spre obiectul care a apelat ADUNA(). Astfel, this->b se refera la copia b pentru acel
obiect. De exemplu, daca ADUNA() este apelata de ob (ca in ob(1, 2)), atunci this din instructiunea precedenta
indica spre ob. ATENTIE: scrierea instructiunii fara this este doar o prescutare.
Pointerul this este transmis automat catre toate functiile membru.
PRECAUTII:
1. functiile friend nu sunt membri ai clasei si de aceea nu le sunt pasati pointeri this
2. functiile membre static nu au un pointer this
#include<iostream>
using namespace std;
class ADUNA {
int a, b, suma;
public:
ADUNA(int i, int j) {
this->a = i;
this->b = j;
this->suma = this->a + this->b;
}
int da() {return this->suma;}
};
void main()
{
ADUNA ob(1, 2);
cout<<ob.da()<<endl;
}
Un pointer din clasa de bază poate să fie folosit ca un pointer spre un obiect din oricare clasă derivată din
clasa de bază.
Reciproca nu este adevărată: un pointer din clasa derivată nu poate indica spre un obiect din clasa de bază.
Mai mult, chiar dacă se poate folosi un pointer din baza pentru a indica un obiect derivat, accesul este permis doar la
membrii de tip derivat care au fost importati din baza. Deci nu este permis accesul la membrii adaugaţi în clasa
derivată. Totuşi pointerul din clasa de bază poate fi convertit la unul (pointer) derivat şi câştigă acces la deplin la
întreaga clasă derivată.
#include<iostream>
using namespace std;
class BAZA {
int b;
public:
void pune_b(int num) {b = num; }
int da_b() {return b; }
};
void main()
{
BAZA *pb;
DERIVAT d;
pb->pune_b(10);
Pointerul care “indică” generic către un membru al unei clase şi nu către un anumit exemplar al acelui
membru dintr-un obiect se numeşte pointer către un membru al clasei (sau pointer-la-membru). Pointerul la membru
nu este acelaşi lucru cu pointerul normal. Pointerul la membru asigură doar un offset (o poziţie) într-un obiect din
clasa membrului, unde poate fi găsit acel membru. Deoarece pointerul la membru nu este pointer adevărat, nu i se
poat aplica operatorii . şi ->. Pentru a avea acces la membrul unei clase prin intermediul unui pointer spre el, va
trebui să folosiţi operatorii speciali ai pointerilor la membri, .* şi ->*. Misiunea lor este să vă permită accesul la un
membru al unei clase prin intermediul unui pointer către acesta.
#include<iostream>
using namespace std;
class C {
public:
C(int i) {val = i;}
int val;
int val_dubla() {return val+val;}
};
void main()
{
int C::*date; //pointer la o data membru
int (C::*func)(); //pointer la o functie membru
C ob(1), *pob;
pob = &ob;
cout<<(ob.*func)()<<endl;
cout<<(pob->*func)()<<endl;
}
Referinţe
O referinţă este un pointer implicit care acţionează ca un alt nume al unui obiect.
Parametri de referinţă
Referinţa permite crearea unor funcţii care folosesc automat transmiterea prin referinţă.
Pentru a crea o apelare prin referinţă în C, trebuie pasată explicit funcţiei adresa argumentului.
#include<iostream>
using namespace std;
void main() {
int x = 1;
fa_10(&x);
cout<<x<<endl;
}
fa_10() preia ca parametru un pointer către un întreg pe care îl va transforma în 10. În interiorul funcţiei fa_10()
trebuie folosit operatorul * pentru a avea acces la variabila spre care indică i. Acesta este modul de generare a unei
apelări-prin-referinţă-manuale.
În C++, pentru a crea un parametru de referinţă, numele parametrului trebuie precedat de &. Funcţia
fa_10() ar deveni:
void fa_10(int &i);
i devine practic un alt nume pentru orice argument folosit la apelul funcţiei. Altfel spus, i este un pointer implicit
care se referă la argumentul folosit pentru invocarea funcţiei fa_10(). Folosirea mai departe a operatorului * nu mai
este permisă. De asemenea, în apelul funcţiei nu mai este permisă folosirea operatorului &.
#include<iostream>
using namespace std;
void main() {
int x = 1;
fa_10(x); //x este apelat prin referinta si schimbarea lui este definitiva
cout<<x<<endl;
}
Când se face apel prin referinţă, nu se face nici o copie a obiectului, aşa cum se întâmplă cu apelul prin
valoare. Aceasta înseamnă că nici un obiect folosit ca parametru nu este distrus atunci când se termină funcţia, iar
destructorul parametrului nu este apelat.
NOTĂ: când parametrii sunt transmişi prin referinţă, schimbările obiectului din interiorul funcţiei afectează
obiectul apelant.
Returnarea referinţelor
O funcţie poate să returneze o referinţă ceea ce face ca ea să poată fi folosită în membrul stâng al unei
instrucţiuni de atribuire.
#include<iostream>
using namespace std;
int var_globala = 1;
void main() {
schimba();
cout<<var_globala<<endl; //output: 2
schimba() = 3;
cout<<var_globala<<endl; //output: 3
}
ATENŢIE!!!
#include<iostream>
using namespace std;
int var = 1;
void main() {
schimba(3); //local var devine 2 dar var e distrus la iesirea din functie
cout<<var<<endl; //aici var este globala; output: 1
schimba(4); //local var devine 2 dar var e distrus la iesirea din functie
cout<<var<<endl; //aici var este globala; output: 1
}
CORECT AR FI:
#include<iostream>
using namespace std;
int var = 1;
void main() {
schimba(var); cout<<var<<endl; //output: 2
schimba(var) = 3; cout<<var<<endl; //output: 3
}
Referinţe independente
O referinţă care este doar o simplă variabilă este numită referinţă independentă.
#include<iostream>
using namespace std;
void main() {
int a;
int &ref = a; //referinta independenta
NOTĂ: referinţa independentă este de mică valoare practică deoarece ea este de fapt doar un alt nume aceeaşi
variabilă. Având două nume care descriu acelaşi obiect programul poate deveni confuz.
RESTRICŢII:
1. o referinţă nu poate referi altă referinţă
2. nu se pot crea matrice de referinţe
3. nu se poate crea un pointer spre o referinţă
4. nu se pot face referinţe la câmpuri de biţi
ATENŢIE:
1. o referinţă trebuie iniţializată la declarare
2. o referinţă poate să nu fie declarată dacă este membru al unei clase, parametru de funcţie sau o valoare returnată