Vreau sa scriu cod fara sa ma repet!
Obiectivul lectiei
Imagineaza-ti ca ai un program cu aceleasi 5 linii copiate in 3 locuri diferite. Apoi gasesti un bug... si trebuie sa-l repari in toate cele 3 locuri. Asta e un cosmar!
Dupa aceasta lectie vei putea:
- Sa explici ce este o functie si de ce ai nevoie de ea
- Sa implementezi de ce repetarea codului e o problema grava
- Sa aplici ce inseamna void
- Sa aplici apelarea = chemarea functiei
- Sa aplici fiecare functie face un singur lucru
Testeaza inainte sa inveti!
Nu trebuie sa intelegi totul acum. Doar copiaza, ruleaza si observa ce se intampla.
afiseazaLinie() este apelata de 3 ori, dar scrisa o singura data. Ce apare pe ecran?
"********************" cu "====================" . Ruleaza din nou. Ce observi? Cate linii ai modificat?
void salut() care afiseaza "Buna ziua!". Apeleaz-o din main inainte de prima linie.
void afiseazaCaseta() care afiseaza o caseta completa (linie, text, linie) si apeleaz-o de 2 ori!
Ai modificat o singura linie (cea din interiorul functiei), dar efectul se vede in toate cele 3 locuri unde e apelata. Asta e puterea functiilor!
Fara functie, ai fi trebuit sa modifici 3 linii separate. Cu functia, modifici una singura.
Scrie noua functie deasupra lui main (la fel ca afiseazaLinie):
void salut() {
cout << "Buna ziua!" << endl;
}
Apoi, in main(), scrie salut(); pe prima linie (inainte de afiseazaLinie();).
Poti chema o functie din alta functie! Scrie:
void afiseazaCaseta() {
afiseazaLinie();
cout << " Mesaj important!" << endl;
afiseazaLinie();
}
Pune aceasta functie dupa afiseazaLinie si inainte de main.
Ce este o functie si de ce ai nevoie de ea?
O functie (sau subprogram) este un bloc de cod cu un nume pe care il poti apela (chema) ori de cate ori ai nevoie, fara sa rescrii codul.
Gandeste-te asa: in loc sa copiezi aceleasi linii de cod in 5 locuri, le scrii o singura data intr-o functie, si apoi doar chemi functia de 5 ori.
Cand vrei sa faci prajituri, nu inventezi reteta de fiecare data. O scrii o data pe o foaie si apoi o folosesti ori de cate ori vrei sa gatesti. Reteta este functia. A gati dupa reteta este apelarea functiei.
Daca vrei sa schimbi cantitatea de zahar, modifici doar reteta, nu toate prajiturile pe care le-ai facut vreodata!
De ce repetarea codului e o problema grava
Cand copiezi acelasi cod in mai multe locuri, se intampla 3 lucruri rele:
| Problema | Ce se intampla concret |
|---|---|
| Bug multiplicat | Gasesti un bug intr-o copie. Il repari. Dar ai uitat ca exista inca 2 copii cu acelasi bug. Programul tot nu merge. |
| Cod greu de citit | 200 de linii de cod cu blocuri repetate vs. 50 de linii cu functii clare. Care e mai usor de inteles? |
| Timp pierdut | Orice modificare trebuie facuta in N locuri. Cu o functie, o faci o singura data. |
Ce inseamna void?
Cuvantul void inseamna "nimic" sau "gol". O functie void este o functie care face ceva (afiseaza text, deseneaza pe ecran, etc.) dar nu returneaza un rezultat.
Gandeste-te la reteta din analogia de mai sus: void afiseazaLinie() este ca un bucatar care executa un pas din reteta (afiseaza linia) dar nu iti da nimic inapoi — ti-a facut treaba, atat. In schimb, o functie fara void (cu tip returnat) este ca un bucatar care executa pasul si iti da rezultatul: "am calculat suma, uite: 42". Lectia 4 acopera functiile cu valoare returnata.
Apelarea = chemarea functiei
Ca sa "chemi" o functie, scrii numele ei urmat de paranteze si punct si virgula:
Definirea functiei = scrierea "retetei" (o faci o singura data).
Apelarea functiei = folosirea "retetei" (o faci de cate ori vrei).
O functie pe care o definesti dar nu o apelezi niciodata este ca o reteta pe care o scrii dar nu o gatesti niciodata - codul din ea nu se va executa.
Fiecare functie face UN singur lucru
Un program bine scris este ca o echipa: fiecare membru (functie) are un rol clar. Nu pui un singur om sa faca totul!
Regula: daca poti descrie ce face functia intr-o singura propozitie, atunci e bine definita.
Regula de plasare: functia INAINTE de apel
In C++, functia trebuie sa fie definita inainte de locul unde o apelezi. De obicei, scriem functiile deasupra lui main().
Exercitii practice
Exercitiul 1 (Nivel minim) - Analiza conceptelor
Raspunde la urmatoarele intrebari despre functii:
- Explica in cuvintele tale ce inseamna principiul DRY si de ce este important in programare. Da un exemplu concret de situatie in care l-ai aplica.
- Care este diferenta intre definirea unei functii si apelarea ei? De ce trebuie sa le facem pe amandoua?
- Un coleg a scris o functie
void salut() { cout << "Buna!"; }dar programul nu afiseaza nimic. Ce a uitat sa faca? Explica.
Raspunde numerotat: 1. ... 2. ... 3. ...
Vezi rezolvarea
- DRY (Don't Repeat Yourself) inseamna sa nu scrii acelasi cod in mai multe locuri. In loc sa copiezi un bloc in 5 locuri, il scrii o singura data intr-o functie si o apelezi de cate ori ai nevoie. Exemplu: o linie decorativa "====" folosita in 10 locuri devine functia
separator(), apelata de 10 ori. - Definirea = scrii codul functiei o singura data (ca reteta). Apelarea = folosesti reteta, de cate ori vrei. Ai nevoie de ambele: fara definire nu exista cod de executat; fara apelare, codul definit nu ruleaza niciodata.
- Colegul a uitat sa APELEZE functia. A scris
void salut() { cout << "Buna!"; }dar nicaieri inmain()nu a scrissalut();. O functie definita dar neapelata nu se executa.
Exercitiul 2 (Nivel standard) - Programeaza cu functii
Cerinta: Scrie un program C++ care contine 3 functii void:
void separator()- afiseaza o linie de 30 de caractere '-'void antet()- apeleaza separator(), afiseaza "MAGAZIN ONLINE", apoi apeleaza separator() din nouvoid produse()- afiseaza o lista de 3 produse (ex: "1. Laptop - 2500 lei")
In main(), apeleaza: antet(), produse(), separator().
Exemplu output:
------------------------------
MAGAZIN ONLINE
------------------------------
1. Laptop - 2500 lei
2. Mouse - 50 lei
3. Tastatura - 150 lei
------------------------------
Indicii:
- Defineste toate cele 3 functii deasupra lui
main() - Functia
antet()poate apelaseparator()- dar separator trebuie definit inainte de antet! - Ordinea definirii conteaza: separator → antet → produse → main
Vezi rezolvarea
Program complet, respectand ordinea ceruta: separator inainte de antet, ambele inainte de main.
void separator() { cout << "------------------------------" << endl; } void antet() { separator(); cout << " MAGAZIN ONLINE" << endl; separator(); } void produse() { cout << "1. Laptop - 2500 lei" << endl; cout << "2. Mouse - 50 lei" << endl; cout << "3. Tastatura - 150 lei" << endl; } int main() { antet(); produse(); separator(); return 0; }
Observa: antet() apeleaza separator(), care e definita DEASUPRA ei - de aceea ordinea conteaza.
Exercitiul 3 (Nivel performanta) - Refactorizeaza si extinde
Cerinta: Mai jos este un program C++ care afiseaza 3 raporturi identice (fara functii). Codul este repetitiv si greu de modificat.
#include <iostream>
using namespace std;
int main() {
cout << "========================" << endl;
cout << " RAPORT SCOALA" << endl;
cout << "========================" << endl;
cout << "Clasa: 8A" << endl;
cout << "========================" << endl;
cout << "========================" << endl;
cout << " RAPORT SCOALA" << endl;
cout << "========================" << endl;
cout << "Clasa: 8B" << endl;
cout << "========================" << endl;
cout << "========================" << endl;
cout << " RAPORT SCOALA" << endl;
cout << "========================" << endl;
cout << "Clasa: 8C" << endl;
cout << "========================" << endl;
return 0;
}
- Scrie o functie
void separator()care afiseaza linia"========================"si o functievoid antetRaport()care afiseaza separatorul, titlul si separatorul. Rescriemain()sa foloseasca aceste functii pentru toate cele 3 rapoarte (clasele 8A, 8B, 8C). Programul trebuie sa produca acelasi output ca inainte. - Extinde: adauga o a treia functie
void raport(string clasa)care primeste numele clasei si afiseaza intregul raport (antet + clasa + separator de inchidere). Rescriemain()sa apelezeraport("8A"),raport("8B"),raport("8C"). Ai nevoie de#include <string>. - Reflecta si scrie: daca directorul iti cere sa schimbi titlul din "RAPORT SCOALA" in "SITUATIE CLASE", cate linii modifici in versiunea cu functii vs. versiunea originala? Noteaza raspunsul intr-un comentariu C++ in cod (
// ...).
Indicii:
- Functia
raport(string clasa)poate apelaantetRaport()— functia ta poate apela alte functii! - Ordinea de definire conteaza:
separator→antetRaport→raport→main - Pentru a afisa un
string:cout << clasa << endl;
Cuvinte cheie de folosit: void, functie, apel, parametru, string, DRY, refactorizare
Vezi rezolvarea
Nu scriem tot codul - iti dam doar schita, ca sa ai ce rezolva:
- Scrie
void separator()care afiseaza doar linia de egal, sivoid antetRaport()care apeleaza separator(), afiseaza titlul, apoi apeleaza separator() din nou (in aceasta ordine!). - In
main(), inlocuieste blocurile repetate cu apeluri: pentru fiecare clasa, cheama antetRaport(), apoi afiseaza clasa, apoi separator() de inchidere. - Pentru extindere, scrie
void raport(string clasa)care combina antetRaport() + afisarea clasei + separator() final, si apeleaza-l de 3 ori din main cu "8A", "8B", "8C".
Capcana: ai nevoie de un #include pentru string. Criteriu de reusita: output identic cu programul original, dar cu cod de 3x mai scurt.
Ce ai invatat astazi
- Ai invatat ce este o functie si de ce ai nevoie de ea
- Acum stii de ce repetarea codului e o problema grava
- Ai descoperit ce inseamna void
- Ai explorat apelarea = chemarea functiei
- Ai inteles fiecare functie face un singur lucru
- Ai invatat regula de plasare: functia inainte de apel
Vrei mai mult?
Provocare: Ia programul cu linie(), titlu() si meniu() din lectie. Adauga o a patra functie, afiseazaAutor(), care afiseaza numele tau. Apeleaz-o din main() exact intre titlu() si meniu(). Ruleaza programul: numele tau apare unde trebuie, nu inainte, nu dupa?
De gandit: Compilatorul citeste fisierul o singura data, de sus in jos. De ce crezi ca regula este "functia trebuie sa existe inainte de apel", in loc sa lase compilatorul sa caute functia oriunde in fisier, inainte sau dupa?
Deschidere: Cand scrii cout sau cin, de fapt apelezi functii scrise de altcineva, ascunse in biblioteca standard a C++. Acelasi principiu - scrie o data, apeleaza de oricate ori - sta la baza oricarui program mare: un joc video are mii de functii, fiecare facand un singur lucru (una deseneaza, alta calculeaza, alta reda sunetul).