Documente Academic
Documente Profesional
Documente Cultură
net
Executarea unui program in mod simplu se face cu combinatia de taste CTRL si F5
COSTRUCTIA PROGRAMELOR IN Visual C++.Net
1)Intru in Visual studio.net
2)File/new project
3)Visual C++ si aleg Window Command Apas PE
4)dau numele proiectului OBJECT
5) BROWSER
APAS PE
ACEASTA
OPTIUNE
1
Il rulez
apasand
dublu clic
2
APLICATII
PROGRAMAREA PE OBIECTE
ASPECTE INTRODUCTIVE
Notiunea de structura
Abordarea orientată pe obiecte (AOO)
căciula studentului
o fereastră deschisă pe un calculator
un triunghi desenat pe hîrtie
Exemple de clase :
căciulă
fereastră
triunghi
Exemple: a muta
o căciulă
o fereastră
un triunghi
3
Exemple: se pot defini clasele Triunghi_Isoscel şi Triunghi_Echilateral ca
şi clase derivate din clasa Triunghi şi care moştenesc din această clasă poziţia pe
hîrtie, respectiv operaţia a muta.
4
Partajarea oferă posibilitatea reutilizării proiectării, în proiecte ulterioare.
Reutilizarea însă trebuie avută în vedere de la începutul proiectării, chiar
dacă implică un efort ceva mai mare. Beneficiile însă se recuperează din
plin, în timp.
C++ a crescut rolul structurii standard din C la acela al unui mod mai subtil, de
specificare a unei clase. De fapt, diferenţa imediat vizibilă dintre o structură şi o clasă este
aceea că implicit toţi membrii unei structuri sînt publici pe cînd cei ai unei clase sînt implicit
privaţi. În celelalte privinţe, structurile şi clasele sînt similare. Aceasta înseamnă că în C++ o
structură defineşte de asemenea un tip special de clasă
Deoarece o structură (declarată cu cuvîntul cheie struct) în C++ defineşte un tip de clasă,
obiectele de acel tip pot fi declarate folosind doar numele generic al structurii, fără a mai folosi
cuvîntul cheie struct, aşa cum trebuie făcut în C (dar nu este o eroare dacă se precedă declaraţia
cu struct).
//Sa se defineasca o structura
#include "stdafx.h"
#include <iostream>
using namespace std;
#include <string.h>
// declararea structurii
struct sir_exemplu{
void face_sir(char *); // implicit va fi sectiune public
void arata_sir();
private: // iar sectiunea privata trebuie declarata explicit
char sir[80];
};
void sir_exemplu::arata_sir()
{
cout << sir << "\n";
}
Notiunea de uniune
Uniuni şi clase
5
mai importantă fiind aceea că toate elementele de date împart aceeaşi locaţie de memorie. Ca şi
structura, membrii unei union sînt implicit publici.
La fel ca şi o structură, o declaraţie a unei union în C++ defineşte un tip special de clasă, deci
se păstrează principiul încapsulării. Iată acum cîteva restricţii asupra folosirii union în C++ :
Uniuni anonime
În C++ există un tip special de union numit uniune anonimă. Aceasta nu conţine un nume de
tip şi nici o variabilă nu poate fi declarată ca fiind de acel tip de uniune. În schimb, ea comunică
compilatorului că variabilele membre ale uniunii vor împărţi aceeaşi locaţie. Dar variabilele în
sine pot if utilizate direct, fără sintaxa cu operator punct.
Mai mult, chiar dacă ele sînt definite într-o declaraţie union, ele sînt la acelaşi nivel al
domeniului de existenţă ca şi oricare alte variabile locale din acelaşi bloc. Membrii unei uniuni
anonime nu pot de altfel să aibă acelaşi nume cu al nici unui alt identificator cunoscut în
domeniul curent. Aceasta înseamnă că numele membrilor unei uniuni anonime nu trebuie să
intre în conflict cu alţi identificatori cunoscuţi din domeniul uniunii. Toate restricţiile pentru o
union se aplică şi celor anonime, cu următoarele completări :
elementele care pot fi conţinute într-o uniune anonimă trebuie să fie de tip date (nu
sînt permise funcţii membre)
uniunile anonime nu pot conţine elemente de tip private sau protected
uniunile globale anonime trebuie să fie specificate ca fiind de tip static.
#include "stdafx.h"
#include <iostream>
using namespace std;
#include <string.h>
main()
{
// urmeaza definirea uniunii anonime
union {
long l;
double d;
char s[10];
};
// accesul la membrii uniunii anonime este direct
l=150000;
cout << l << endl;
d=123.456;
cout << d <<endl;
strcpy(s, "abcdefghij");
cout << s << endl;
return 0;
6
}
//sa se creeze o uniune in care sa se puna in evidenta urmatoarele:
//• nu poate mosteni nici un alt tip de clasa
//• nu poate avea functii virtuale membre (vom vedea mai departe ce
înseamna functii virtuale)
//• nu poate avea ca membre variabile de tip static
//• nu poate avea ca membru nici un obiect care are supraîncarcat
operatorul =
//• nu poate avea ca membri obiecte care contin functii constructor
sau destructor
#include "stdafx.h"
#include <iostream>
using namespace std;
// declararea union
union schimbare_octeti {
void schimba();
void pune_octeti(unsigned );
void arata_cuvint();
unsigned u;
unsigned char c[2];
};
main()
{
schimbare_octeti sch;
sch.pune_octeti(34567);
sch.schimba();
sch.arata_cuvint();
return 0;
}
Clasele
Clasele sînt create utilizîndu-se cuvîntul cheie class. O declarare a unei clase defineşte
un nou tip care uneşte cod şi date. Acest nou tip este apoi folosit pentru a declara obiecte din
acea clasă. De aceea, o clasă este o abstractizare logică, dar un obiect are o existenţă fizică.
Altfel spus, un obiect este un exemplar (o instanţă) al unei clase.
O declarare de classă este similară sintactic cu cea a unei structuri. În capitolul
precedent a fost prezentată (simplificat) această declarare. Iată forma generală completă
a unei declaraţii de clasă care nu este un descendent al vreunei alte clase :
7
class nume_clasa {
date si functii particulare (fara specificator de acces, implicit)
specificator_de_acces:
date si functii
specificator_de_acces:
date si functii
...
specificator_de_acces:
date si functii
} lista de obiecte;
class nume_clasa {
date si functii private
public:
8
date si functii publice
} lista de obiecte;
Functii prietene
Este posibil să permitem unei funcţii care nu este membru să aibă acces la membrii particulari
ai clasei folosind cuvîntul cheie friend (prieten). O funcţie friend are acces la membrii private
şi protected ai clasei căreia îi este prietenă. Pentru a declara o funcţie friend, trebuie inclus
prototipul ei în acea clasă, precedat de cuvîntul cheie friend, există condiţii cînd funcţiile
prietene îşi dovedesc din plin utilitatea :
la supraîncărcarea anumitor tipuri de operatori (se va vedea mai încolo)
la crearea anumitor tipuri de operatori de intrare/ieşire
în unele cazuri, două sau mai multe clase pot conţine membri care sînt corelaţi cu
alte secţiuni ale programului.
Pentru funcţiile friend se aplică următoarele restricţii :
Chiar şi clasele pot fi declarate friend una pentru alta. În această situaţie, clasa friend
are acces la numele private definite în cadrul celeilalte. Aceste nume pot cuprinde nume de
tipuri şi enumerări de date. Trebuie reţinut că o clasă friend are acces doar la numele definite în
interiorul celeilalte. Ea nu moşteneşte cealaltă clasă, deci membrii primei clase nu devin
membri ai clasei friend.
9
using namespace std;
class clasa_exemplu{
int a,b;
public:
friend int suma(clasa_exemplu ); // iata o functie
// prietena
void furniz_ab(int, int );
};
main(){
clasa_exemplu c;
c.furniz_ab(1,2);
cout << suma(c);
return 0;
}
// declarari de clase
class C2; // vezi mai jos
class C1 {
int stare; // valorile IN_USE daca este pe ecran,
// IDLE daca nu e
// …
public:
void setare_stare(int );
int idle(C2 ); // nu mai este friend ci pur si
// simplu membru al clasei C1 de aceea nu mai
// trebuie C1 in lista de parametri
};
class C2{
int stare; // IN_USE daca e pe ecran, IDLE daca nu e
// …
public:
void setare_stare(int );
friend int C1::idle(C2 ); //diferenta e ca apare C1::
// (deci se marcheaza apartenenta la C1)
};
10
void C2::setare_stare(int cond)
{
stare=cond;
}
// programul principal
main()
{
C1 x;
C2 y;
x.setare_stare(IDLE);
y.setare_stare(IDLE); // initial ambele sint IDLE
sir.face_sir(""); // initializare
sir.face_sir("Acesta"); // construim
sir.face_sir("este"); // un sir mai lung in etape
sir.face_sir("exemplu.");
sir.arata_sir(); // si il afisam
return 0;
}
11
public:
void pune_nume(char *);
void scoate_nume(char *);
private: // iar sectiune private
double salar;
public: // iar sectiune public
void pune_salar(double );
double furnizeaza_salar();
};
gheorghe.pune_nume("Gheorghe Popescu");
gheorghe.pune_salar(860000); // i se adauga salariul pe
// luna curenta
gheorghe.scoate_nume(nume); // in nume va fi transferat
// numele
cout << nume << " are atitia lei ";
cout << gheorghe.furnizeaza_salar() << "pe luna.\n";
return 0;
}
//accesul la date publice se face direct in orice sectiune a
programului
#include "stdafx.h"
#include <iostream>
using namespace std;
class clasa_exemplu{
public:
int i,j,k; //acestea vor fi accesibile intregului program
};
main()
{
clasa_exemplu a,b; // se definesc doua obiecte de tipul
// clasa_exemplu
a.i=100;
a.j=4; // se lucreaza la fel ca si cu oricare
a.k=a.i*a.j; // variabila
12
b.i=a.j;
b.k=11; // a.k si b.k sint evident diferite
cout << a.k << " " <<b.k;
return 0;
}
Functii inline
O importantă caracteristică în C++, posibilitatea de a utiliza funcţii inline, eset
adeseori asociată cu folosirea claselor. În C++ pot fi create funcţii scurte care nu sînt apelate
efectiv ci codul respectivelor funcţii este inserat la fiecare folosire a acestora. Aceasta seamănă
cu utilizarea macro-urilor. Pentru a determina această modalitate de lucru, definirea funcţiei
respective trebuie precedată de cuvîntul-cheie inline.
Funcţiile inline sînt utilizate din motive de eficienţă. Astfel, pentru clase este adeseori necesar
să se solicite executarea frecventă a funcţiilor de interfaţă, care asigură accesul la datele private.
Prin utilizarea funcţiilor inline, eficienţa creşte prin aceea că astfel este înlocuit mecanismul
relativ complex al apelului şi transmiterii parametrilor (prin folosirea stivei şi salvarea
regiştrilor), prin folosirea directă a codului executabil a funcţiilor, fără să se mai folosească acel
mecanism. Bineînţeles prin acest procedeu codul executabil creşte în dimensiuni, de aceea se
recomandă utilizarea funcţiilor inline doar pentru coduri foarte scurte (puţine linii-sursă). Mai
mult decît atît, se recomandă alegerea acelor funcţii care au un impact puternic asupra
îmbunătăţirii performanţelor programului.
Asemenea specificatorului register, inline este pentru compilator o solicitare, nu o
comandă. Acesta poate chiar să o ignore. De asemenea, unele compilatoare nu pot insera inline
orice funcţie. De exemplu nu poate fi inline o funcţie recursivă (uşor de înţeles de ce).
Funcţiile inline pot fi membre ale unei clase.
Este posibilă definirea funcţiilor inline şi direct într-o declarare de clasă. Cînd o funcţie este
definită într-o declarare a unei clase, ea este automat transformată într-o funcţie inline, dacă e
posibil (dacă permite compilatorul). Nu este necesară declararea cu cuvîntul cheie inline (dar
bineînţeles nu constituie o greşeală).
// Sa se foloseasca o functie inline(codul respectivelor funcţii este
inserat la fiecare folosire a acestora)
#include "stdafx.h"
#include <iostream>
using namespace std;
main()
{
cout << max(100,200);
cout << " " << max (300, 299);
return 0;
}
13
class ordine{
public:
int cine;
ordine(int );
~ordine();
} glob_ob1(10), glob_ob2(20); // doua obiecte globale
ordine::ordine(int valinit)
{
cout << "Initializare " << valinit << "\n";
cine=valinit;
}
ordine::~ordine()
{
cout << "Distrugere " << cine << "\n";
}
main()
{
ordine local_ob1(30); // obiect local
return 0;
}
#define IN_BIBLIO 1
#define IMPRUMUTAT 0
class carte{
char autor[40];
char titlu[40];
int stare;
public:
carte(char *, char *, int );
int furniz_stare() {return stare;}
void pozit_stare(int s) {stare=s;}
void arata();
};
// constructorul initializeaza autor, titlu, stare
// transmisi ca parametri
carte::carte(char *aut, char *tit, int s)
{
strcpy(autor, aut);
strcpy(titlu, tit);
stare=s;
}
void carte::arata()
{
cout << titlu << " de " << autor <<" este ";
14
if (stare== IN_BIBLIO) cout << "aici.\n";
else cout << "imprumutata.\n";
}
main()
{
carte carte1("Cartarescu","Orbitor",IMPRUMUTAT);
carte carte2("Dinescu", "Democratia naturii", IN_BIBLIO);
carte1.arata();
carte2.arata();
return 0;
}
Membrii de tip static ai claselor
Membrii de tip static ai claselor
Atît funcţiile membre cît şi datele membre ale unei clase pot fi declarate static. În
continuare, să vedem ce înseamnă aceasta pentru fiecare tip de membru.
O dată care este precedată de cuvîntul static va exista doar într-un singur exemplar (o
singură copie) şi va fi folosită de toate obiectele de acea clasă. Spre deosebire de variabilele
membre obişnuite, nu sînt create copii individuale ale variabilelor membre static, pentru fiecare
obiect. Nu are importanţă cîte obiecte de acea clasă sînt create, va exista doar o singură copie a
membrilor de tip static. Cînd este creat primul obiect de acel tip, toate variabilele de tip static
sînt automat iniţializate cu zero.
În cadrul unei clase, declararea unei variabile static nu alocă memorie pentru aceasta.
Din acest motiv, trebuie dată a definire globală pentru membrii de tip static, în afara clasei,
folosind specificatorul de domeniu, pentru a preciza clasa de apartenenţă. Doar astfel se asigură
existenţa fizică a variabilei, prin alocarea de memorie pentru aceasta (este şi normal, declararea
clasei nu este altceva decît definirea unei structuri abstracte, a unui model după care pot fi
create obiecte; din acest motiv, variabilele statice nu pot fi alocate prin simpla includere într-un
model abstract). O variabilă membră de tip static există înainte de a fi creat orice obiect din
acea clasă. Mai mult, dacă respectiva variabilă este public şi întrucît există înainte de crearea
unui obiect din clasa în a cărei declarare apare variabila ca membră, aceasta poate dobîndi
valoare (care nu va fi modificată de crearea vreunui obiect din acea clasă) şi poate fi utilizată în
domeniul său de valabilitate, oricînd. Trebuie reţinut modul de acces la variabilele statice,
atunci cînd sînt accesate independent de obiecte: prin folosirea numelui clasei, urmat de
operatorul de rezoluţie şi apoi numele vaiabilei statice.
Uzual, variabilele membre statice sînt folosite la controlul accesului la unele resurse
comune. Fiecare obiect va putea să controleze valoarea variabilei statice membre pentru a
verifica posibilitatea accesului, deoarece există un singur exemplar al acestei variabile, care
poate fi văzut de toate instanţele clasei şi care va juca rolul unui semafor.
Funcţii membre statice
Şi funcţiile membre pot fi declarate static. Există mai multe restricţii relativ la funcţiile
astfel declarate :
15
pot să aibă acces doar la alţi membri de tip static ai clasei (şi bineînţeles la funcţiile
şi datele globale);
nu pot avea un pointer de tip this (se va vedea mai departe ce înseamnă acesta);
nu pot coexista versiuni statice şi ne-statice ale aceleiaşi funcţii
De fapt, funcţiile membre de tip static au o arie de aplicatibilitate destul de limitată. O
utilizare potrivită a acestora este iniţializarea datelor private de tip static, înainte de
crearea vreunui obiect al clasei respective.
Operatorul de specificare a domeniului
//Cînd este creat primul obiect de acel tip, toate variabilele de tip
static sînt automat iniţializate cu zero.
//În cadrul unei clase, declararea unei variabile static nu
alocă memorie pentru aceasta. Din acest motiv, trebuie dată a
definire globală pentru membrii de tip static, în afara clasei,
folosind
//specificatorul de domeniu, pentru a preciza clasa de
apartenenţă.
#include "stdafx.h"
#using <mscorlib.dll>
#include <stdlib.h>
#include <iostream>
using namespace std;
class exemplu_static{
static int a; // aici e o variabila membra de tip static
int b; // aceasta nu e de tip static
public:
void seteaza(int i, int j) {a=i; b=j; }
void arata();
};
main()
{
exemplu_static ob1, ob2; // doua obiecte de tipul clasei
// exemplu_static
ob1.seteaza(1,2); // a va fi 1, b va fi 2
ob1.arata(); // sa vedem daca e asa
16
ob1.arata(); // dar vedem ca a s-a modificat si
// pentru ob1, firesc deoarece a este
// acelasi pentru ambele obiecte
return 0;
}
//Trebuie reţinut modul de acces la variabilele statice, atunci cînd
sînt accesate independent de obiecte: prin folosirea numelui clasei,
urmat de
//operatorul de rezoluţie şi apoi numele vaiabilei statice.
#include "stdafx.h"
#using <mscorlib.dll>
#include <stdlib.h>
#include <iostream>
using namespace std;
class comun{
public:
static int a; // static si public totodata
};
main()
{
// initializam variabila statica inainte de crearea
// vreunui obiect folosind operatorul ::
comun::a=789;
cout << "Valoarea initiala a lui a: " << comun::a <<"\n";
comun c1; // abia acum se creaza un obiect de tip comun
cout << "Valoarea lui a din c1: " << c1.a;
return 0;
}
//Exemplul următor ilustrează cum poate fi controlat accesul la o
astfel de resursă comună (care
//poate fi un fişier, un buffer partajat etc.):
#include "stdafx.h"
#using <mscorlib.dll>
#include <stdlib.h>
#include <iostream>
using namespace std;
class semafor{
static int resursa;
public:
int ocupa_resursa();
void elibereaza_resursa() {resursa=0; }
};
17
main()
{
semafor s1, s2; // doua obiecte de tip semafor
if(s1.ocupa_resursa())
cout << "Obiectul 1 a ocupat resursa.\n";
if(!s2.ocupa_resursa())
cout << "Obiectul 2 nu are acces la resursa.\n";
s1.elibereaza_resursa(); // eliberare resursa
if(s2.ocupa_resursa())
cout << "Obiectul 2 poate acum folosi resursa.\n";
return 0;
}
//Se observă că accesul la funcţia statică ocupa_resursa()
//este permis fie independent de vreun obiect, utilizînd numele
clasei şi operatorul de specificare
//a domeniului (operatorul de rezoluţie) fie în legătură
//cu un obiect (operatorul de apartenenţă cu punct).
#include "stdafx.h"
#using <mscorlib.dll>
#include <stdlib.h>
#include <iostream>
using namespace std;
class semafor{
static int resursa;
public:
static int ocupa_resursa();
void elibereaza_resursa() {resursa=0; }
};
main()
{
semafor s1, s2; // doua obiecte de tip semafor
// in plus fata de programul precedent, ocupa_resursa()
// poate fi apelat independent de orice obiect
if(semafor::ocupa_resursa())
cout << "Obiectul 1 a ocupat resursa.\n";
if(!semafor::ocupa_resursa())
cout << "Obiectul 2 nu are acces la resursa.\n";
s1.elibereaza_resursa(); // eliberare resursa
if(s2.ocupa_resursa()) // se poate folosi si apelul
// cu obiect
cout << "Obiectul 2 poate acum folosi resursa.\n";
return 0;
}
18
Clase imbricate, clase locale
Se poate defini o clasă în interiorul altei clase. Procedînd astfel, se crează clase
imbricate. Deoarece o declarare a unei clase defineşte de fapt un domeniu de delimitare, ("de
influenţă", de valabilitate, potrivit principiului încapsulării), o clasă imbricată este validă doar
în interiorul clasei ce o conţine. Clasele imbricate sînt rareori folosite, deoarece moştenirea
oferă suficientă flexibilitate şi putere pentru a acoperi necesităţile care ar fi acoperite de
folosirea claselor imbricate.
Cînd declarăm o clasă în definirea unei funcţii, respectiva clasă este cunoscută doar acelei
funcţii. Nu putem să facem referiri la ea în afara funcţiei.
Există mai multe restricţii care se aplică acestui gen de clase :
Obiectele pot fi pasate către funcţii exact ca oricare alt tip de variabilă (de altfel,
această posibilitate a fost folosită la un exemplu anterior, care folosea o funcţie friend pentru
controlul accesului la o resursă comună). Obiectele sînt pasate funcţiilor prin utilizarea
mecanismului standard de apelare prin valoare, adică prin copiere. Aceasta ar implica de fapt
crearea unui alt obiect. În aceste circumstanţe, se pune întrebarea dacă la crearea acestei copii
mai este apelat constructorul, respectiv, dacă această copie este distrusă apoi cu destructorul
clasei. Răspunsul la această întrebare este interesant şi uşor de justificat : constructorul nu este
apelat la realizarea copiei pentru pasarea către funcţie, deoarece astfel valorile care dau
atributele obiectului (deci valorile variabilelor membre) ar fi iniţializate, iar noi dorim să
transmitem spre funcţia apelantă chiar starea curentă a obiectului. În schimb destructorul este
executat la încheierea funcţiei, întrucît copia folosită nu mai e necesară
Cînd un obiect este returnat de o funcţie, este creat automat un obiect temporar, care conţine
valoarea returnată. Acesta este de fapt obiectul returnat. După ce valoarea a fost returnată, acest
obiect temporar este distrus. Această distrugere poate avea uneori efecte secundare neaşteptate.
Astfel, dacă obiectul care este returnat are un destructor care eliberează memorie alocată
dinamic, acea memorie va fi eliberată chiar dacă obiectul care primeşte valoarea returnată încă
o mai foloseşte. Apariţia acestei probleme poate fi prevenită prin supraîncărcarea operatorului
de atribuire şi definirea constructorului de copii, amintit anterior.
Atribuirea obiectelor
Presupunînd că două obiecte sînt de acelaşi tip, se poate realiza operaţia de atribuire
între acestea. Aceasta determină copierea datelor obiectelor din membrul drept în datele
obiectului din membrul stîng al operaţiei de atribuire.
19
#include <iostream>
using namespace std;
void f();
main()
{
f();
// aici inca nu cunoastem clasa clas_local
return 0;
}
void f()
{
// aici definim clasa locala clas_local
class clas_local{
int i;
public:
void setare_i(int val) {i=val; }
int furniz_i() {return i; }
} ob; // si iata si un obiect de clasa respectiva
ob.setare_i(77);
cout << ob.furniz_i();
}
//Obiectele pot fi pasate către funcţii exact ca oricare
//alt tip de variabilă (de altfel, această posibilitate a
//fost folosită la un exemplu anterior, care folosea o
//funcţie friend pentru controlul accesului la o resursă
//comună). Obiectele sînt pasate funcţiilor prin utilizarea
mecanismului standard de apelare prin valoare, adică prin copiere.
#include "stdafx.h"
#using <mscorlib.dll>
#include <stdlib.h>
#include <iostream>
using namespace std;
class ex_apel{
int i;
public:
ex_apel(int );
~ex_apel();
void set_i(int val) {i=val;}
int ret_i() {return i;}
};
ex_apel::ex_apel(int init)
{
i=init;
cout << "Construirea pentru " << i << "\n";
}
ex_apel::~ex_apel()
{
cout << "Distrugerea pentru " << i << "\n";
}
void f(ex_apel );
main()
{
ex_apel ex1(1); // un obiect de tip ex_apel
f(ex1); // aici, apel de functie cu parametru obiect
cout << "Valoarea i din main : " << ex1.ret_i() << "\n";
20
return 0;
}
main()
{
retur_ob o; // se creaza un obiect
retur_ob f()
{
retur_ob interior; // obiect din functie
interior.set_i(1); // setam ca sa ne convingem ca e
// transmis in afara
return interior; // si returnam un obiect
}
//Sa se prezinte atribuirea a doua obiecte
#include "stdafx.h"
#using <mscorlib.dll>
#include <stdlib.h>
#include <iostream>
using namespace std;
class atribuire{
int i;
public:
void set_i(int val) {i=val; }
int ret_i() {return i; }
};
main()
{
atribuire a1, a2; // cele doua obiecte
21
cout << "Valoarea i din a2 : " << a2.ret_i() << "\n";
return 0;
}
//sa se defineasca o functie in 3 feluri
//adica se supraincarca
#include "stdafx.h"
#using <mscorlib.dll>
#include <stdlib.h>
#include <iostream>
using namespace std;
// aici definim functia noastra in trei feluri
int abs(int );
double abs(double );
long abs(long );
main()
{
cout << abs(-10) << "\n";
cout << abs(-22.5) << "\n";
cout << abs(-5L) << "\n";
return 0;
}
int abs(int i)
{
cout << "ABS pentru intregi\n";
return i<0 ? -i : i ;
}
double abs(double d)
{
cout << "ABS pentru double\n";
return d<0 ? -d : d ;
}
long abs(long l)
{
cout << "ABS pentru intregi lungi\n";
return l<0 ? -l : l ;
}
22
stiva(); // constructor
~stiva(); // destructor
void pune(int );
int scoate();
};
// functia constructor
stiva::stiva(){
virf_stiva=0;
cout << "In regula, stiva este initializata\n";
}
// functia destructor
stiva::~stiva()
{
cout << "In regula, stiva e distrusa\n";
}
int stiva::scoate(){
if (virf_stiva==0) {
cout << "Depasire inferioara\n";
return 0;
}
virf_stiva--;
return stiv[virf_stiva];
}
// Programul principal
main()
{
stiva stiv1, stiv2; // crearea a doua obiecte de tip stiva
stiv1.pune(1); // punem ceva in stive
stiv2.pune(2);
stiv1.pune(3);
stiv2.pune(4);
cout << stiv1.scoate() << " "; // acum scoatem din stive
si
cout << stiv1.scoate() << " "; // afisam
cout << stiv2.scoate() << " ";
cout << stiv2.scoate() << "\n ";
return 0; // gata
}
// Exercitiul 11.3.1.txt
// Acest program testeaza clasa Fraction prin initializarea unei
serii de
23
// fractii si afisarea fiecarei valori.
//
// Nota: Desi eu sugerez sa folositi combinatia copy-si-paste pentru
a genera
// o parte a acestui cod, folosirea unor matrice este probabil cea
mai buna
// modalitate de a economisi timpul. Dar aceasta abordare este
lasata pentru
// dumneavoastra, ca un alt exercitiu.
#include "stdafx.h"
#using <mscorlib.dll>
#include <stdlib.h>
#include <iostream>
using namespace std;
class Fraction {
private:
int num, den;
public:
void set(int n, int d) {num = n; den = d; normalize();}
int get_num() {return num;}
int get_den() {return den;}
private:
void normalize();
int gcf(int a, int b);
int lcm(int a, int b);
};
int main() {
void Fraction::normalize(){
if (den == 0 || num == 0) {
num = 0;
den = 1;
24
}
if (den < 0) {
num *= -1;
den *= -1;
}
#include "stdafx.h"
#using <mscorlib.dll>
#include <iostream>
using namespace std;
class Point {
private:
int x, y;
public:
void set(int new_x, int new_y);
int get_x();
int get_y();
};
int main() {
Point pt1, pt2;
pt1.set(10, 20);
cout << "pt1 is " << pt1.get_x();
cout << ", " << pt1.get_y() << endl;
pt2.set(-5, -25);
cout << "pt2 is " << pt2.get_x();
cout << ", " << pt2.get_y() << endl;
return 0;
}
25
void Point::set(int new_x, int new_y) {
if (new_x < 0)
new_x *= -1;
if (new_y < 0)
new_y *= -1;
x = new_x;
y = new_y;
}
int Point::get_x() {
return x;
}
int Point::get_y() {
return y;
}
// Exercitiul 11.1.1.txt
// Acest program declara o clasa Point ca in scriptul din point1.cpp,
// dar, in aceasta versiune, este stabilita o limita superioara
pentru
// valorile din membrii x si y.
#include "stdafx.h"
#using <mscorlib.dll>
#include <iostream>
using namespace std;
class Point {
private: // Data members (private)
int x, y;
public: // Member functions
void set(int new_x, int new_y);
int get_x();
int get_y();
};
int main() {
Point pt1, pt2;
pt1.set(10, 20);
cout << "pt1 is " << pt1.get_x();
cout << ", " << pt1.get_y() << endl;
pt2.set(-5, -25);
cout << "pt2 is " << pt2.get_x();
cout << ", " << pt2.get_y() << endl;
pt1.set(200, 500);
cout << "pt1 is " << pt1.get_x();
cout << ", " << pt1.get_y() << endl;
return 0;
}
26
new_x *= -1;
if (new_y < 0)
new_y *= -1;
if (new_x > 100)
new_x = 100;
if (new_y > 100)
new_y = 100;
x = new_x;
y = new_y;
}
int Point::get_x() {
return x;
}
int Point::get_y() {
return y;
}
//sa se scrie doua functii care seteaza punctul X si Punctul Y
diferite
#include "stdafx.h"
#using <mscorlib.dll>
#include <iostream>
using namespace std;
class Point {
private:
int x, y;
public:
void set(int new_x, int new_y);
int get_x();
int get_y();
void set_x(int new_x);
void set_y(int new_y);
};
int main() {
Point pt1, pt2;
pt1.set(10, 20);
cout << "pt1 is " << pt1.get_x();
cout << ", " << pt1.get_y() << endl;
pt2.set(-5, -25);
cout << "pt2 is " << pt2.get_x();
cout << ", " << pt2.get_y() << endl;
pt1.set_x(-50);
pt1.set_y(-10);
cout << "pt1 is " << pt1.get_x();
cout << ", " << pt1.get_y() << endl;
return 0;
}
27
new_x *= -1;
x = new_x;
}
int Point::get_x() {
return x;
}
int Point::get_y() {
return y;
}
// Sa se adune doua fractii cu POO
#include "stdafx.h"
#using <mscorlib.dll>
#include <iostream>
using namespace std;
class Fraction {
private:
int num, den;
public:
void set(int n, int d)
{num = n; den = d; normalize();}
int get_num() {return num;}
int get_den() {return den;}
Fraction add(Fraction other);
Fraction mult(Fraction other);
private:
void normalize();
int gcf(int a, int b);
int lcm(int a, int b);
};
int main() {
Fraction fract1, fract2, fract3;
fract1.set(1, 2);
fract2.set(1, 3);
fract3 = fract1.add(fract2);
cout << "1/2 plus 1/3 = ";
cout << fract3.get_num() << "/" << fract3.get_den();
28
}
void Fraction::normalize(){
if (den == 0 || num == 0) {
num = 0;
den = 1;
}
if (den < 0) {
num *= -1;
den *= -1;
}
#using <mscorlib.dll>
#include <iostream>
29
using namespace std;
class Fraction {
private:
int num, den;
public:
void set(int n, int d)
{num = n; den = d; normalize();}
int get_num() {return num;}
int get_den() {return den;}
Fraction add(Fraction other);
Fraction mult(Fraction other);
private:
void normalize();
int gcf(int a, int b);
int lcm(int a, int b);
};
int main() {
Fraction fract1, fract2, fract3;
int n, d;
fract3 = fract1.add(fract2);
void Fraction::normalize(){
if (den == 0 || num == 0) {
num = 0;
den = 1;
}
if (den < 0) {
num *= -1;
den *= -1;
}
30
int Fraction::gcf(int a, int b) {
if (a % b == 0)
return abs(b);
else
return gcf(b, a % b);
}
#using <mscorlib.dll>
#include <iostream>
using namespace std;
class Fraction {
private:
int num, den;
public:
void set(int n, int d)
{num = n; den = d; normalize();}
int get_num() {return num;}
int get_den() {return den;}
Fraction add(Fraction other);
Fraction mult(Fraction other);
private:
void normalize();
int gcf(int a, int b);
int lcm(int a, int b);
};
int main() {
Fraction fract1, fract2, fract3;
int n, d;
31
cout << "Enter denominator for first fraction: ";
cin >> d;
fract1.set(n, d);
cout << "Enter numerator for second fraction: ";
cin >> n;
cout << "Enter denominator for second fraction: ";
cin >> d;
fract2.set(n, d);
fract3 = fract1.mult(fract2);
cout << "fract1 * fract2 is: ";
cout << fract3.get_num() << "/" << fract3.get_den() << endl;
void Fraction::normalize(){
if (den == 0 || num == 0) {
num = 0;
den = 1;
}
if (den < 0) {
num *= -1;
den *= -1;
}
//
int Fraction::lcm(int a, int b){
return (a / gcf(a, b)) * b;
}
32
return fract;
}
// Exercitiul 11.4.3.txt
// Acest program extinde clasa Point prezentata in capitolul 11
// prin includerea unei functii noi, Point::add.
#include<stdafx.h>
#include <iostream>
using namespace std;
class Point {
private:
int x, y;
public:
void set(int new_x, int new_y);
int get_x();
int get_y();
Point add(Point other);
};
int main() {
Point pt1, pt2, pt3;
pt1.set(10, 20);
cout << "pt1 is " << pt1.get_x();
cout << ", " << pt1.get_y() << endl;
pt2.set(-5, -25);
cout << "pt2 is " << pt2.get_x();
cout << ", " << pt2.get_y() << endl;
pt3 = pt1.add(pt2);
pt2.set(-5, -25);
cout << "pt3 is " << pt3.get_x();
cout << ", " << pt3.get_y() << endl;
return 0;
}
int Point::get_x() {
return x;
}
int Point::get_y() {
return y;
}
33
Point Point::add(Point other) {
Point new_pt;
int new_x = x + other.get_x();
int new_y = y + other.get_y();
new_pt.set(new_x, new_y);
return new_pt;
}
#include "stdafx.h"
// Exercitiul 11.4.4.txt
// Acest program include functiile sub (scadere) si div (impartire)
// pentru clasa Fraction.
#include <iostream>
using namespace std;
class Fraction {
private:
int num, den;
public:
void set(int n, int d)
{num = n; den = d; normalize();}
int get_num() {return num;}
int get_den() {return den;}
Fraction add(Fraction other);
Fraction mult(Fraction other);
Fraction sub(Fraction other);
Fraction div(Fraction other);
private:
void normalize();
int gcf(int a, int b);
int lcm(int a, int b);
};
int main() {
Fraction fract1, fract2, fract3;
int n, d;
34
}
void Fraction::normalize(){
if (den == 0 || num == 0) {
num = 0;
den = 1;
}
if (den < 0) {
num *= -1;
den *= -1;
}
//
int Fraction::gcf(int a, int b) {
if (a % b == 0)
return abs(b);
else
return gcf(b, a % b);
}
35
fract.set(-1 * other.num, other.den);
return add(fract);
}
Se pot transmite parametri către funcţiile constructor. Aceştia sînt folosiţi mai ales
pentru iniţializarea unui obiect la creare. Pentru aceasta, trebuie pur şi simplu adăugaţi
parametri în modul în care acest lucru se realizează pentru orice funcţie. Iar parametrii transmişi
vor fi folosiţi pentru iniţilizarea obiectului.
Funcţiile constructor cu parametri sînt utile deoarece permit evitarea unui aple suplimentar
pentru iniţializarea valorilor unor variabile din obiecte.
Un caz special al funcţiilor constructor cu parametri este constituit de funcţiile
constructor cu un parametru. În acest caz, există o altă cale de a-i pasa acestuia o valoare
iniţială. În cazul cînd constructorul are un singur argument, se poate folosi pur şi simplu forma
de iniţializare "naturală". Compilatorul va atribui automat valoarea din dreapta semnului "=",
parametrului constructorului.
Despre execuţia constructorilor şi destructorilor
2. Funcţiile constructor pentru obiecte globale sînt executate înaintea lui main(). Constructorii
globali din acelaşi fişier sînt executaţi în rodinea în care au fost întîlniţi, de la stînga la dreapta
şi de sus în jos. E greu de depistat ordinea execuţiei constructorilor împrăştiaţi în mai multe
fişiere. Destructorii globali se execută în ordine inversă, după încheierea funcţiei main().
#include "stdafx.h"
#include <iostream>
using namespace std;
class Point {
private:
int x, y;
public: // Constructori
Point() {set(0,0);};
Point(int new_x, int new_y) {set(new_x, new_y);}
36
// functii membre
int main() {
Point pt1, pt2;
Point pt3(5, 10);
int Point::get_x() {
return x;
}
int Point::get_y() {
return y;
}
// Exercitiul 12.1.1.txt
// Aceasta versiune a lui point2.cpp raporteaza ce constructori vor
fi utilizati.
#include "stdafx.h"
#include <iostream>
using namespace std;
class Point {
private: // Data members (private)
int x, y;
public: // Constructors
Point()
{set(0,0); cout << "Using default constructor" << endl; }
37
// Other member functions
int main() {
Point pt1, pt2;
Point pt3(5, 10);
int Point::get_x() {
return x;
}
int Point::get_y() {
return y;
}
// Exercitiul 12.1.2.txt
// Aceasta versiune a programului Point2 adauga constructorul
Point(int)
// (un constructor care preia un singur argument intreg).
#include "stdafx.h"
#include <iostream>
using namespace std;
class Point {
private: // Data members (private)
int x, y;
public: // Constructors
Point() {set(0, 0);}
Point(int new_x, int new_y) {set(new_x, new_y);}
38
int get_x();
int get_y();
};
int main() {
Point pt1(6); // THIS TESTS THE NEW CONSTRUCTOR
Point pt2;
Point pt3(5, 10);
int Point::get_x() {
return x;
}
int Point::get_y() {
return y;
}
//sa se defineasca constructori pentru clasa Fractie
#include "stdafx.h"
#include <iostream>
using namespace std;
class Fraction {
private:
int num, den; // Numerator and denominator.
public:
Fraction() {set(0, 1);}
Fraction(int n, int d) {set(n, d);}
int main() {
39
Fraction f1, f2;
Fraction f3(1, 2);
void Fraction::normalize(){
if (den == 0 || num == 0) {
num = 0;
den = 1;
}
if (den < 0) {
num *= -1;
den *= -1;
}
40
Fraction Fraction::mult(Fraction other) {
Fraction fract;
fract.set(num * other.num, den * other.den);
fract.normalize();
return fract;
}
// Exercitiul 12.2.1.txt
// Aceasta versiune a clasei Fraction revizuieste constructorul
prestabilit
// astfel incat sa stabileasca direct valoarea membrilor de date num
si den.
//
// Apelarea functiei normalize nu este strict necesara, dar este
putin mai precaut,
// in particular, daca functia normalize va fi rescrisa de subclase
// (cum se va explca mai tarziu in acest capitol).
//
// Setarea directa a functiilor num si den este putin mai eficienta,
deoarece ocoleste
// ap
#include "stdafx.h"
elarea unei functii; totusi, aceasta este un foarte mica
imbunatatire.
#include <iostream>
using namespace std;
class Fraction {
private:
int num, den; // Numerator and denominator.
public:
Fraction() {num = 0; den = 0; normalize();} // <-- NEW VERSION
int main() {
Fraction f1, f2;
Fraction f3(1, 2);
41
return 0;
}
void Fraction::normalize(){
if (den == 0 || num == 0) {
num = 0;
den = 1;
}
if (den < 0) {
num *= -1;
den *= -1;
}
// Exercitiul 12.2.2.txt
// Aceasta versiune a clasei Fraction adauga un constructor
Fraction(int),
42
// care creeaza o fractie de forma n/1.
#include "stdafx.h"
#include <iostream>
using namespace std;
class Fraction {
private:
int num, den; // Numerator and denominator.
public:
Fraction() {set(0, 1);}
Fraction(int n, int d) {set(n, d);}
Fraction(int n) {set(n, 1);} // NEW CONSTRUCTOR ADDED
int main() {
Fraction f1(6); // THIS TESTS THE NEW CONSTRUCTOR
Fraction f2;
Fraction f3(1, 2);
void Fraction::normalize(){
if (den == 0 || num == 0) {
num = 0;
den = 1;
}
if (den < 0) {
num *= -1;
den *= -1;
}
43
num = num / n;
den = den / n;
}
#include "stdafx.h"
#include <iostream>
using namespace std;
class Fraction {
private:
int num, den; // Numerator and denominator.
public:
Fraction() {set(0, 1);}
Fraction(int n, int d) {set(n, d);}
Fraction(Fraction const &src);
44
int lcm(int a, int b); // Lowest Common Denominator.
};
int main() {
Fraction f1(3, 4);
Fraction f2(f1);
Fraction f3 = f1.add(f2);
// ---------------------------------------------------
// FRACTION CLASS FUNCTIONS
if (den == 0 || num == 0) {
num = 0;
den = 1;
}
if (den < 0) {
num *= -1;
den *= -1;
}
45
int Fraction::lcm(int a, int b){
return (a / gcf(a, b)) * b;
}
// Exercitiul 12.3.1.txt
// Aceasta versiune a programului fract4.cpp rescrie un constructor
de copiere
// sub forma unei functii in linie.
#include "stdafx.h"
#include <iostream>
using namespace std;
class Fraction {
private:
int num, den; // Numerator and denominator.
public:
Fraction() {set(0, 1);}
Fraction(int n, int d) {set(n, d);}
int main() {
Fraction f1(3, 4);
Fraction f2(f1);
Fraction f3 = f1.add(f2);
46
cout << "The value of f3 is ";
cout << f3.get_num() << "/";
cout << f3.get_den() << endl;
return 0;
}
void Fraction::normalize(){
if (den == 0 || num == 0) {
num = 0;
den = 1;
}
if (den < 0) {
num *= -1;
den *= -1;
}
47
// Exercitiul 12.3.2.txt
// Aceasta versiune a programului fract4.cpp revizuieste
constructorul de copiere
// astfel incat sa faca apel la functia set in loc sa stabileasca
direct valoarea
// membrilor de date num si den.
//
// Aceasta abordare isi pierde putin din eficienta fata de situatia
cand constructorul
// este setat ca o functie in linie. Cu toate acestea, el apeleaza
functia normalize,
// lucru care nu este neaparat necesar. (Cand copiati o fractie
existenta, puteti
// presupune ca valoarea sa a fost deja normalizata.)
#include "stdafx.h"
#include <iostream>
using namespace std;
class Fraction {
private:
int num, den; // Numerator and denominator.
public:
Fraction() {set(0, 1);}
Fraction(int n, int d) {set(n, d);}
Fraction(Fraction const &src);
int main() {
Fraction f1(3, 4);
Fraction f2(f1);
Fraction f3 = f1.add(f2);
// ---------------------------------------------------
// FRACTION CLASS FUNCTIONS
48
void Fraction::normalize(){
if (den == 0 || num == 0) {
num = 0;
den = 1;
}
if (den < 0) {
num *= -1;
den *= -1;
}
SUPRAINCARCAREA(DEFINIREA NOUA) A
OPERATORILOR
49
//Sa se defineasca operatorul care aduna coordonatele unor puncte
//si care face diferenta intre coordonatele unor puncte
#include "stdafx.h"
#include <iostream>
using namespace std;
class Point {
private: // Data members (private)
int x, y;
public: // Constructors
Point() {};
Point(int new_x, int new_y) {set(new_x, new_y);}
Point(const Point &src) {set(src.x, src.y);}
// Operations
int main() {
return 0;
}
50
Point Point::sub(const Point &pt) {
Point new_pt;
new_pt.x = x - pt.x;
new_pt.y = y - pt.y;
return new_pt;
}
// Exercitiul 13.1.1.txt
// Aceasta versiune a programului point3.cpp indica de cate ori sunt
apelati
// constructorul predefinit si constructorul de copiere.
#include "stdafx.h"
#include <iostream>
using namespace std;
class Point {
private: // Data members (private)
int x, y;
public: // Constructors
Point()
{set(0, 0); cout << "Inside default constructor" << endl; } //
ALTERED CODE
// Operations
int main() {
return 0;
}
51
void Point::set(int new_x, int new_y) {
if (new_x < 0)
new_x *= -1;
if (new_y < 0)
new_y *= -1;
x = new_x;
y = new_y;
}
// Exercitiul 13.1.2.txt
// Acest program creeaza si testeaza operatii de inmultire (*) intre
// clasa Point si tipul de date int.
#include "stdafx.h"
#include <iostream>
using namespace std;
class Point {
private: // Data members (private)
int x, y;
public: // Constructors
Point() {};
Point(int new_x, int new_y) {set(new_x, new_y);}
Point(const Point &src) {set(src.x, src.y);}
// Operations
int main() {
52
Point point1(20, 20);
Point point2 = point1 * 4; // TEST
MULTIPLICATION WITH INT'S
return 0;
}
#include "stdafx.h"
#include <iostream>
using namespace std;
class Fraction {
private:
int num, den; // Numerator and denominator.
public:
Fraction() {set(0, 1);}
53
Fraction(int n, int d) {set(n, d);}
Fraction(const Fraction &src);
private:
void normalize(); // Put fraction into standard form.
int gcf(int a, int b); // Greatest Common Factor.
int lcm(int a, int b); // Lowest Common Denominator.
};
int main() {
Fraction f1(1, 2);
Fraction f2(1, 3);
Fraction f3 = f1 + f2;
// ---------------------------------------------------
// FRACTION CLASS FUNCTIONS
if (den == 0 || num == 0) {
num = 0;
den = 1;
}
if (den < 0) {
num *= -1;
den *= -1;
}
54
num = num / n;
den = den / n;
}
#include "stdafx.h"
#include <iostream>
using namespace std;
class Fraction {
private:
int num, den; // Numerator and denominator.
public:
Fraction() {set(0, 1);}
Fraction(int n, int d) {set(n, d);}
Fraction(const Fraction &src);
55
Fraction operator*(const Fraction &other)
{return mult(other);}
private:
void normalize(); // Put fraction into standard form.
int gcf(int a, int b); // Greatest Common Factor.
int lcm(int a, int b); // Lowest Common Denominator.
};
int main() {
Fraction fraction_sum(0, 0);
Fraction fraction_new;
int numerator, denominator;
return 0;
}
// ---------------------------------------------------
// FRACTION CLASS FUNCTIONS
if (den == 0 || num == 0) {
num = 0;
den = 1;
}
if (den < 0) {
num *= -1;
den *= -1;
}
56
num = num / n;
den = den / n;
}
class Fraction {
private:
int num, den; // Numerator and denominator.
public:
Fraction() {set(0, 1);}
Fraction(int n, int d) {set(n, d);}
Fraction(int n) {set(n, 1);}
Fraction(const Fraction &src);
57
private:
void normalize(); // Put fraction into standard form.
int gcf(int a, int b); // Greatest Common Factor.
int lcm(int a, int b); // Lowest Common Denominator.
};
int main() {
Fraction f1(1, 2);
Fraction f2(1, 3);
Fraction f3 = f1 + f2 + 1;
// ---------------------------------------------------
// FRACTION CLASS FUNCTIONS
if (den == 0 || num == 0) {
num = 0;
den = 1;
}
if (den < 0) {
num *= -1;
den *= -1;
}
58
//
int Fraction::lcm(int a, int b){
return (a / gcf(a, b)) * b;
}
// ---------------------------------------------------
// FRACTION CLASS FRIEND FUNCTION
// Exercitiul 13.3.1.txt
// Acest exemplu revizuieste programul din exemplul 13.3 astfel incat
afiseaza
// iesirea din clasa Fraction in format (num, den).
#include "stdafx.h"
#include <iostream>
using namespace std;
class Fraction {
private:
int num, den; // Numerator and denominator.
public:
Fraction() {set(0, 1);}
Fraction(int n, int d) {set(n, d);}
Fraction(int n) {set(n, 1);}
Fraction(const Fraction &src);
59
Fraction operator*(const Fraction &other)
{return mult(other);}
int operator==(const Fraction &other);
friend ostream &operator<<(ostream &os, Fraction &fr);
private:
void normalize(); // Put fraction into standard form.
int gcf(int a, int b); // Greatest Common Factor.
int lcm(int a, int b); // Lowest Common Denominator.
};
int main() {
Fraction f1(1, 2);
Fraction f2(1, 3);
Fraction f3 = f1 + f2 + 1;
// ---------------------------------------------------
// FRACTION CLASS FUNCTIONS
if (den == 0 || num == 0) {
num = 0;
den = 1;
}
if (den < 0) {
num *= -1;
den *= -1;
}
60
return gcf(b, a % b);
}
// ---------------------------------------------------
// FRACTION CLASS FRIEND FUNCTION -- THIS IS THE REVISED FUNCTION
CODE
#include "stdafx.h"
#include <iostream>
using namespace std;
class Fraction {
private:
int num, den; // Numerator and denominator.
public:
Fraction() {set(0, 1);}
Fraction(int n, int d) {set(n, d);}
Fraction(int n) {set(n, 1);}
Fraction(const Fraction &src);
61
Fraction mult(const Fraction &other);
Fraction operator+(const Fraction &other)
{return add(other);}
Fraction operator*(const Fraction &other)
{return mult(other);}
int operator==(const Fraction &other);
int operator>(const Fraction &other); // DECLARATION OF >
FNCT.
int operator<(const Fraction &other); // DECLARATION OF <
FNCT.
friend ostream &operator<<(ostream &os, Fraction &fr);
private:
void normalize(); // Put fraction into standard form.
int gcf(int a, int b); // Greatest Common Factor.
int lcm(int a, int b); // Lowest Common Denominator.
};
int main() {
Fraction f1(1, 2);
Fraction f2(1, 3);
return 0;
}
// ---------------------------------------------------
// FRACTION CLASS FUNCTIONS
if (den == 0 || num == 0) {
num = 0;
den = 1;
}
if (den < 0) {
num *= -1;
den *= -1;
62
}
// ---------------------------------------------------
// FRACTION CLASS FRIEND FUNCTION
63
}
FUNCTII PRIETEN
// Exercitiul 13.3.3.txt
// Acest program adauga functia operator<< la clasa Point.
// Functia este declarata ca prieten al clasei.
#include "stdafx.h"
#include <iostream>
using namespace std;
class Point {
private: // Data members (private)
int x, y;
public: // Constructors
Point() {};
Point(int new_x, int new_y) {set(new_x, new_y);}
Point(const Point &src) {set(src.x, src.y);}
// Operations
int main() {
cout << "The point is " << point4 << endl; // TEST OPERATOR<<
FUNCT.
return 0;
}
64
Point Point::add(const Point &pt) {
Point new_pt;
new_pt.x = x + pt.x;
new_pt.y = y + pt.y;
return new_pt;
}
Exact aşa cum pot fi definiţi pointeri către alte tipuri de variabile, pot exista şi
pointeri către obiecte. Când se doreşte acces la membrii unei clase cu ajutorul unui
pointer către un obiect, se foloseşte operatorul săgeată ( -> ) în locul operatorului
punct. Se poate atribui unui pointer adresa unui membru public al unui obiect şi apoi
să aveţi acces la acel membru folosind pointerul.
Se poate elimina orice nepotrivire folosind un modelator (adică o conversie de tip) dar
astfel se trece peste mecanismul de verificare a tipului din C++. În C++, se realizează
o verificare mai strictă a tipurilor decît în C (unde se poate atribui orice tip de valoare
oricărui pointer), atunci cînd sînt implicaţi pointeri.
Pointerul this
Cînd este apelată o funcţie membru, i se pasează automat un argument implicit
(care nu apare în lista de parametri), care este un pointer către obiectul care a generat
apelul (adică obiectul care a invocat funcţia : obiect.functie(...) ). Acest pointer este
numit this.
La membrii unei clase se poate dobîndi acces direct din cadrul unei funcţii membru,
fără nici un specificator de obiect sau de clasă.
Există două restricţii legate de this :
Funcţiile friend nu sînt membri ai clasei, deci nu le sînt pasaţi pointeri this.
Funcţiile membre de tip static nu au nici ele un pointer this.
65
derivat, care au fost importaţi din clasa de bază. Deci nu putem avea acces prin
intermediul acelui pointer, la membrii adăugaţi de clasa derivată (şi justificarea este
logică şi imediată: un pointer din clasa de bază nu poate indica ceva ce nu are de unde
să cunoască - adică membrii adăugaţi - în schimb, poate indica acei membri care sînt
de fapt tot din clasa de bază - dar care sînt moşteniţi, “cunoscuţi” de clasa derivată).
Acest inconvenient poate fi rezolvat prin convertirea unui pointer din clasa de bază
într-unul derivat şi astfel se dobîndeşte acces la întreaga clasă derivată.
Pointeri către membrii clasei
C++ permite generarea unui tip special de pointeri care indică generic spre un
membru al unei clase, nu către un anumit exemplar al acelui membru dintr-un obiect.
Acest tip de pointer este numit pointer către un membru al clasei sau pe scurt pointer
la membru. Acesta nu e acelaşi lucru cu un pointer normal. Un astfel de pointer
asigură doar o poziţionare (un offset) într-un obiect din clasa membrului, unde poate
fi găsit acel membru. Deoarece pointerii la membri nu sînt chiar pointeri în înţelesul
pe care îl cunoaştem, nu li se pot aplica operatorii obişnuiţi în operarea cu pointeri
normali: . şi -> . Pentru a avea acces la membrul unei clase prin intremediul unui
pointer de acest tip, vor trebui folosiţi operatorii speciali pentru pointeri la membri: .*
şi ->* .
Referinţe
S-a văzut în precedentul capitol că atunci cînd un obiect este transmis unei funcţii ca
argument, se face automat o copie a acelui obiect, ba mai mult, cînd este realizată
acea copie, nici nu e apelat constructorul obişnuit al clasei (fiind realizată doar o copie
exactă, fără iniţializările şi celelalte operaţii conţinute în constructor). În schimb, la
terminarea funcţiei, este apelat destructorul copiei. Dacă nu se doreşte apelarea
destructorului, se poate realiza transmiterea obiectului prin referinţă. La acest gen de
apel, aşa cum ne şi aşteptăm, nu se face o copie a obiectului ci manipularea datelor are
loc chiar în obiectul transmis ca referinţă. Deci destructorul nu mai este apelat la
terminarea funcţiei.
Referinţe independente
Cea mai obişnuită utilizare pentru referinţe este pasarea argumentelor prin
referinţă şi obţinerea valorii returnate de funcţie. Totuşi, pot fi declarate şi referinţe ca
simple variabile. Acest tip de referinţă se numeşte referinţă independentă.
La crearea unei referinţe independente, tot ceea ce se creează este de fapt un al
doilea nume pentru o variabilă. Toate variabilele de tip referinţă independentă trebuie
iniţializate la creare.
Restricţii
66
Există mai multe restricţii care se aplică referinţelor :
O referinţă nu se poate referi la altă referinţă (adică nu poate fi obţinută adresa unei
referinţe).
Nu pot fi create matrice de referinţe.
Nu se poate crea un pointer spre o referinţă.
O referinţă nu se poate defini pentru un cîmp de biţi.
O variabilă de tip referinţă trebuie iniţializată la declarare, dar nu trebuie
iniţializată dacă este membru al unei clase, parametru de funcţie sau valoare
returnată.
Referinţele nule nu sînt permise.
Observaţie
cele două declaraţii sînt echivalente funcţional dar asocierea cu numele tipului reflectă
dorinţa programatorilor ca limbajul C++ să pună la dispoziţie un pointer distinct
pentru tip (tipul întreg, în cazul nostru). Dar sintaxa din C++nu presupune
distributivitatea operatorilor într-o listă de parametri. De aceea se pot uşor formula
declaraţii greşite. Astfel :
int* a,b;
creează un pointer de tip întreg, nu doi, aşa cum am fi dorit. Într-adevăr, în C++ ,
operatorii * sau & se referă doar la următoarea variabilă şi nu la tipul variabilelor,
deşi văzînd linia-sursă am fi tentaţi să credem că atît a cît şi b ar fi pointeri. Această
confuzie este frecventă chiar şi la programatorii buni, cînd nu sînt atenţi.
Din punctul de vedere al compilatorului, este indiferentă forma de scriere de
mai sus. Pentru evitarea confuziilor, se recomandă asocierea operatorilor de mai sus
totuşi cu variabilele.
Operatorii de alocare dinamică din C++
p_var=new tip;
67
...
delete p_var;
Aici, p_var este o variabilă de tip pointer care primeşte un pointer spre
memoria care este suficient de mare pentru a păstra un element de tipul tip.
Operatorul delete trebuie să fie folosit doar cu un pointer valid, alocat deja prin new.
Folosirea oricărui alt tip de pointer cu delete duce la un rezultat imprevizibil şi
aproape sigur determină probleme, chiar căderea sistemului.
Deşi new şi delete efectuează funcţii similare cu malloc() şi free(), ele
prezintă mai multe avantaje:
#include "stdafx.h"
#include <iostream>
using namespace std;
int main() {
int sum = 0;
int n;
int *p;
68
cout << "Enter number of items: ";
cin >> n;
return 0;
}
// Exercitiul 14.1.1.txt
// Acest program modifica scriptul new1.cpp pentru a utiliza un tip
double
// ca tip de baza pentru o matrice in loc de tipul int.
//se aloca memorie pentru elementele unei matrice cu elemete reale
#include "stdafx.h"
#include <iostream>
using namespace std;
int main() {
double sum = 0.0; // TYPE ALTERED TO DOUBLE HERE.
int n;
double *p; // TYPE OF *p ALTERED TO DOUBLE.
return 0;
}
//sa se creeze un analizator lexical adica un program care
69
//sa imparta in cuvinte o fraza dandu-se un delimitator
//ex:3/4/5 =>
// 3
// 4
// 5
#include "stdafx.h"
#include <iostream>
#include <stdlib.h>
#include <string.h>
using namespace std;
class StringParser {
private:
int pos;
char *input_str;
char *delimiters;
public:
StringParser(char *inp, char *delim)
{input_str = inp; delimiters = delim; pos = 0; }
StringParser(char *inp)
{input_str = inp; delimiters = ","; pos = 0; }
char *get();
int get_int();
int more() {return input_str[pos] != '\0'; }
void reset() {pos = 0;}
};
int main() {
char input_str[100];
char *p;
while (parser.more()) {
p = parser.get(); // Get ptr to newly allocated string
cout << p << endl; // Print it
delete [] p; // Release string memory
}
return 0;
}
// ----------------------------------------------
// STRINGPARSER CLASS FUNCTIONS
char *StringParser::get() {
int j = 0;
char *new_str;
new_str = new char[100];
70
// Copy characters as long as none is a
// delimiter or end of string (null)
new_str[j++] = input_str[pos++];
new_str[j] = '\0';
return new_str;
}
int StringParser::get_int() {
char *p = get();
return atoi(p);
delete [] p;
}
// Exercitiul 14.2.1.txt
// Acest program modifica scrptul din exemplul 14.2 astfel incat sa
utilizeze
// functia membru get_int() (limitind intrarile la valori intregi)
in locul
// functiei get().
#include "stdafx.h"
#include <iostream>
#include <stdlib.h>
#include <string.h>
using namespace std;
class StringParser {
private:
int pos;
char *input_str;
char *delimiters;
public:
StringParser(char *inp, char *delim)
{input_str = inp; delimiters = delim; pos = 0; }
StringParser(char *inp)
{input_str = inp; delimiters = ","; pos = 0; }
char *get();
int get_int();
int more() {return input_str[pos] != '\0'; }
void reset() {pos = 0;}
};
int main() {
char input_str[100];
int n; // USE INTEGER RATHER THAN CHAR* STRING
71
StringParser parser(input_str, "/,");
while (parser.more()) {
n = parser.get_int(); // GET AN INTEGER FROM NEXT SUBSTRING
cout << n << endl; // Print it
}
return 0;
}
// ----------------------------------------------
// STRINGPARSER CLASS FUNCTIONS
char *StringParser::get() {
int j = 0;
char *new_str;
new_str = new char[100];
new_str[j++] = input_str[pos++];
new_str[j] = '\0';
return new_str;
}
int StringParser::get_int() {
char *p = get();
return atoi(p);
delete [] p;
}
// Copierea unui subsir intr-un sir prin alocare dinamica
#include "stdafx.h"
#include <iostream>
#include <stdlib.h>
#include <string.h>
using namespace std;
class StringParser {
private:
int pos;
char *input_str;
char *delimiters;
public:
StringParser(char *inp, char *delim)
{input_str = inp; delimiters = delim; pos = 0; }
StringParser(char *inp)
72
{input_str = inp; delimiters = ","; pos = 0; }
int main() {
char input_str[100];
char substr[100]; // USES A STATIC STRING -- THIS SHOULD BE
LARGE
// ENOUGH TO CONTAIN ANY POSSIBLE
SUBSTRING.
while (parser.more()) {
parser.get(substr); // GET NEXT SUBSTRING INTO THE STRING
VAR.
cout << substr << endl; // Print it
}
return 0;
}
// ----------------------------------------------
// STRINGPARSER CLASS FUNCTIONS
dest[j++] = input_str[pos++];
dest[j] = '\0';
return dest;
}
73
DESTRUCTORI SI CUVANTUL CHEIE this
//sa se creeze un destructor care scoate din memorie un sir de
caractere
#include "stdafx.h"
#include <iostream>
#include <string.h>
using namespace std;
class String {
private:
char *ptr;
public:
String();
String(char *s);
~String();
int main() {
String a("STRING 1");
String b("STRING 2");
cout << "The value of a is: " << endl;
cout << a << endl;
cout << "The value of b is: " << endl;
cout << b << endl;
}
// ----------------------------------
// STRING CLASS FUNCTIONS
String::String() {
ptr = new char[1];
ptr[0] = '\0';
}
String::String(char *s) {
int n = strlen(s);
ptr = new char[n + 1];
strcpy(ptr, s);
}
String::~String() {
delete [] ptr;
}
// Exercitiul 15.1.1.txt
// Aceasta versiune a programului string1.cpp testeaza
// constructorul prestabilit String().
#include "stdafx.h"
74
#include <iostream>
#include <string.h>
using namespace std;
class String {
private:
char *ptr;
public:
String();
String(char *s);
~String();
int main() {
String a("STRING 1");
String b("STRING 2");
String c; // NEW OBJECT DECL.
cout << "The value of a is: " << endl;
cout << a << endl;
cout << "The value of b is: " << endl;
cout << b << endl;
// ----------------------------------
// STRING CLASS FUNCTIONS
String::String() {
ptr = new char[1];
ptr[0] = '\0';
}
String::String(char *s) {
int n = strlen(s);
ptr = new char[n + 1];
strcpy(ptr, s);
}
String::~String() {
delete [] ptr;
}
#include "stdafx.h"
#include <iostream>
#include <string.h>
using namespace std;
75
class String {
private:
char *ptr;
public:
String();
String(char *s);
String(const String &src);
~String();
int main() {
String a, b, c;
a = "I ";
b = "am ";
c = "so ";
String d = a + b + c + "very happy!\n";
cout << d;
return 0;
}
// ----------------------------------
// STRING CLASS FUNCTIONS
String::String() {
ptr = new char[1];
ptr[0] = '\0';
}
String::String(char *s) {
int n = strlen(s);
ptr = new char[n + 1];
strcpy(ptr, s);
}
String::~String() {
delete [] ptr;
}
76
String String::operator+(char *s) {
String new_str(ptr);
new_str.cat(s);
return new_str;
}
strcpy(p1, ptr);
strcat(p1, s);
delete [] ptr;
ptr = p1;
}
// Exercitiul 15.2.1.txt
// Acest exemplu revizuieste programul string2.cpp astfel incat sa
suporte functia
// operator+ sub forma unei functii prieten globale.
#include "stdafx.h"
#include <iostream>
#include <string.h>
using namespace std;
class String {
private:
char *ptr;
public:
String();
String(char *s);
String(const String &src);
~String();
77
// NEW DECLARATIONS -- FRIEND FUNCTIONS
int main() {
String a, b, c;
a = "I ";
b = "am ";
c = "so ";
// ----------------------------------
// STRING CLASS FUNCTIONS
String::String() {
ptr = new char[1];
ptr[0] = '\0';
}
String::String(char *s) {
int n = strlen(s);
ptr = new char[n + 1];
strcpy(ptr, s);
}
String::~String() {
delete [] ptr;
}
78
ptr = new char[n + 1];
strcpy(ptr, s);
}
strcpy(p1, ptr);
strcat(p1, s);
delete [] ptr;
ptr = p1;
}
// Exercitiul 15.2.2.txt
// Acest program modifica declaratiile din string2.cpp
// astfel incat fiecare functie care are un argument de tipul
// char* sa foloseasca un argument de tipul const char*.
#include "stdafx.h"
#include <iostream>
#include <string.h>
using namespace std;
class String {
79
private:
char *ptr;
public:
String();
String(const char *s); // ALTERED LINE
String(const String &src);
~String();
int main() {
String a, b, c;
a = "I ";
b = "am ";
c = "so ";
String d = a + b + c + "very happy!\n";
cout << d;
return 0;
}
// ----------------------------------
// STRING CLASS FUNCTIONS
String::String() {
ptr = new char[1];
ptr[0] = '\0';
}
String::~String() {
delete [] ptr;
}
80
String new_str(ptr);
new_str.cat(s);
return new_str;
}
strcpy(p1, ptr);
strcat(p1, s);
delete [] ptr;
ptr = p1;
}
MOSTENIRE-IN PROGRAMAREA PE OBIECT VISUAL
C++.NET
Moştenirea
Moştenirea este una dintre caracteristicile cele mai importante ale unui limbaj
de programare OO. În C++ moştenirea este realizată prin acceptarea ca o clasă să
încorporeze în declararea sa altă clasă. Moştenirea permite construirea unei ierarhii
de clase, trecerea de la cele mai generale la cele mai particulare. Procesul acesta
implică pentru început definirea clasei de bază, care stabileşte calităţile comune ale
tuturor obiectelor ce vor deriva de aici. Clasa de bază reprezintă cea mai generală
descriere. Clasele derivate (obţinute prin moştenire) din clasa de bază se numesc chiar
clase derivate. O clasă derivată include toate caracteristicile clasei de bază şi în plus
calităţi proprii acelei clase.
#include "stdafx.h"
#include <iostream>
using namespace std;
class Fraction {
private:
int num, den; // Numerator and denominator.
81
public:
Fraction() {set(0, 1);}
Fraction(int n, int d) {set(n, d);}
Fraction(int n) {set(n, 1);}
Fraction(const Fraction &src);
private:
void normalize(); // Put fraction into standard form.
int gcf(int a, int b); // Greatest Common Factor.
int lcm(int a, int b); // Lowest Common Denominator.
};
int main() {
FloatFraction fract1;
fract1.set(1, 2);
cout << "Value of 1/2 is " << fract1.get_float() << endl;
fract1.set(3, 5);
cout << "Value of 3/5 is " << fract1.get_float() << endl;
return 0;
}
void Fraction::normalize(){
82
if (den == 0 || num == 0) {
num = 0;
den = 1;
}
if (den < 0) {
num *= -1;
den *= -1;
}
// ---------------------------------------------------
// FRACTION CLASS FRIEND FUNCTION
83
ostream &operator<<(ostream &os, Fraction &fr) {
os << fr.num << "/" << fr.den;
return os;
}
// Exercitiul 16.1.1.txt
// Acest program modifica scriptul floatfract1.cpp astfel incat sa
// contina o functie set_float().
#include "stdafx.h"
#include <iostream>
using namespace std;
class Fraction {
private:
int num, den; // Numerator and denominator.
public:
Fraction() {set(0, 1);}
Fraction(int n, int d) {set(n, d);}
Fraction(int n) {set(n, 1);}
Fraction(const Fraction &src);
private:
void normalize(); // Put fraction into standard form.
int gcf(int a, int b); // Greatest Common Factor.
int lcm(int a, int b); // Lowest Common Denominator.
};
};
int main() {
FloatFraction fract1;
fract1.set_float(0.5);
cout << "Value of 0.5 is " << fract1.get_float() << endl;
84
fract1.set_float(0.6);
cout << "Value of 0.6 is " << fract1.get_float() << endl;
return 0;
}
void FloatFraction::set_float(double x) {
int new_val = static_cast<int>(x * 100.0);
set(new_val, 100);
}
// ---------------------------------------------------
// FRACTION CLASS FUNCTIONS
if (den == 0 || num == 0) {
num = 0;
den = 1;
}
if (den < 0) {
num *= -1;
den *= -1;
}
85
// Lowest Common Multiple
//
int Fraction::lcm(int a, int b){
return (a / gcf(a, b)) * b;
}
#include "stdafx.h"
#include <iostream>
using namespace std;
class Fraction {
private:
int num, den; // Numerator and denominator.
public:
Fraction() {set(0, 1);}
Fraction(int n, int d) {set(n, d);}
Fraction(int n) {set(n, 1);}
Fraction(const Fraction &src);
86
friend ostream &operator<<(ostream &os, Fraction &fr);
private:
void normalize(); // Put fraction into standard form.
int gcf(int a, int b); // Greatest Common Factor.
int lcm(int a, int b); // Lowest Common Denominator.
};
double get_float() {
return static_cast<double>(get_num())/get_den();}
};
int main() {
FloatFraction fract1(0.5), fract2(0.6);
void FloatFraction::set_float(double x) {
int new_val = static_cast<int>(x * 100.0);
set(new_val, 100);
}
if (den == 0 || num == 0) {
num = 0;
den = 1;
87
}
if (den < 0) {
num *= -1;
den *= -1;
}
// ---------------------------------------------------
// FRACTION CLASS FRIEND FUNCTION
88
#include<nume_fiesier.cpp> exemplu #include "Fract7.cpp"
dar
1) el trebuie salvat in directorul unde avem exemplele de mostenire
89
open
4)Fisierul de imoprtat trebuie sa nu contina sectiunea main()
deci sa aiba continutul de mai jos:
#include <iostream>
using namespace std;
class Fraction {
private:
int num, den; // Numerator and denominator.
public:
Fraction() {set(0, 1);}
Fraction(int n, int d) {set(n, d);}
Fraction(int n) {set(n, 1);}
Fraction(const Fraction &src);
private:
void normalize(); // Put fraction into standard form.
int gcf(int a, int b); // Greatest Common Factor.
int lcm(int a, int b); // Lowest Common Denominator.
};
// ---------------------------------------------------
90
// FRACTION CLASS FUNCTIONS
if (den == 0 || num == 0) {
num = 0;
den = 1;
}
if (den < 0) {
num *= -1;
den *= -1;
}
91
fract.set(num * other.num, den * other.den);
fract.normalize();
return fract;
}
// ---------------------------------------------------
// FRACTION CLASS FRIEND FUNCTION
#include "stdafx.h"
#include <iostream>
#include "Fract7.cpp"
using namespace std;
};
int main() {
FloatFraction fract1;
fract1.set_float(0.5);
cout << "Value of 0.5 is " << fract1.get_float() << endl;
fract1.set_float(0.6);
cout << "Value of 0.6 is " << fract1.get_float() << endl;
return 0;
}
void FloatFraction::set_float(double x) {
int new_val = static_cast<int>(x * 100.0);
set(new_val, 100);
}
POLIMORIFISM
Polimorfismul cu functii virtuale
92
Polimorfismul in C++ este admis atit in timpul compilarii cit si in timpul
rularii. polimorfismul din timpul rularii este realizat folosind mostenirea si functiile
virtuale.
Functiile virtuale
93
pentru descrierea redefinirii functiei virtuale intr-o clasa derivata se foloseste operandul
suprascriere.
O clasa care include o functie virtuala se numeste clasa polimorfica.
b. Functiile virtuale sint ierarhizate
Orice clasa derivata trebuie sa asigure o definire fiecarei functii virtuale pure.
Daca aceasta cerinta nu este indeplinita, compilatorul sesizeaza eroare.
In practica programarii in C++ se folosesc citeodata clasele abstracte. Acestea sint
clase care contin cel putin o functie virtuala pura. Deoarece o clasa abstracta contine
una sau mai multe functii pentru care nu exista definitii (adica sint functii virtuale
pure), nu pot fi create obiecte de tipul acelei clase. O clasa abstracta este un tip
incomplet care este folosit doar pentru mai usoara definire a claselor derivate.
Chiar daca nu pot fi create obiecte de tipul unei clase abstracte, se pot crea
pointeri si referinte pentru astfel de clase. Aceasta permite claselor abstracte sa admita
polimorfismul in timpul rularii, care consta din selectarea functiei virtuale corecte de
catre pointerii clasei de baza.
Utilizarea functiilor virtuale
94
Una dintre caile cele mai indicate pentru a asigura transpunerea in practica a
principiului “o interfata – metode multiple” este folosirea functiilor virtuale, a claselor
abstracte si a polimorfismului in timpul rularii. Folosind aceste caracteristici, se pot
realiza ierarhii care sa faca trecerea de la general la specific (de la clasa de baz aspre
clasele derivate), respectind astfel si unul din principiile ingineriei programarii –
abstractizarea. Conform acestei filosofii, trebuie definite toate caracteristicile si
interfetele comune ale unei clase de baza. De asemenea, se folosesc functii virtuale
pentru a defini interfata care va fi folosita de clasele derivate. In esenta, in clasa de
baza trebuie create si definite toate referirile la cazul general, iar clasele derivate
completeaza detaliile specifice.
O utilizare importantă a claselor abstracte şi a funcţiilor virtuale este cea a bibliotecilor de
clase. Un utilizator poate crea propria bibliotecă de clase generice şi extensibile care vor fi
refolosite de alţi utilizatori. Aceştia vor moşteni clasa generală creată iniţial, care defineşte
interfaţa şi elementele comune şi vor defini doar acele funcţii specifice clasei derivate.
Legat de cele discutate, mai trebuie precizate două noţiuni folosite frecvent :
Legăturile ulterioare (late bindings) se referă la apelările de funcţii care nu sînt rezolvate
pînă în momentul rulării. Pentru realizarea legăturilor ulterioare sînt utilizate funcţiile virtuale.
În acest caz, apelarea efectivă a funcţiei virtuale este determinată de tipul obiectului spre care
indică pointerul prin care îl accesăm. Deoarece în majoritatea cazurilor acesta nu poate fi
determinat în timpul compilării, obiectul şi funcţia nu sînt legate pînă în momentul rulării.
Avantajul legăturilor ulterioare este flexibilitatea : spre deosebire de legăturile iniţiale, cele
ulterioare permit crearea programelor care să răspundă la evenimentele care apar în timpul
rulării fără să fie necesară crearea unui cod suplimentar pentru selectarea situaţiilor şi apelurilor
dorite. Însă, deoarece rezolvarea direcţionării apelurilor este împinsă spre execuţia programului,
acesta va fi mai lent.
// Prin apelul aceleasi functii ca denumire a unui obiect dintr-o
//subclasa a unei functii din clasa de baza si aceleasi functii dar
redefinita
//in subclasa dar ca si continut diferita
//Sa se exemplifice acest lucru
//EX:1
// 2
// 1
// 2
// 1
#include "stdafx.h"
#include <iostream>
95
using namespace std;
class Horse
{
public:
void Gallop(){ cout << "Galloping...\n"; }
virtual void Fly() { cout << "Horses can't fly.\n" ; }
private:
int itsAge;
};
#include "stdafx.h"
#include <iostream>
96
virtual HANDS GetHeight() const { return itsHeight; }
virtual COLOR GetColor() const { return itsColor; }
private:
HANDS itsHeight;
COLOR itsColor;
};
class Bird
{
public:
Bird(COLOR color, BOOL migrates);
virtual ~Bird() {cout << "Bird destructor...\n"; }
virtual void Chirp()const { cout << "Chirp... "; }
virtual void Fly()const
{
cout << "I can fly! I can fly! I can fly! ";
}
virtual COLOR GetColor()const { return itsColor; }
virtual BOOL GetMigration() const { return itsMigration; }
private:
COLOR itsColor;
BOOL itsMigration;
};
private:
long itsNumberBelievers;
};
Pegasus::Pegasus(
COLOR aColor,
HANDS height,
BOOL migrates,
long NumBelieve):
Horse(aColor, height),
Bird(aColor, migrates),
itsNumberBelievers(NumBelieve)
{
97
cout << "Pegasus constructor...\n";
}
int main()
{
Pegasus *pPeg = new Pegasus(Red, 5, TRUE, 10);
pPeg->Fly();
pPeg->Whinny();
cout << "\nYour Pegasus is " << pPeg->GetHeight();
cout << " hands tall and ";
if (pPeg->GetMigration())
cout << "it does migrate.";
else
cout << "it does not migrate.";
cout << "\nA total of " << pPeg->GetNumberBelievers();
cout << " people believe it exists.\n";
delete pPeg;
return 0;
}
#include "stdafx.h"
#include <iostream>
Animal::Animal(int age):
itsAge(age)
{
cout << "Animal constructor...\n";
}
98
};
Pegasus::Pegasus(
COLOR aColor,
HANDS height,
BOOL migrates,
long NumBelieve,
int age):
Horse(aColor, height,age),
Bird(aColor, migrates,age),
itsNumberBelievers(NumBelieve)
{
cout << "Pegasus constructor...\n";
}
int main()
{
Pegasus *pPeg = new Pegasus(Red, 5, TRUE, 10, 2);
99
int age = pPeg->GetAge();
cout << "This pegasus is " << age << " years old.\n";
delete pPeg;
return 0;
}
#include <iostream>
using namespace std;
enum BOOL { FALSE, TRUE };
class Shape
{
public:
Shape(){}
~Shape(){}
virtual long GetArea() { return -1; } // error
virtual long GetPerim() { return -1; }
virtual void Draw() {}
private:
};
void Circle::Draw()
{
cout << "Circle drawing routine here!\n";
}
100
void Rectangle::Draw()
{
for (int i = 0; i<itsLength; i++)
{
for (int j = 0; j<itsWidth; j++)
cout << "x ";
Square::Square(int len):
Rectangle(len,len)
{}
{
if (GetLength() != GetWidth())
cout << "Error, not a square... a Rectangle??\n";
}
int main()
{
int choice;
BOOL fQuit = FALSE;
Shape * sp;
while (1)
{
cout << "(1)Circle (2)Rectangle (3)Square (0)Quit: ";
cin >> choice;
switch (choice)
{
case 1: sp = new Circle(5);
break;
case 2: sp = new Rectangle(4,6);
break;
case 3: sp = new Square(5);
break;
default: fQuit = TRUE;
break;
}
if (fQuit)
break;
sp->Draw();
cout << "\n";
}
return 0;
101
}
#include "stdafx.h"
#include <iostream>
using namespace std;
enum COLOR { Red, Green, Blue, Yellow, White, Black, Brown } ;
enum BOOL { FALSE, TRUE };
Animal::Animal(int age):
itsAge(age)
{
cout << "Animal constructor...\n";
}
102
public:
Horse(int age, COLOR color ):
Mammal(age), itsColor(color)
{ cout << "Horse constructor...\n"; }
virtual ~Horse() { cout << "Horse destructor...\n"; }
virtual void Speak()const { cout << "Whinny!... \n"; }
virtual COLOR GetItsColor() const { return itsColor; }
virtual void Sleep() const
{ cout << "Horse snoring...\n"; }
virtual void Eat() const { cout << "Horse feeding...\n"; }
virtual void Move() const { cout << "Horse running...\n";}
protected:
COLOR itsColor;
};
protected:
COLOR itsColor;
};
int main()
{
Animal *pAnimal=0;
int choice;
BOOL fQuit = FALSE;
while (1)
{
cout << "(1)Dog (2)Horse (3)Fish (0)Quit: ";
cin >> choice;
switch (choice)
{
case 1: pAnimal = new Dog(5,Brown);
break;
case 2: pAnimal = new Horse(4,Black);
break;
case 3: pAnimal = new Fish (5);
break;
default: fQuit = TRUE;
break;
}
if (fQuit)
break;
pAnimal->Speak();
pAnimal->Eat();
103
pAnimal->Reproduce();
pAnimal->Move();
pAnimal->Sleep();
delete pAnimal;
cout << "\n";
}
return 0;
}
SUPRAINCARCAREA FUNCTIILOR
Supraîncărcarea
Supraîncărcarea funcţiilor reprezintă folosirea aceluiaşi nume pentru două sau mai
multe funcţii. Fiecare redefinire a funcţiei trebuie să folosească tipuri diferite de parametri de
apel sau număr diferit de parametri. Compilatorul poate detecta care funcţie trebuie apelată, pe
baza acestor diferenţe.
Trebuie reţinut că nu pot fi supraîncărcate două funcţii care diferă doar prin tipul
returnat.
Ambiguităţi şi anacronisme la supraîncărcarea funcţiilor
În C putem să atribuim adresa unei funcţii, unui pointer şi apoi să aelăm funcţia
folosind pointerul. La fel se poate proceda (s-a văzut în cursurile precedente) şi în C++. O
complicaţie survine la supraîncărcarea funcţiilor, deoarece în această situaţie doar declararea
corespunzătoare a pointerului poate face diferenţierea.
Supraîncărcarea operatorilor
În C++ pot fi supraîncărcaţi aproape toţi operatorii. Supraîncărcarea acestora este strîns
legată de supraîncărcarea funcţiilor. În C++ supraîncărcarea operatorilor poate să determine
efectuarea unor operaţii speciale relativ la clasele create. Astfel, o memorie stivă poate fi
încărcată cu un element, folosind operatorul + supraîncărcat corespunzător, respectiv - pentru
104
extragere. Supraîncărcarea nu afectează vreuna din semnificaţiile originale ale utilizării
operatorului supraîncărcat.
Operatorii se supraîncarcă folosind funcţiile operator. O astfel de funcţie defineşte
operaţiile specifice pe care le va efectua operatorul supraîncărcat relativ la clasa în care este
destinat să lucreze. Funcţiile operator pot sau nu să fie membre ale clasei în care vor opera. De
obicei, cînd funcţiile operator nu sînt membre, sînt măcar funcţii friend. Cele două situaţii
(cînd sînt membre, respectiv cînd sînt friend) trebuie tratate diferit.
tip_returnat nume_clasa::operator#(lista_argumente)
{
... // aici vor fi operatiile care reprezinta redefinirea
// operatorului
}
La operandul -, a trebuit să fim atenţi la ordine : operandul din dreapta semnului trebuie scăzut
din operandul din stînga (ordinea naturală) şi ţinînd cont de operandul care generază apelul
funcţiei operator-() (adică acel operand care va transmite un pointer this), a rezultat
exprimarea aparent curioasă din definirea funcţiei operand respective.
Pe de altă parte, trebuie remarcat că în C++, în lipsa unei supraîncărcări, operatorul =
devine un operator de copiere membru cu membru. În exemplul prezentat, funcţia operator=()
a returnat *this, ceea ce a permis realizarea atribuirilor multiple (de altfel, aceasta este raţiunea
pentru care a fost supraîncărcat acest operator).
Ultimul lucru pe care îl remarcăm este legat de supraîncărcarea operatorului unar.
Evident, acesta nu are parametri, deoarece acţionează asupra unui singur operand, care este deja
transmis prin this.
#include "stdafx.h"
#include <iostream>
using namespace std;
int supra(int ); // prima functie are un parametru intreg
double supra(double ); // iar a doua are parametru double
main()
{
cout << supra(19) << " "; // apelul primei functii
cout << supra(5.4) << "\n"; //apelul celeilalte functii
return 0;
}
105
double supra(double d)
{
return d;
}
// Sa se supraincarce o functie cu numar diferit de paramatrii
#include "stdafx.h"
#include <iostream>
using namespace std;
main()
{
cout << supra1(11) << " "; // apelul primei functii
cout << supra1(5,4) << "\n"; //apelul celeilalte functii
return 0;
}
#include "stdafx.h"
#include <iostream>
#include <stdio.h>
using namespace std;
class data {
int zi, luna, an;
public:
data(char *);
data(int, int, int );
void arata_data();
};
106
{
cout << zi << "/" << luna<< "/"<<an<<"\n";
}
main()
{
data d1(4, 3, 98), d2("10/04/98");
d1.arata_data();
d2.arata_data();
return 0;
}
SUPRAINCARCAREA OPERATORILOR
// Sa se prezinte supraincarcarea operatorului PLUS
#include "stdafx.h"
#include <iostream>
using namespace std;
class loc{
int longit, latit;
public:
loc(){} // necesar pentru constructii de obiecte
// temporare
loc(int lg, int lt) {
longit=lg;
latit=lt;
}
void arata() {
cout << longit << " ";
cout << latit <<"\n";
}
loc operator+(loc ot);
};
main()
{
loc ob1(10,20), ob2(15,25); // se creeaza doua obiecte
// initializate
ob1.arata(); // se va afisa 10 20
ob2.arata(); // se va afisa 15 25
return 0;
}
107
// Sa se supraincarce patru operatori
#include "stdafx.h"
#include <iostream>
using namespace std;
class loc{
int longit, latit;
public:
loc(){} // necesar pentru constructii de obiecte
// temporare
loc(int lg, int lt) {
longit=lg;
latit=lt;
}
void arata() {
cout << longit << " ";
cout << latit <<"\n";
}
loc operator+(loc ot);
loc operator-(loc ot);
loc operator=(loc ot);
loc operator++();
};
108
return *this; // de asemenea este returnat chiar
// obiectul care a generat apelarea, de fapt a operat
// direct asupra obiectului
main()
{
loc ob1(10,20), ob2(15,25), ob3(3,7); // se creeaza
// trei obiecte initializate
ob1.arata(); // se va afisa 10 20
ob2.arata(); // se va afisa 15 25
ob2=++ob1;
ob1.arata(); // afiseaza 12 22
ob2.arata(); // afiseaza tot 12 22
return 0;
}
Matrice, pointeri şi referinţe
//sa se creeze o matrice de obiecte
#include "stdafx.h"
#include <iostream>
using namespace std;
class cl {
int i;
public:
cl(int j){ i = j; }
int da_i() { return i; }
};
main()
{
c1 mo[ 3] = { 1, 2, 3 }; // initializare
int i;
for ( i = 0; i < 3 ; i ++)
cout << mo[ i ] . da_i() << endl;
return 0;
}
109
main()
{
cl ob(23), *p;
p = &ob; // da adresa lui ob
cout << p->da_i(); // foloseste -> pentru a apela da_i()
return 0;
}
// Sa se puna pointer prin deplasarea in matrice
#include<stdafx.h>
#include <iostream>
using namespace std;
class cl {
int i;
public:
cl() { i = 0; }
cl(int j) { i = j; }
int da_i() { return i; }
};
main()
{
cl ob[ 3 ] = { 1, 2, 3 };
cl *p;
int i;
main()
{
acces_p poin(1);
int *p ,i;
110
#include<stdafx.h>
#include <iostream>
using namespace std;
class putere{
double b;
int e;
double rez;
public:
putere(double, int );
double rezultat() {return this->rez; }
};
main()
{
putere x(65.3, 4), y(1.35, 5), z(200.1, 0); // 3 obiecte
return 0;
}
//Sa se puna in evidenta folosirea pointerului THIS
//(adica obiectul care a invocat functia : obiect.functie(...) )
//acici el se subintelege ca e din clasa curenta
#include<stdafx.h>
#include <iostream>
using namespace std;
class putere{
double b;
int e;
double rez;
public:
putere(double, int );
double rezultat() {return rez;}
};
main()
{
putere x(65.3, 4), y(1.35, 5), z(200.1, 0); // 3 obiecte
111
cout << x.rezultat() << endl;
cout << y.rezultat() << endl;
cout << z.rezultat() << endl;
return 0;
}
//Sa se puna in evidenta pointer catre functii si date membru
//ai unei clase
#include<stdafx.h>
#include <iostream>
using namespace std;
class c1{
public:
c1(int i) {val=i; }
int val;
int val_dubla() {return val+val; }
};
main()
{
int c1::*date; // pointer la o data membru
int (c1::*func)(); // pointer la o functie membru
c1 ob1(1), ob2(2); // crearea a doua obiecte
return 0;
}
//cu pointari sa se puna in evidenta
//transmiterea datelor prin referinta
#include<stdafx.h>
#include <iostream>
using namespace std;
void neg(int *);
main()
{
int in;
in=100;
cout << in << " este negat ";
neg(&in); // se transmite adresa explicit
cout << in << endl;
return 0;
}
112
using namespace std;
void neg(int &i); // i este referinta
main()
{
int in;
in=100;
cout << in << " este negat ";
neg(in); // nu e nevoie de &
cout << in << endl;
return 0;
}
main()
{
int a,b;
a=1;
b=2;
cout << " a si b: " << a << " " << b << " ";
schimb(a, b); // aici schimbam ; vedem ca nu trebuie
// scris cu &
cout << " a si b: " << a << " " << b << " "
;
return 0;
}
class nu_distruge{
int k;
public:
int i;
nu_distruge(int );
~nu_distruge();
void neg(nu_distruge &ob) {ob.i = -ob.i; } // nu se va
// crea obiect temporar
113
};
nu_distruge::~nu_distruge() // destructorul
{
cout << "Distruge " << k << "\n";
}
main()
{
nu_distruge ob(1); // un obiect initializat
ob.i=10;
ob.neg(ob); // la apel se transmite obiectul prin
// referinta
return 0;
}
a=1;
cout << a << " " << ref << "\n";
ref=10;
cout << a << " " << ref << "\n";
int b=39;
ref=b; // aici, valoarea lui b trece de fapt in a
cout << a << " " << ref << "\n";
return 0;
}
Operatorii de alocare dinamică din C++
//Sa se aloce dinamic un intreg si sa se elibereze spatiul
#include "stdafx.h"
#include <iostream>
using namespace std;
#include <stdlib.h>
main()
114
{
int *p;
p=new int; // aloca spatiu pentru un intreg
if (!p) {
cout << "Eroare de alocare\n";
exit(1);
}
*p=190;
delete p;
return 0;
}
//sa se supraincarce operatorii de alocare dinamica
#include "stdafx.h"
#include <iostream>
using namespace std;
#include <stdlib.h>
main()
{
int *p;
p=new int(314); // aloca spatiu pentru un intreg
// dar si initializeaza
if (!p) {
cout << "Eroare de alocare\n";
exit(1);
}
*p=190;
delete p;
return 0;
}
//alocarea dintr-o data a memoriei pentru 10 obiecte
//si eliberarea memoriei
#include "stdafx.h"
#include <iostream>
using namespace std;
#include <stdlib.h>
main()
{
int *p, i; // (ati retinut ca doar primul e pointer ?)
115
#include "stdafx.h"
#include <iostream>
using namespace std;
const int* u;
int const* v;
int d = 1;
int* const w = &d;
const int* const x = &d; // (1)
int const* const x2 = &d; // (2)
int main() {} ///:~
116