Sunteți pe pagina 1din 9

5.

Introducere în programarea orientată pe obiecte

Toate limbajele de programare furnizează abstractizări. Limbajul de asamblare este o uşoară


abstractizare a calculatorului. Alte limbaje, multe denumite “imperative”, cum ar fi: Fortran, Basic
şi C, sunt abstractizări ale limbajului de asamblare. Ele sunt îmbunătăţiri importante peste limbajul
de asamblare, dar abstractizarea lor de bază necesită, încă, ca utilizatorul (programatorul) să
gândească, mai degrabă, în termenii structurii calculatorului, decât în termenii structurii problemei
de rezolvat. El trebuie să stabilească o asociere între modelul maşinii (“spaţiul soluţiei”) şi modelul
problemei (“spaţiul problemei”).
Efortul de a realiza această suprapunere va avea ca rezultat programe dificil de scris şi de
întreţinut, iar ca efect al acestei metode s-a creat o întreagă industrie de “metode de programare”.
Limbajele au fost create pentru programarea bazată pe restricţii şi pentru programare
exclusiv prin manipulare de simboluri grafice. Ele sunt o soluţie bună pentru o clasă particulară de
probleme, pentru care au fost proiectate să le rezolve, dar când se depăşeşte acest domeniu ele nu
mai pot fi utilizate.
Metoda orientată obiect furnizează instrumente pentru programator pentru a reprezenta
elemente în spaţiul problemei. Această reprezentare este destul de generală astfel că programatorul
nu este constrâns la vreun tip particular de problemă. Ne referim la elementele din spaţiul problemei
şi reprezentările lor în spaţiul soluţiei ca “obiecte”.
Idea este că programul este capabil să se adapteze el însăşi la jargonul problemei prin
adăugarea de noi tipuri de obiecte, astfel că la citirea codului care descrie soluţia se citesc cuvinte
care explică, de asemenea, problema. Aceasta este o abstractizare mult mai flexibilă şi mai
puternică a limbajului. Astfel programarea orientată obiect permite descrierea problemei, mai
degrabă, în termenii problemei decât în termenii specifici calculatorului: fiecare obiect arată, chiar
dacă puţin, ca un mic calculator; el are o stare şi are operaţii pe care i le poţi cere să le execute.
Alan Kay a pus în evidenţă cinci caracteristici de bază pentru Smalltalk, primul limbaj
orientat pe obiecte, de succes, şi unul dintre limbajele pe care se bazează C++. Aceste caracteristici
reprezintă o abordare pură pentru programarea orientată pe obiecte:
1. Orice este un obiect. Un obiect trebuie văzut ca o variabilă mai deosebită; ea
memorează date, dar se pot “face cereri” către acest obiect, cerând să realizeze operaţii
pe el însăşi. Teoretic, poţi lua orice componentă conceptuală din problema de rezolvat
(animale, clădiri, servicii etc.) şi să o reprezinţi ca un obiect în cadrul problemei.
2. Un program este un ansamblu de obiecte, fiecare spunându-i celuilalt ce să facă
prin transmiterea de mesaje. Pentru a lansa o cerere (solicitare) către un obiect se
“transmite un mesaj” la acel obiect. Mai adecvat este să vă gândiţi la un mesaj ca la o
cerere de apel de funcţie care aparţine unui anumit obiect.
3. Fiecare obiect are zona sa de memorie proprie alcătuită din alte obiecte. Cu alte
cuvinte, se poate crea un nou tip de obiect făcând un pachet ce conţine obiecte existente.
Astfel se poate construi complexitate într-un program în timp ce ea se ascunde în spatele
simplităţii obiectelor.
4. Fiecare obiect are un tip. Fiecare obiect este o “instanţă” a unei clase, unde “clasă”
este un sinonim cu “tip”. Caracteristica distinctivă cea mai importantă a unei clase este
“ce mesaje pot fi transmise la ea?”.
5. Toate obiectele unui anumit tip pot primi aceleaşi mesaje. Aceasta este o
declaraţie foarte importantă. Deoarece un obiect este de tipul “cerc” este, de asemenea,
un obiect de tipul “figură”, un cerc, este garantat, că va primi mesaje “formă”. Aceasta
înseamnă că se poate scrie cod despre figuri şi, în mod automat, va manipula orice ce se
potriveşte cu descrierea unei “figuri”. Această posibilitate de înlocuire (substituţie) este
una dintre cele mai puternice concepte în programarea orientată obiect.

1
5.1. Interfaţa unui obiect

Idea că toate obiectele, chiar dacă sunt mici, sunt de asemenea parte a unei clase de obiecte
care au caracteristici şi comportament comun a fost utilizată, direct, în primul limbaj de programare
orientat obiect, Simula-67, împreună cu cuvântul cheie clasă, ce introduce un nou tip în program.
Simula a fost creat pentru dezvoltarea simulărilor pentru clasica “problemă a casierului de bancă”,
în care sunt implicaţi casieri, clienţi, conturi, tranzacţii, unităţi monetare, adică o mulţime de
“obiecte”.
Crearea de tipuri de date abstracte (clase) este un concept fundamental în programarea
orientată obiect. Tipurile de date abstracte funcţionează aproape exact ca tipurile construite: se pot
crea variabile de un tip (denumite obiecte sau instanţe în limbajul orientat obiect) şi se manipulează
acele variabile (denumită transmiterea de mesaje sau cereri; se transmite mesajul şi obiectul
determină ce să facă cu el). Membrii (elementele) fiecărei clase partajează aceleaşi funcţiuni
(fiecare cont are o balanţă, fiecare casier poate accepta un depozit). În acelaşi timp, fiecare membru
are propria sa stare (fiecare cont are o balanţă diferită, fiecare casier are un nume). Astfel, casierii,
clienţii, conturile, tranzacţiile etc. pot fi reprezentate cu o entitate unică în program. Această entitate
este obiectul, şi fiecare obiect aparţine unei anumite clase care-i defineşte proprietăţile şi
comportamentul.
De fapt, ceea ce se realizează în programarea orientată obiect este crearea de noi tipuri de
date, denumite “clase”. Tehnicile programării orientate obiect pot uşor reduce un set larg de
probleme la o soluţie simplă.
Odată o clasă stabilită se pot face oricâte obiecte din acea clasă, şi apoi pot fi manipulate
acele obiecte ca şi cum ar fi elemente ce există în problema de rezolvat. Problema programării
orientată obiect este de a crea o asociere unu la unu între elementele din spaţiul problemei şi obiecte
din spaţiul soluţiilor.
Pentru a face ca un obiect să realizeze un lucru util, trebuie făcută o cerere către acel obiect.
Cererile ce se pot face pentru un obiect sunt definite de interfaţa sa, iar tipul este ce tip are funcţia
asociată cu fiecare cerere posibilă, iar când se face o anumită cerere către un obiect, acea funcţie
este apelată. Un exemplu simplu poate fi reprezentarea luminii unui bec:

Lumina bec;
Nume
Lumina
tip:
bec.aprins();

+ aprins()
+ stins()
+ mai_strălucitor()
Interfaţa:
+ mai_întunecat()

Interfaţa stabileşte ce acţiuni (cereri) se pot face pentru un anumit obiect. Totuşi undeva
trebuie să fie şi cod pentru a satisface cererea. Acesta, alături de datele ascunse constituie
implementarea. Un tip are o funcţie asociată cu fiecare cerere posibilă, şi atunci când se solicită o
anumită acţiune către un obiect, acea funcţie este apelată. Acest proces este, de obicei, rezumat
spunând că se “trimite un mesaj” (sau se face o cerere) la un obiect, şi că obiectul realizează ceea ce
trebuie cu acel mesaj (execută codul).
În acest exemplu tipul / clasa este Lumina, numele particular pentru obiectul Lumina este
bec, iar cererile ce pot fi făcute pentru un obiect Lumina sunt: aprins, stins, mai strălucitor, mai
întunecat. Prin declaraţia bec se creează un obiect Lumina. Pentru a trimite un mesaj către obiect se
pune numele obiectului şi se conectează cu cererea /mesajul printr-un punct. Diagrama anterioară
este conformă formatului UML (Unified Modeling Language), în care fiecare clasă este
2
reprezentată de o casetă (bloc), cu numele tipului în partea superioară, orice date membre ce trebuie
descrise în partea din mijloc a casetei, iar funcţiile membre (funcţii ce aparţin acestui obiect, care
recepţionează orice mesaj ce se transmite la obiect) în partea de jos. Semnul “+” în faţa funcţiilor
membre indică faptul că acestea sunt publice.

5.2. Ascunderea implementării

Este util să separăm câmpul de lucru în “creatori de clasă” (aceia care creează noi tipuri de
date) şi “programatori client” (adică, clienţii claselor, care utilizează tipurile de date în aplicaţiile
lor). Scopul programatorului client este de a colecta o casetă (bară) de instrumente plină de clase
pentru a le utiliza în dezvoltări rapide de aplicaţii.
Scopul creatorului de clase este de a construi o clasă care expune numai ce este necesar
programatorului client şi ţine ascuns tot restul. De ce ? Deoarece dacă este ascuns, programatorul
client nu îl poate utiliza, ceea ce înseamnă că creatorul de clase poate modifica porţiunea ascunsă
cum vrea fără să aibă grijă de impactul asupra altcuiva. Porţiunea ascunsă reprezintă, de obicei,
conţinutul unui obiect ce poate fi uşor corupt de un programator client neglijent sau neinformat,
astfel că ascunderea implementării reduce erorile programului.
Dacă toţi membrii unei clase sunt disponibili pentru oricine, atunci programatorul client
poate să facă orice cu acea clasă şi nici nu este un mod de a forţa vreo regulă. Astfel, primul motiv
pentru controlul accesului este de a ţine departe programatorul client de porţiunile pe care nu
trebuie să le atingă, părţi care sunt necesare pentru mecanismele interne ale tipului de date, dar nu
partea de interfaţă de care utilizatorii au nevoie pentru a rezolva problemele lor. Acesta este, de fapt,
un serviciu pentru utilizatori, deoarece ei pot vedea uşor ce este important pentru ei şi ce pot ignora.
Al doilea motiv pentru controlul accesului este de a permite proiectanţilor de biblioteci să
modifice modul de lucru al clasei fără a avea grijă de cum va fi afectat programatorul client. De
exemplu, poţi implementa o anumită clasă într-un mod simplu, uşor de dezvoltat, şi apoi ulterior se
descoperă că este nevoie să fie rescrisă pentru a o face mai rapidă. Dacă interfaţa şi implementarea
sunt clar separate, poţi simplu realiza aceasta şi este necesară doar o reeditare a legăturilor de către
utilizator.
C++ utilizează trei cuvinte cheie pentru a stabili limitele într-o clasă: public, private,
protected. Aceşti specificatori de acces determină cine poate utiliza definiţiile ce le urmează.
public , înseamnă că definiţiile ce urmează după ea sunt disponibile pentru oricine.
private , nimeni nu poate accesa definiţiile, cu excepţia creatorului tipului, în cadrul
membrilor funcţiilor de acel tip. private este o barieră între creator şi programatorul
client. Dacă se încearcă accesul la un membru private, se va genera o eroare la
compilare.
protected , acţionează ca private, cu excepţia că o clasă moştenitoare are acces la membrii
protected, dar nu la membrii private (moştenirea va fi prezentată în continuare).

5.3. Refolosirea implementării (a codului)

Odată o clasă creată şi testată, ea ar trebui să reprezinte o unitate de cod utilă. Reutilizarea
codului este unul dintre cele mai mari avantaje pe care le furnizează limbajele de programare
orientată obiect.
Cel mai simplu mod de reutilizare a unei clase este utilizarea directă, pur şi simplu, a unui
obiect al clasei, dar se poate, de asemenea, să se plaseze un obiect al acelei clase într-o nouă clasă.
Acesta este denumită “crearea unui obiect membru”. Noua clasă poate fi alcătuită din orice număr şi
tip de alte obiecte, oricâte sunt necesare pentru a realiza funcţionalitatea dorită în noua clasă. Acest
concept este denumit “compoziţie” (sau, mai general, agregare), deoarece se compune o nouă clasă
3
din clasele existente. Uneori compoziţia este referită (denumită) ca o relaţie “are-un”, ca de
exemplu în “o maşină are un motor”.
Compoziţia aduce o mare flexibilitate. Obiectele membre ale noii clase sunt, de obicei,
private, făcându-le inaccesibile programatorilor clienţi ce utilizează clasa. Aceasta vă permite să
modificaţi acei membrii fără a perturba codul client existent. De asemenea, puteţi modifica
obiectele membre la momentul execuţiei, prin modificarea dinamică a comportării programului
dumneavoastră. Moştenirea, care va fi descrisă în continuare, nu are această flexibilitate cât timp
compilatorul trebuie să instaleze restricţiile de timp de compilare pe clasele create cu moştenire.

5.4. Moştenirea: reutilizarea interfeţei

Un obiect permite să asamblăm împreună date şi funcţionalitate prin concept, astfel că se


poate reprezenta o idee adecvată de spaţiu mai degrabă decât să se forţeze utilizarea limbajului
maşinii de bază. Aceste concepte sunt exprimate ca unităţi fundamentale în limbajul de programare
prin utilizarea cuvântului cheie clasă.
Un alt concept al programării orientată obiect este acela că se poate lua o clasă existentă,
clona şi să se facă adăugări şi modificări acestei clase. Aceasta este efectiv ceea ce se obţine cu
moştenirea, cu excepţia că dacă clasa originală (denumită şi clasă bază sau clasă super sau clasă
părinte) este modificată, “clona” modificată (denumită clasă derivată sau clasă moştenită sau clasă
copil) reflectă, de asemenea, aceste modificări. Pot fi mai multe clase derivate.
Un tip face mai mult decât să descrie restricţiile pe un set de obiecte; el are, de asemenea, o
relaţie cu alte tipuri. Două tipuri pot avea caracteristici şi comportament comun, dar un tip poate
conţine mai multe caracteristici decât altul şi poate, de asemenea, să interpreteze mai multe mesaje
sau să le interpreteze diferit. Moştenirea exprimă această similaritate între tipuri cu conceptul
tipurilor de bază şi tipuri derivate. Un tip de bază conţine toate caracteristicile şi comportamentul ce
sunt partajate între tipurile derivate din el. Se creează un tip de bază pentru a reprezenta nucleul
pentru obiectele din sistem. Pornind de la tipul de bază se derivează alte tipuri pentru a exprima
moduri diferite pe care nucleul le poate realiza.
De exemplu, problema clasică a formelor (figurilor), care poate fi utilă în proiectarea
asistată de calculator sau în simulări de jocuri. Tipul da bază este “formă” şi fiecare formă are o
dimensiune, culoare, poziţie etc. Fiecare formă poate fi desenată, ştearsă, mutată, colorată etc. De
aici sunt derivate tipuri specifice de figuri: cerc, pătrat, triunghi etc., fiecare având caracteristici şi
comportamente suplimentare.
Ele au comportament diferit, de exemplu, modul de calcul al unei figuri. Tipul ierarhic
include atât similarităţile cât şi diferenţele dintre figuri.

forma

+deseneaza()
+sterge()
+muta()
+culoare()
+coloreaza()

Cerc Patrat Triunghi

4
Când se moşteneşte de la un tip existent, se va crea un nou tip. Acest nou tip conţine nu
numai toţi membrii tipului existent (deşi cei privaţi sunt ascunşi şi deci inaccesibili), dar mult mai
important, el multiplică interfaţa clasei de bază. Adică, mesajele ce se pot trimite la obiectele clasei
de bază pot fi trimise şi clasei derivate. Tipul clasei derivate este acelaşi cu cel al clasei de bază; de
asemenea şi comportamentul este similar.
Există două moduri de a diferenţia noua clasă derivată faţă de clasa de bază, originală.
Primul constă în adăugarea de noi funcţii clasei derivate, care nu fac parte din interfaţa clasei de
bază. O soluţie este simpla utilizare a moştenirii. Totuşi s-ar putea dori ca aceste funcţii adiţionale
să fie necesare şi clasei de bază. Acest proces de descoperire şi iteraţie a proiectării se întâmplă
frecvent în programarea orientată obiect.

forma

+deseneaza()
+sterge()
+muta()
+culoare()
+coloreaza()

Cerc Patrat Triunghi

+Orientare_Verticala()
+Orientare_Orizontala()

Deşi moştenirea poate, uneori, implica şi adăugarea de noi funcţii la interfaţă, nu este
neapărat adevărat.
Cel de-al doilea mod de a diferenţia noua clasă este de a modifica comportarea unei funcţii
existente în clasa de bază. Aceasta este denumită ca fiind redefinirea funcţiei (overridding).

forma

+deseneaza()
+sterge()
+muta()
+culoare()
+coloreaza()

Cerc Patrat Triunghi

+desen() +desen() +Orientare_Verticala()


+sterge() +sterge() +Orientare_Orizontala()

5
Pentru a redefini o funcţie se creează o nouă definiţie pentru funcţie în clasa derivată. Se
spune că “se utilizează aceeaşi funcţie de interfaţă, dar vrem să facă ceva diferit pentru noul tip”.

Comparaţie între relaţiile “este un” şi “este ca (asemănător cu) un”


Moştenirea ar trebui să modifice (overridde) numai funcţiile clasei de bază (şi să nu adauge
noi funcţii membre, care nu sunt în clasa de bază)? Asta ar însemna că tipul derivat este exact
acelaşi tip cu clasa de bază deoarece el are exact aceeaşi interfaţă. Aceasta poate fi văzută ca o pură
substituire, şi este adesea referită ca principiul substituţiei. Într-un sens, acesta este modul ideal de a
trata moştenirea. Adesea ne referim la relaţia dintre clasa de bază şi cele derivate, în acest caz, ca o
relaţie “este un”, deoarece se poate spune “un cerc este o figură”.
Sunt situaţii, însă, în care se adaugă noi elemente de interfaţă la un tip derivat, extinzând
astfel interfaţa şi creând un nou tip. Noul tip poate încă fi substituit pentru tipul de bază, dar
substituţia nu este perfectă deoarece noile funcţii nu sunt accesibile de la tipul de bază. Aceasta
poate fi descrisă ca o relaţie “este asemenea ca”.
De exemplu, dacă o instalaţie de aer condiţionat (care numai răceşte) este înlocuită cu un
“sistem de control al temperaturii” care poate şi răci şi încălzi, în acest caz interfaţa noului obiect
este extinsă cu noi funcţii (încălzire) faţă de cel anterior, iar dacă sistemul de control al casei este
proiectat doar pentru răcire, el va fi restructurat doar la comunicarea cu partea de răcire a noului
obiect.

5.5. Obiecte interschimbabile. Polimorfism.

Când avem de-a face cu ierarhii de tipuri, adesea se doreşte să se trateze un obiect nu ca un
anumit tip ce este el ci ca tipul său de bază. Aceasta permite să se scrie cod care nu depinde de
tipurile respective. În exemplul cu figuri, funcţiile manipulează forme generice fără a ţine cont dacă
ele sunt cercuri, pătrate, triunghiuri etc. Toate formele pot fi desenate, şterse şi mutate, astfel că
aceste funcţii trimit simplu un mesaj la un obiect figură; ele nu au grijă de modul în care obiectul
face faţă mesajului.
Astfel de cod nu este afectat de adăugarea de tipuri noi, iar adăugarea de tipuri noi este
modul cel mai obişnuit de a extinde un program orientat obiect, de a trata noi situaţii.
De exemplu, se poate deriva un nou subtip de figură, denumită pentagon, fără modificarea
funcţiilor ce tratează forme generice. Această facilitate de a extinde uşor un program prin derivarea
de noi subtipuri este importantă deoarece îmbunătăţeşte proiectarea şi reduce costul de întreţinere
software. Există totuşi o problemă cu tratarea obiectelor de tip derivat ca tipurile lor de bază,
generice (cercuri ca figuri, bicicletele ca vehicule, cormoranii ca păsări etc.). Dacă o funcţie spune
unei forme generice să se deseneze ea însăşi, sau un vehicul generic să fie condus, sau unei păsări
generice să zboare, compilatorul nu poate şti precis, la momentul compilării, ce porţiune de cod va
fi executată. Adică, atunci când mesajul este trimis, programatorul nu vrea să ştie ce bucată de cod
va fi executată; funcţia de desenare poate fi aplicată, în mod egal, pentru un cerc, pătrat sau triunghi
şi obiectul va executa codul adecvat depinzând de tipul său specific.
Dacă nu trebuie să ştii ce secvenţă de cod va fi executată, atunci când se adaugă un nou
subtip, codul pe care-l execută poate fi diferit fără modificări pentru apelul funcţiei. De aceea
compilatorul nu poate şti precis ce porţiune de cod este executată, şi deci ce va face.
De exemplu, în următoarea diagramă obiectul “Controler pasăre” operează cu obiecte de tip
“Pasăre” generice, şi deci nu ştie exact ce tip este. Aceasta este convenabil din perspectiva
“Controler pasăre”, deoarece nu trebuie scris cod special pentru a determina tipul exact de “Pasăre”
cu care lucrează el, sau comportamentul “Pasăre”. Atunci, cum se întâmplă aceasta, când se
apelează zboară(), care ignoră tipul specific de “Pasăre”, să se realizeze comportamentul
corespunzător?

6
7
Pinguin
Controler
Pasăre
Gâscă Pasăre Ce se întâmplă cînd

se apelează zboară()

+zboară()
+zboară_oricum()

Răspunsul este prima cotitură în programarea orientată obiect: compilatorul nu face un apel
de funcţie în sensul tradiţional. Apelul de funcţie generat de un compilator ce nu este orientat obiect
determină ceea ce este denumită “editarea timpurie de legături” (early binding), un termen de care
poate nu aţi auzit, şi care înseamnă că, de fapt, compilatorul generează un apel la un anumit nume
de funcţie şi editorul de legături rezolvă acest apel către adresa absolută de cod de executat. În
programarea orientată obiect, programul nu poate determina adresa codului până la momentul
execuţiei, astfel că altă schemă este necesară când un mesaj este trimis la un obiect generic. Pentru a
rezolva această problemă limbajele orientate obiect utilizează conceptul de “editare întârziată de
legături”. Când se trimite un mesaj la un obiect, codul ce va fi apelat nu este determinat până la
momentul execuţiei. Compilatorul trebuie să se asigure că funcţia există şi el realizează verificarea
argumentelor şi valorii returnate, dar el nu ştie codul exact de executat.
Pentru a realiza legarea întârziată, compilatorul inserează un cod special în locul apelului
absolut. Acest cod calculează adresa funcţiei utilizând informaţii memorate în obiectul însăşi.
Astfel, fiecare obiect se poate comporta diferit, în concordanţă cu conţinutul acelui cod special.
Când se transmite un mesaj la un obiect, obiectul respectiv va realiza efectiv ce să facă cu acel
mesaj.
Se stabileşte că se doreşte o funcţie care să aibă flexibilitatea unei proprietăţi de legare
întârziată prin utilizarea cuvântului cheie virtual.
Funcţiile virtuale permit exprimarea diferenţelor în comportarea claselor în cadrul aceleiaşi
familii. Acele diferenţe sunt cele ce determină comportare polimorfică. Să demonstrăm
polimorfismul în cazul exemplului cu figuri: vrem să scriem o singură secvenţă de cod care ignoră
detaliile specifice ale tipului şi comunică doar cu clasa de bază. Acest cod este decuplat de
informaţia specifică tipului, şi astfel este mai simplu de scris şi mai uşor de înţeles. Astfel dacă un
nou tip, un hexagon, de exemplu, este adăugat prin moştenire, codul pe care-l scriem va funcţiona
bine pentru noul tip de figură, aşa cum o făcea şi pentru tipurile existente. Astfel programul este
extensibil.
Dacă scriem o funcţie C++, de forma:
void Operatii (Forma& f)
{
f.sterge();
// . . . . .
f.deseneaza();
}

Această funcţie este valabilă pentru orice Formă, deci este independentă de tipul specific de
obiect ce se desenează sau şterge; simbolul & înseamnă că se ia adresa obiectului ce este transmis
funcţiei Operatii(). Această funcţie va fi utilizată în altă parte a programului astfel:
8
cerc c;
triunghi t;
linie l;
Operatii (c);
Operatii (t);
Operatii (l);

Aceste apeluri ale funcţiei Operatii() vor lucra corect indiferent de tipul exact al obiectului.
De exemplu prima dintre funcţii, Operatii(c), primeşte ca parametru un cerc, în timp ce se aştepta o
Formă. Deoarece cerc este o Formă el poate fi tratat astfel de Operatii(). Deci orice mesaj ce poate
fi trimis la o Formă poate fi acceptat de cerc. Acest proces de a trata un tip derivat ca şi cum ar fi
tipul de bază upcasting. Numele cast este utilizat în sensul de modelare într-o formă şi up vine de la
modul în care este tipic aranjată diagrama de moştenire, cu tipul de bază la vârf şi clasele derivate
distribuite în partea de jos.

Forma
upcasting

Cerc Patrat Triunghi

Apelul şi execuţia codului funcţiei Operatii() realizează operaţia dorită. Apelând


deseneaza() pentru cerc se va executa cod diferit decât codul executat în cazul în care se apelează
deseneaza() pentru un pătrat sau linie, dar când mesajul desenează() este trimis la o Formă
anonimă se produce efectul dorit asupra tipului actual de Formă. Aceasta se întâmplă datorită
polimorfismului. Compilatorul şi sistemul pe care se execută manipulează detaliile; tot ce trebuie
ştiut este că aceasta se întâmplă şi mult mai important cum se proiectează. Dacă un membru al
funcţiei este virtual, atunci când se trimite un mesaj la un obiect, obiectul va face lucrul dorit, chiar
când este implicat upcasting.

S-ar putea să vă placă și