Curs C++ | Sectiunea 19 – Functii (Transmitere de parametri)
Orice functie trebuie sa aiba abilitatea de a comunica cu mediul. Trebuie sa poata primi date, sa le proceseze si sa distribuie rezultatul. Cunoastem pana acum doua forme de comunicare:
- transferarea datelor catre o functie folosind parametrii efectivi (actual parameters), ale caror valori sunt asignate parametrilor formali
- transferarea datelor de la o functie folosind rezultatul functiei (o singura valoare se poate transfera sub aceasta forma folosind instructiunea return)
💡 Am spus in sectiunile precedente ca variabilele definite in interiorul corpului functiei nu pot fi accesibile in afara functiei. Exista insa un tip special de variabila numit variabila globala (global variable). Acestea sunt declarate in afara oricarei functii (inclusiv functia main) si pot fi accesibile tuturor functiile declarate in acel fisier sursa.
❗ Declararea acestui tip de variabila trebuie facuta inaine de definirea functiilor in care este folosita.
Variabilele globale permit functiilor sa primeasca si sa furnizeze orice tip de date. Daca o functie care nu foloseste alt mecanism de a transfera date, modifica o variabila globala, spunem ca acea functie are un efect secundar (side effect).
❌ Efectele secundare, desi folositoare uneori, nu sunt recomandate si sunt considerate un semn pentru un stil de programare gresit, facand dificila citirea si intelegerea codului.
global_variable este variabila noastra globala. Declararea ei nu se afla in nicio functie iar power o multiplica de fiecare data cu 2 cauzand un efect secundar. Pe de alta parte, main nu modifica variabila, doar o afiseaza astfel ca nu este considerat un efect secundar.
❗ Vom evita folosirea efectelor secundare pe viitor. Trebuie sa stiti doar ca exista dar nu va faceti un mod de gandire din ele.
Passing by value
Am presupus pana acum ca valorile parametrilor nostrii efectivi sunt transferati functiei dar nu am spus ce se intampla pe drumul de intoarcere. Sa facem un mic experiment sa vedem ce se intampla de fapt.
❓ Avem o functie function_by_value ce primeste valoarea unui parametru si il incrementeaza. Intrebarea se pune, variabila modificata va fi vizibila in afara functiei? Reflecta modificarea parametrului formal valoarea parametrului efectiv?
In urma compilarii, obtinem urmatorul rezultat in consola:
❗ Dupa cum putem vedea, valoarea parametrului formal nu modifica si valoarea parametrului efectiv. In realitate, parametrul formal devine o copie a parametrului efectiv, copiind valoarea in momentul invocarii, insa aici se opreste si asemanarea dintre cei doi.
💡 Acest mod de comunicare, bazat pe copierea valorii in momentul invocarii poarta numele de transfer prin valoare (passing by value).
Passing by reference
💡 A doua metoda este cunoscuta sub numele de transfer prin referinta (passing by reference) si permite functiilor sa modifice valorea parametrilor efecivi.
Primul lucru pe care trebuie sa-l facem este sa anuntam in declararea functiei folosind &:
- type nume – parametrul nume este trasferat ca valoare (passed by value)
- type &nume – parametru nume este transferat ca referinta (passed by reference)
Cand un parametru este transferat ca referinta, parametrul formal este un sinonim al parametrului efectiv. Orice modificare facuta parametrului formal are efect si asupra parametrului efectiv asociat. In realitate, parametrul formal devine un pointer ce indica la adresa parametrului efectiv.
❓ Bineinteles, apare imediat intrebarea, care este atunci diferenta dintre un pointer si o referinta? Ei bine raspunsul este unul simplu si il deducem din cele discutate.
📝 Un pointer poate fi NULL, dupa cum va amintiti, dar o referinta trebuie mereu sa aiba o valoare, adica sa indice la o adresa.
Astfel ca in urma rularii exemplului nostru, vom avea rezultatul asteptat:
Mixed
Putem sa folosim si ambele metode in acelasi timp. Selectia modului in care transferam fiecare parametru se face individual. In exemplul de mai sus, primul parametru este transferat ca referinta iar al doilea ca valoare.
Rezultatul va fi cel asteptat, si anume:
❗ Nu uitati, daca un parametru este declarat ca referinta, parametrul efectiv corespondent trebuie sa fie o variabila. Astfel ca daca daca avem o functie function(int & x) si o invocam conform urmatoarelor exemple:
- function(x);
- function(x + 10);
- function(function_two());
Singura metoda corecta este prima, avand o variabila ca paremtru in momentul invocarii. Pe de alta parte, daca am avea o functie ce primeste un parametru ca valoare, toatele cele 3 variante ar fi corecte.
Passing by pointer
💡 Aceasta metoda nu mai este recomandata, fiind mostenita de la stramosul nostru C, fiind singura optiune valabila la acel moment. Limbajul C nu are mecanismul de referinta, astfel ca idea de baza este sa transferam un pointer la o valoare, nu valoare in sine. Prototipul ar fi de forma urmatoare:
Permitem astfel functiei sa acceseze adresele care indica la valorile corespunzatoare, in cazul nostru int si prin urmare, avem posibilitatea sa modificam acele valori indicate de parametru.
❗ Functia function_by_ptr are un pointer ca parametru si acceseaza valoarea la care indica prin operatorul de dereferentiere. Astfel, modificam valoarea la care acesta indica. Observati si modul in care invocam functia, transferam ca parametru adresa variabilei noastre, asa cum am lucrat anterior cu pointerii.
Rezultatul executarii programului este cel asteptat:
❌ Desi unii pot considera ca aceasta este a treia metoda de a transfera un parametru, in realitate este un mod mai vechi de a transfera prin valoare.
Aici se termina si aceasa sectiune, vom continua tot cu functii in urmatoarele sectiuni 🙂 . Pentru mai multe intrebari puteti folosi informatiile de aici.
➡ Sectiunea anterioara:Curs C++ | Sectiunea 18 – Functii (Declarare & Definire)
➡ Sectiunea urmatoare:Curs C++ | Sectiunea 20 – Functii (Parametri Default)

