-pastreaza cuvantul citit in memoria heap;
-realizeaza initializarile;
frecv = 1;
urm = 0.
*/ 47832nkz77dyg2j
{
char t[255] ;
int sf;
cuvint = 0; ky832n7477dyyg
if (tnod : : ind = = false) {
while ( (sf = scanf ( “%s”,t)) ! = EOF ) {
char *p = t ;
int c ;
// salt peste caractere care nu sant litere
while ((c =*p)&&(c<‘A‘||C>‘Z‘&&
c<‘a’||c>‘z‘))
p++;
if ( c = = 0 ) //nu sant litere
continue;
//pastreaza inceputul cuvantului
char *q = p ;
//cauta inceputul cuvantului
while ((c=*p)&&(c>=‘A‘&&c<=‘z’ ||
c >= ‘a‘ &&c <=‘z‘ ))
p++ ;
*q = ‘\0’ ; //caracterul NUL la sfarsitul cuvantului
//rezerva zona pentru cuvantul in memoria heap
//se apeleaza operatorul new standard
printf ( “ tnod : : tnod %lu\n” , coreleft () );
if ( ( cuvant = new char[strlen(q) +1] ) = = 0 ) {
printf ( “ memorie insuficienta\n” ) ;
exit (1) ;
}
printf( “ tnod : : tnod %lu\n” , coreleft () ) ;
//se transfera cuvantul in zona rezervata
strcpy ( cuvant , q );
//initializari
frecv = 1 ;
urm = 0 ; //pointerul nul
break;
} //sfarsit while
if ) sf = = EOF ) //s-a intalnit EOF
tnod : : ind = true ;
}
} // sfarsit constructor
inline tnod : : ~ tnod ( )
{
//se apeleaza operatorul delete standard
printf (“\ndestructor tnod %lu\n”,coreleft ( ) );
delete cuvint ;
printf (“\ndestructor tnod %lu\n”,coreleft ( ) );
}
inline void tnod::afistnod() //afiseaza cuvantul si frecventa
{
printf (“cuvantul=%s\t are frecventa=%d\n”,cuvant,frecv) ;
{
tnod *p ;
//se aplica operatorul new standard
printf (“ operator new %\lu\n”, coreleft ( ) ) ;
p=(tnod *) new char [lung] ;
printf (“ operator new %\lu\n”, coreleft ( ) ) ;
return p ;
}
void tnod::operator delete(void*p) //supraincarcarea operatorului delete
{
//se aplica operatorul delete standard
printf (“ operator delete %\lu\n”, coreleft ( ) ) ;
: : delete p ;
printf (“ operator delete %\lu\n”, coreleft ) ) ;
}
void tnod : : operator ++ ( ) //incrementeaza frecv
{
frecv++ ;
}
Boolean tnod : : retind ( ) //returneaza valoarea ind
{
return tnod : : ind ;
}
Observatie
Functia coreleft returneaza dimensiunea,in octeti, a memoriei libere in momentul apelului.Ea a fost apelata in mai multe functii pentru a putea urmari momentele in care se dezaloca obiectele care sant instantieri ale clasei tnod.
23.12 Sa se defineasca tipul abstract slist pentru implementarea listei simplu inlantuite.
Listele simplu inlantuite au fost implementate in limbajul C in capitolul 11.
Pentru gestiunea listelor simplu inlantuite s-au folosit doua variabile prim si ultim care sant pointeri sper primul si respectiv ultimul nod al listei.
Aceste valori se vor utiliza si in cazul de fata cu acelasi scop.Ele sunt date membru protejate ale tipului abstract slist
Avantajul implementarii tipului abstract slist este acela ca , se pot defini simultan si simplu orice obiecte de tip lista.
Functiile membru ale tipului abstract slist sunt:
constructor implicit ;
deconstructor ;
adaugarea unui nou nod inaintea primului nod al listei ;
stergerea primului nod al listei ;
stergerea ultimului nod al listei ;
cautarea in lista a unui nod ;
afisarea datelor aflate in nodurile listei.
Nodurile listei sunt obiecte de tip tnod, tip definit in exercitiul 23.11
FISIERUL BXXIII12H
#ifndef __BXXIII11_H
#include “BXXIII1.CPP”
#define __ BXXIII1_H
class slist {
tnod *prim ;
tnod *ultim ;
public :
slist ( ) ; // constructor
~slist ( ) ; //destructor
tnod *adauga (tod*) ; //adauga un nod dupa cel spre care
//pointeaza ultim
tnod *insereaza (tnod *p); //insereaza un nod inaintea
//celui spre care pointeza prim
void sprim ( ) ; //sterge primul nod din lista
void sultim ( ) ; //sterge ultimul nod al listei
tnod *cauta (tnod *p) ;
/* - cauta nodul din lista pentru care p -> cuvant pointeaza
spre un sir identic cu cel care pointeaza cuvant din nod ;
-returneaza pointerul spre nodul respectiv sau zero daca nu
exista un astfel de nod */ 47832nkz77dyg2j
void afislist ( ) ; //afiseaza datele din nodurile listei
} ;
Functiile membru ale clasei slist se definesc in fisierul de extensie CPP, de mai jos
FISIERUL BXXIII12
#idndef __BXXIII12_H
#include “BXXIII12.H”
#define __BXIII12_H
#endif
inline slist : : slist ( ) //constructor
{
prim = ultim = 0 ;
}
slist : : ~slist ( ) //destructor ; distruge toate nodurile listei
{
tnod *p, *q ;
for (p = prim ; p ; p=q) {
q=p->urm ; //pointer spre nodul urmator
delete p ; //operatorul delete supraincarcat
}
prim = ultim = 0 ;
}
tnod *slist::adauga(tnod*p) //adauga un nod dupa ultimul nod al listei
{
if (prim == 0) //lista vida
prim = p ;
else ultim -> urm = p ;
ultim = p ;
return p ;
}
tnod *slist ; : insereaza (tnod *p)
//insereaza un nou nod inaintea celui spre care pointeaza prin
{
if ( prim = = 0 ) //lista vida
ultim = p ;
else p -> urm = prim ;
prim = p ;
return p ;
}
void slist : : sprim ( ) //sterge primul nod din lista
{
if (prim0 {
tnod *p = prim -> urm ;
delete prim ; //se aplica operatorul delete supraincarcat
prim = p ;
if (prim = = 0 ) ultim = 0 ; //lista a devenit vida
} else
printf ( “lista vida\n” ) ;
}
void slist : : sultim ( ) //sterge ultimul nod al listei
{
if (prim) {
tnod 8p,*p1 ;
// p – pointeaza spre nodul curent
p = prim ;
//p1 – poinbteaza spre nodul precendet
p1 = 0 ;
while ( p != ultim ) { //parcurge lista
p1 = p ;
p = p -> urm ;
}
// p – pointeaza spre ultimul nod
//p1 – pointeaza spre nodul precedent
if (p1 = = 0 ) { //lista are un singur nod si devine vida
delete p ; //se aplica operatorul supraincarcat
prim = ultim = 0 ;
return ;
}
//nodul spre care pointeaza p1 devine ultimul nod al listei
p1 -> urm = 0 ;
ultim = p1 ;
//se sterge nodul spre care pointeaza p
delete p ; //se aplica operatorul supraincarcat
} else
printf ( “ lista vida\n “ ) ;
}
tnod *slist : : cauta (tnod *p )
/* - cauta nodul pentru care cuvant pointeaza spre un sir identic cu cel spre
care pointeaza p -> cuvant ;
- returneaza pointerul spre nodul respectiv sau 0 daca nu exista un astfel
de nod. */ 47832nkz77dyg2j
{
tnod *q ;
for (q=prim;q;q=q->urm)
if (stricmp (p -> cuvant,q -> cuvant = = 0 )
return q ;
return 0 ;
}
void slist : : afislist ( )
/* - afiseaza pentru fiecare nod:
-cuvant
si
-frecv.
*/ 47832nkz77dyg2j
{
int nrlin = 1 ;
for (tnod *p = prim ; p ; p = p -> urm ) {
p -> afistnod ( ) ;
nrlin ++;
if (nrlin %23 = = 0) {
printf(“Actionati o tasta pentru a continua\n” );
getch ( ) ;
}
}
}
23.13 Sa se scrie un program care citeste un text si afiseaza frecventa de aparitie a fiecarui cuvant din tex.Nu se face distinctie intre literele mari si mici
Aceasta problema a fost rezolvata in mai multe moduri in capitolele precedente.
In particular,in capitolul 11 se da o rezolvare folosind listele simplu inlantuite.
Programul de fata utilizeaza aceeasi metoda.
PROGRAMUL BXXIII13
#include <alloc.h>
#ifndef __CONIO_H
#include <conio.h>
#define __CONIO_H
#endif
#include “BXIII12.CCP”
main ( )
/*citeste un text si afiseaza frecventa cuvintelor citite 8/
{
slist lista ;
tnod *nod, *p ;
printf ( “%lu\n”,coreleft ( ) );
while (tnod : : retind ( ) = = false )
//nu s-a ajuns la sfarsitul textului
{
nod = new tnod ; //se aplica operatorul new supraincarcat
//cauta nodul in lista
if (tnod : : retind ( ) = = false )
if (p = lista.cauta(nod) ) {
//cuvantul exista deja in lista
(*p)++; //incrementeaza frecv
delete nod ; //se aplica operatorul delete supraincarcat
} else
lista.adauga (nod);
/*nodul spre care pointeazanod contine un cuvant
negasit in lista; se adauga la lista */ 47832nkz77dyg2j
else delete nod ;
printf(“Pentru a continua actionati o tasta\n”);
getch ( ) ;
} //sfarsit while
//listeaza nodurile listei
lista.afislist ( ) ;
}
23.2 Supraincarcarea operatorului =
In limbajul C++ se pot face atribuiri de obiecte care sant instantieri ale aceleeasi clase.
Exemplu
Fie instantierile:
numae_clasa obiect1,obiect2;
…
O atribuire de forma:
obiect2 = obiect1 ;
este acceptata de compilator.
La atribuirea de obiecte,in mod implicit,se atribuie datele membru aleobiectului din dreapta operatorului = la datele membru corespunzatoare ale obiectului din stanga aceluiasi operator.Astfel de atribuiri se pot utiliza si in declaratii.
Exemplu:
class complex {
double real
double imag;
public :
complex (double x = 0, double y = 0 )
{
real = x ;
img = y ;
}
…
} ;
complex z (1,1) ; //z = 1+2I
complex z1 = z ; //z1 = 1 +2I
complex z2 ;
…
z2 = z1 ; //z2 = 1 +2I
Atat in cazul declaratiei lui z1 ,cat si in cazul instructiunii de atribuire pentru z2 , se copiaza componentele date ale obiectului complex din dreapta caracterului "“"”in zona de memorie alocata componentelor date ale obiectulu aflat in stanga aceluiasi caracter.
In cazul declaratiei lui z1 , caracterul “=” se utilizaeaza pentru a realiza o initializare , iar in cazul instructiunii:
z2 = z1 ;
acelasi carater se utilizeaza pentru a realiza o atribuire.
Ambele operatii sant definite in mod implicit si se realizeaza asa cum sa indicat mai sus,adica prin simpla copiere a datelor membru
B.Stroustrup numeste “bitwise copy” (copiere la nivel de biti) copierile de acelasi fel.
In cazul obiectelor clasei complex, copierea din cadrul operatiei de initializare este identica cu cea utilizata in cadrul operatiei de atribuire.
In general,cele doua operatii nu sant identice.De asemenea,copierea de tip “bitwise copy” nu este totdeauna suficienta.Acest fapt rezulta imediat daca reluam exemplul pentru implementarea tipului abstract string (vezi 22.90 sau sir (vezi exercitiul 22.12)
Consideram clasa sir,definita ca mai jos :
class sir {
char *psir ;
int lung ;
public :
sir (char *s ) ;
sir (int nrcar = 70 ) ;
int retlung ( ) ; //returneaza lungimea sirului
void afsir() ; // afiseaza sirul definit de psir
int citsir ( ) ; //citeste un sir de caractere
~sir ( ) {delete psir ; }
} ;
Functiile membru de mai sus ,sunt definte in exercitiul 22.12
Fie declaratia:
sir sir1 (“C++ este un C mai bun “);
La instantierea obiectului sir1 se apeleaza constructorul :
sir (char *s)
Acesta rezolva zona de memorie in memoria heap pentru textul:
C++ este un C mai bun
Si atribuie adresa de inceput a acestei zone pointerului:
sir1.psir
De asemene,se atribuie datei membru:
sir1.lung
valoarea 21 (numarul de caractere din compunearea textului de initializare a obiectului sir1,fara a considera si caracterul NUL).
Sa consideram declaratia pentru instantierea obiectului sir2 cu initializarea acestuia folosind obiectul sir1:
sir sir2 = sir1 ;
Utilizatorul foloseste o astfel de declaratie pentru a obtine acelasi efect ca si cand ar utiliza declaratia:
(2) sir sir2 (“C++ este un C mai bun”) ;
In realitate ,cele doua declaratii nu realizeaza acelasi lucru.
In cazul declaratiei (10,la instantierea lui sir2 se apeleaza
constructorul:
sir (int nrcar = 70 )
care rezerva o zona de memorie de 70 de octeti in care se pastreaza sirul vid.
Adresa de inceput a acestei zone se atribuie lui sir.psir ,apoi se copiaza cu bit(bitwise copy) valorile componentelor obiectului sir1 (sir1.psir si sir.lung) in zonele de memorie alocate componentelor corespunzatoare ale obiectului sir2.In felul acesta ,sir2.psir are acceasi valoare ca si sir1.psir.Zona de memmorie de 70 de octeti alocata in memmoria heap este pierduta si nu se mai poate face acces la ea.De asemenea ,textul de initializare este pastrat intr-un singur exemplar,situatie care,de obicei,va conduce la erori in prelucrarea ulterioara a obiectelor sir1 si sir2.
De asemenea,la distrugerea obiectelor sir1 si sir2 ar urma ca textul de initializare,pastrat intr-un singur exemplar,sa fie eliberat din memmoria heap de doua ori.De accea,copierea implicita bit cu bit a obiectelor nu este o solutie corecta pentru obiectele clasei sir.
Instantierea lui sir2 cu ajutorul decalaratiei (2) nu are nici o legatura cu instantierea lui sir1 si se rezerva o zona de memorie in memoria heap distincta fata de cea rezervata pentru acelasi text la instantierea lui sir1.De accea,
sir1.psir
si
sir2.psir
au valori diferite.
Acelasi lucru este valabil si in cazul atriburilor.Fie de exemplu instantierile:
sir1 sir1(“C++ este un C mai bun “);
sir sir2;
Ariburiea :
Sir2 = sir1 ;
realizeaza o copiere bit cu bit,deci sir1.psir si sir2.psir devin egale si pointeaza spre acceasi zona de memorie heap care a fost rezervata la instantierea lui sir1.Ca si in cazul declaratiei (2),zona de memorie din memoria heap alocata la instantierea lui sir2 este pierduta in urma atribuirii,deoarece ea devine inaccesibila.
Din cele de mai sus,rezulta ca pentru obiectele care sant instantieri ale clasei sir nu este suficienta copierea implcita bit cu bit.In astfel de cazuri este nevoie ca utilizatorul sa defineasca copieri specifice,care sa tina seama de natura componentelor obiectelor.
In general,operatia de initializare prin copiere direfita de cea de atribuire,deoarece initializarea este insotita de alocare.De accea,sant necesare doua tipuri de copieri,una care sa se realizeze la initializare prin copiere,adica declaratii de forma:
nume_clasa obiect2 = obiect1 ;
si una pentru atribuiri de obiecte:
obiect2 = obiect1
Initializarea prin copiere se realizeaza cu ajutorulconstructorului de copiere care a fost definit in paragraful 22.8.
Un astfel de constructor are un prototip de forma:
nume_clasa ( const nume_clasa & obiect ) ;
Mentionam ca,un astefel de constructor se apeleaza automat la instantierea unui obiect printr-o declaratie de forma (3).
Copierea bit cu bit se realizeaza numai dca clasa nu are un astfel de constructor.
Clasa sir, definita in exercitiul 22.12 .,are un constructor de copiere definit ca mai jos:
sir :: sir (sonst sir& s)
{
lung – s.lung ; //se copiaza ungimea sirului
//se aloca zona pentru sir
psir = new char [lung+1];
//se copiaza sirul in zonarezervata
strcpy (psir, s.psir);
}
Acest constructor se va apela automat la intalnirea declaratiei (1) si rezultatul lui consta in accea ca declaratia (1) are acelasi efect ca si declaratia (2).
Constructorul de copiere nu se apeleaza la atribuiri.
Pentru a solutiona in mod corect atribuirile de obiectede felul celor de mai sus , este necesar sa supraincarcam in mod corespunzatoroperatorul de atrbuire ( = ).
In principiu,constructorii de copiere si supraincarcarea operatorului de atribuire sant necesari pentru clasele care au ca date membru pointeri spre zone alocate in memoria heap (alocate dinamic)
Un alt caz in care se aloca obiecte temporare pe stiva se de accea intervin operatii similare cu cele de la initializare.
Pentru ca aceste transferuri de obiecte sa se faca corect pentru obiecte cu componente pointeri spre date din memoria heap ,este necesar sa avem constructor de copiere in clasa respectiva.
Acesta se va apela automat atat la transferul prin parametri a obiectelor precum si returnarea de obiecte,se realizeazaaplicand-se copierea implicia,adica copierea bit cu bit.
Un exemplu in care se utilizeaza copierea bit cu bit, la returnarea de obiecte,este clasa complex,implementat in exercitiul 22.1
In legatura cu supraincarcarea operatorului de atribuire este neecsar sa amintim urmatoarele:
= supraincarcarea operatorului de atribuire se poate realizanumai printr-o
functie membru care nu este statica ;
= obiectele operatorului se pot transfera prin valoare sau referinta;
= obiectul din stanga operatorului de atribuire,dca are componente pointeri
spre zone alocate in memoria heap trebuie eliberate inaite de a se aloca
zone noi in vederea copierii elementelor corespunzatoare ale obiectului
din dreapta operatorului respectiv;se obisnuieste sa se spuna ca obiectul
din stanga operatorului de atribuire trebuie “curatat” inainte de a se
atribui valorile obiectului din dreapta operatorului de atribuire.
De obicei , functia pentru supraincarcarea operatorului de atribuire are un parametru de tip referinta si returneaza o referinta la obiectul curent.Aceasta deoarece transferul prin referinta este mai eficient decat transferul obiectelor.
Avand in vedere acest fapt,se recomanda urmatorul antet pentru supraincarcarea operatorului de atribuire :
nume_clasa& nume_clasa::operator = (const nume_clasa & operand_drept)
Obiectul curent este operandul stand al atribuirii
O astfel de functie se apeleza automat pentru reazlizarea atriburilor de forma:
obiect2 = obiect1;
unde:
obiect1 si obiect2 – Sant instantieri ale clasei nume_clasa.
Atribuirile de forma:
obiect1 = obiect2 ;
Nu au nici un efect.De accea ,atrbuirile de acest fel se vor elimina.In acest scop,in corpul functiei pentru supraincarcarea operatorului de atrivuire se testeaza daca operatorul curent este diferit de cel referit prin parametrul si numai in acest caz se executa corpul functiei.
Folosind antetul de mai sus,un astfel de test se poate realiza astfel:
if(this != &operand_drept) {
//operanzi diferiti
…
}else //operanzi identici
return *this ;
Operatorul de atribuire are si o alta forma care se utilizeaza pentru a face prescurtari.Este vorba de formatul:
op=
unde:
op -Este un operator binar aritmetic sau logic pe biti.
Aceste variante pot fi ele supraincarcate in mod corespunzator.Mentionam ca,daca operatorii op si = sant supraincarcati,nu decurge ca este supraincarcat si operatorul op=.Acesta trebuie supraincarcat separat in mod corespunzator.
Operatorul op= se supraincarca folosind functii membru nestatice care au un prototip similar cu functiile pentru supraincarcarea operatorului de atribuire.
Exercitii:
23.14 Sa se implementeze tipul abstract sir pentru instantierea sirurilor de caractere.
Tipul sir a fost definit in exercitiul 22.12.
In exercitiul de fata,se schimba functia membru atribsir a clasei sir cu functia care supraincarca operatorulde atribuire.
In plus,se supraincarca operatorii + si += pentru concatenarea sirurilor de caractere.
Expresia:
sir1 = sir2 = sir3
este legata pentru obiectele clasei sir si ea atribuie lui sir1,sirul obtinut prin concatenarea lui sir3 la sfarsitul lui sir2.
Expresia
sir1 += sir2
este legata pentru obiectele clasei sir si ea are ca efect concatenarea lui sir2 la sfarsitul lui sir1.
FISIERUL BXXIII14.H
class sir {
char *psir ;
int lung ;
public:
sir(chat s); /* constructor pentru initializarea obiectului cu
pointerul spre copia in memoria heap a sirului spre
care pointeaza s */ 47832nkz77dyg2j
sir (int nrcar = 70); /* constructor care rezerva zona de
memorie in memoria heap si pastreaza
in ea sirul vid */ 47832nkz77dyg2j
sir (const sir&(; /*constructor de copiere */ 47832nkz77dyg2j
~sir () ; //destructor
int retlung(); //returneaza lungimea sirului
void afsir(); //afiseaza sirul
int citsir(); //citeste un sir de caractere
sir& operator = (const sir&); //supraincarca =
sir operator +(sir&); /* returneaza un obiect de tip sir obtinut
prin concatenarea prametrului la sfarsitul
obiectului curent */ 47832nkz77dyg2j
sir& operator += (sir&); /* concatenarea parametrului la
sfarsitul obiectuluicurent */ 47832nkz77dyg2j
};
Fisierul de mai jos este extensie .cpp si el contine definitiile functiilor membru.
FISIERUL BXXIII14
#ifndef __STDIO_H
#include <stdio.h>
#define __STDIO_H
#endif
#ifndef __STRING_H
#include <string.h>
#define __STRING_H
#endif
#idndef __SIR_H
#include “BXXIII14.H”
#define __SIR_H
#endif
sir::sir (chat *s)
/* constructor utilizat la initializarea obiectului cu pointerul spre copia in memoria heap a sirului spre care pointeaza s */ 47832nkz77dyg2j
{
lung = strlen(s); //lungimea sirului
psir = new chat[lung+1]; //rezerva zona in memoria heap
strcpy(psir,s); //transfera sirul in memoria heap
}
sir:::sir (int dim)
/*-constructor utilizat pentru a rezolva in memoria heap o zona de dim+1 octeti;
-pastreaza sirul vid in zona respectiva. */ 47832nkz77dyg2j
{
lung = dim ; //pastreaza lungimea
psir = new chat [lung+1]; //rezerva zona
*psir = ‘\0’;
}
sir::sir(const sir& s) //constructor de copiere
{
lung = s.lung ; //pastreaza lungimea sirului
psir = new chat [lung+1] ; //rezerva zona
strcpy(psir,s.psir); //copiaza sirul
}
inline sir::~sir //destructor
{
delete psir;
}
inline int sir::retlung()
/*returneaza numarul de caractere din compunerea sirului fara caracterul NUL */ 47832nkz77dyg2j
{
return lung;
}
inline void sir::afsir() //afiseaza sirul spre care pointea psir
{
printf(psir);
printf(,,\n”);
}
int sir:citsir()
/* -citeste un sir de la intrarea standard si-l pasteaza in zona heap rezervata pentru
obiectul curent;
-returneaza:
0 — la sfarsit de fisier;
-1 — la trunchiere;
1 — altfel
*/ 47832nkz77dyg2j
{
char temp [255];
if(gets(temp) = = 0) return 0 ; //s-a intalnit EOF
strncpy(psir,temp,lung); /* se copiaza sirul citit */ 47832nkz77dyg2j
*(psir+lung) = ‘\0’;
if (strlen (temp) >lung return –a; //truchiere
else return 1;
}
sir& sir::operator = (const sir & operand_drept)
//supraincarca operatorul =
{
if (this != &operand_drept){
//operanzi diferiti
delete psir ; //curata obiectul curent
lung = operand_drept.lung ; //pastreaza lungimea
psir = new char [lung+1]; //rezerva zona
//transfera sirul in zona rezervata
strncpy (psir,operand_drept.psir,lung);
*(psir+lung) = ‘\o’;
}
return *this ;
}
sir sir::operaot+ (sir& sir2)
/* returneaza un obiect care este rezultatul concatenarii obiectuluireferit de sir2 la
obiectul curent */ 47832nkz77dyg2j
{
sir rtemp;
delete rtemp.psir; //curata obiectul rtemp
rtemp.lung = lung; /* determina lungimea sirului rezultat */ 47832nkz77dyg2j
//reserva memorie pentru sirul rezultat
rtemp.psir = new char [rtemp.lung+1];
strcpy(rtemp.psir,psir); //transfera sirul curent
/*concateneaza sirul referit de sir2 la starsitul sirului spre care pointea rtemp.psir */ 47832nkz77dyg2j
return rtemp;
}
sir& sir ::operator += (sir& operand_drept(
/*concatenarea obiectului operand_drept la obiectul curent */ 47832nkz77dyg2j
{
/*pentru concatenare se utilizeaza operatorul + supraincarcat,iar pentru atribuire
operatorul = supraincarcat */ 47832nkz77dyg2j
*this = *this+operand_drept;
return *this:
}
23.15. Sa se scrie un program care citeste intregi din intervalul [1,99] si afiseaza exprimarile lor prin cuvinte.
Programul construieste exprimarea in cuvinte a numerelor din intervalul respectiv prin concatenarea compoentelor sale.
Exemple:
11 unsprezece
12 doisprezece
…
15 cincisprezece
16 saisprezece
17 saptesprezece
…
20 douazeci
21 douazeci si unu
22 douazeci si doi
…
29 douazeci si noua
30 treizeci
…
37 treizeci si sapte
…
40 patruzeci
…
45 patruzeci si cinci
…
60 saizeci
…
66 saizeci si sase
…
70 saptezeci
…
76 saptezeci si sase
…
99 nousazeci si noua
Se observa ca numerele peste 10,dar mai mici de 20 se termina in sufizul sprezece.De asemenea,daca consideram numerele de la 1 la 9,observam ca exprimarea in cuvinte a acestora se urilizeaza drept componentepentru exprimarea in cuvinte a numerelor maimari.Exista cateva exceptii,ca de exemplu:
11,16,20-29 etc.
Tinand seama de aceste observatii,vom proceda camai jos.
Se defineste tabloul cu denumirile unitatilor:
char *unitate[] = {
“ “ ,
“unu”,
“doi”,
………
“noua”
};
Pentru un numar n din intervalul [1,9] exprimarea este data de elementul unitate[n].
Pentru un numar n din intervalul [12,19] diferit de 16,exprimarea se obtine concatenand unitate[n/10] cu sprezece.
Pentru numerele n mai mari decat 20,exprimarile in cuvinte se termina prin:
Douazeci pentru 20-29
Treizeci pentru 30-39
Patruzeci pentru 40-49
Cincizeci pentru 50-59
Saizeci pentru 60-69
Saptezeci pentru 70-79
Optzeci pentru 80-89
Nouazeci pentru 90-99
Aceste cuvinte su sufixul zeci ,iar prefixul este un element al tabloului unitate,exceptand intervalele 20-29 si 60-69.Pentru primul interval prefizul este doua,iar pentru al doilea interval prefixul este sai.
Rezulta urmatorul procedeu:
daca n/10=2,atunci prefixul doua se concatenea cu zeci;
daca n/10=6,atunci prefixul sai se concateneaza cu zeci;
altfel unitate[n/10] se concateneaza cu zeci
PROGRAMUL BXXIII15
#include <stdlib.h>
#include “BXXIII14.CPP” //clasa sir
#include “BVIII2.CPP” //pcit_int
#include “BVIII3.CPP” //pcit_int_lim
main ()
/* -citeste intregi zecimali din intervalul [1,99[;
int n;
char *unit [] [ “ “ , “unu” , “doi” , “trei”
,”patru”,”cinci”,”sase”,”sapte”,”opt”,”noua”};
sir zece (“zece”);
sir spre (“spre”);
sir un (“un”);
sir sai (“sai”);
sir doua (“doua”);
sir zeci (“zeci”);
sir si (“si”);
sir rez;
int q,r;
for (;;) {
if (pcit_int_lim(“n = “,1,99,&n) = = 0)
exit(0);
q = n/10;
r = n%10;
switch (q) {
case 0 : { //[1,9]
sir rez0(unit [n]);
rez = rez0 ;
break ;
}
case 1: { //[10,19]
if ( n = = 10 ) rez = zece ;
else
if (n == 11) rez = un+spre+zece;
else
if (n = = 16) rez = sai+spre+zece;
else {
sir rez0(unit[r]);
rez = rez0+spre+zece;
}
break;
}
case 2 : { //[20-29]
rez = doua + zeci;
if (n = = 20) break;
rez += si;
sir rez0(unit[r]);
rez += rez0;
break;
}
case 6: { //[60-69]
rez =sai+zece;
if (n = = 60) break;
rez += rez- (unit[r]);
rez += rez0
break;
}
default : { //[30-39],[40-49],[50-59],[70-
79], [80-89],[90-99]
sir rez0 (unit [q]0;
if ( r = = 00 break;
rez += si;
sir rez1(unit[r]);
rez += rez1;
}
} //sfarsit switch
//afisare n si exprimare prin cuvinte
printf (“\n n = %d\t”,n);
rez.afsir();
}
}
Observatie :
Corpul functiri poate fi scris mai compact folosind instructiuni if in locul instructiunii switch:
if (q = = 00 //[1,9]
sir rez0(unit[n]);
rez=rez0;
}
else
if (q = =1) { //[10,19]
if (n = = 10) rez = zece;
else {
if (n= = 11 0 rez = un ;
else
if (n = = 160 rez = sai;
else {
sir rez0 (unit[r]);
rez=rez0
}
rez += spre + zece;
}
} //sfarsit [10,19]
else {
if (q = = 2) //[20,29]
rez = doua;
else
if (q = = 6) //[60,69]
rez = sai;
else{
sir rez0(unit[q]0;
rez=rez0;
}
rez += zeci;
if (r) {
sir rez0 (unit[r])
rez += si + rez0;
}
}
23.3 Supraincarcarea operatorului [] (operatorul de indexare)
Operatorul [] predefinit se utilizeaza pentru a face acces la elementele unui tablou.
De exemplu,daca tab este un tablou unidimensional de un tip predefinit,atunci o expresie de forma:
tab [exp]
permite acces la elementul tabloului tab de indice exp,exp fiind o expresie care furnizeaza o valoare de tip intreg.
Constructia (1) a fost numita ariabila cu indici.Ea este o expresie formata din doi operanzi:
tab si exp
la care se aplica operatorul de indexare ( [] ).De obicei, expresia (1) are si o interpretare unitara si anume se considera ca formand un operand.Aceasta interpretare este posibila datorita faptului ca parantezele sant operatori de prioritate maxima.
Interpretarea expresiei (1) ca operand se justifica datorita faptului ca ea area utilizari similare cu numele unei variabile simple;ambele permit acces la o data de un tip predefinit.
Constructia de mai sus este variabila si in cazuri mai generale,cand primul operand este chiar o expresie de pointeri,care are ca valoare un pointer.
Exemplu:
Int *p;
Int I,j;
Expresiile de mai jos sant legale:
p[1]
p[i]
p[i+2]
p[i-1]
(p+20[i*3+j]
(p-10)[i*3-2*j]
Utilizatorul poate supraincarca operatorul [] pentru a da sens constructiilor de felul celor de mai sus si in cazul in care operanzii sant obiecte.
Expresiile de forma (1) sunt expresii lvalue (se pot utiliza ca parte stanga intr-o atribuire).De accea,la supraincarcarea operatorului [] pentru tipuri abstracte,ca si la supraincarcarea operatorului = ,se va utiliza o functie membru nestatica,functie care sa returneze o referinta la elementul selectat prin functia respectiva.
In aceste conditii,functia pentru supraincarcarea operatorului [] are antetul general:
Tip & nume_clasa::operator[](tip_indice i)
Odata supraincarcat operatorul [] ca mai sus,sunt legate expresiile de forma:
obiect [exprsie]
unde:
obiect -Este o instatiere a clasei nume_clasa
expresie -Este o expresie care are tipul tip_indice sau un tip convertibil spre
acesta
Expresia (2) are ca rezultat o referinta la elementul definit prin functia care supraincarca operatorul [].Ea este o lvalue si deci se poate utiliza in ambele parti ale unei expresii de atribuire.De asemenea,expresia (2) se poate interpreta ca fiind un operand,neglijand faptul ca ea se compune din doi operanzi la care se aplica operatorul de indexare.
Operandul de aceasta forma reprezinta un apel al functiei membru operator[].
Astfel, operandul (2) de mai sus,se evalueaza prin apelul:
obiect.operator[] (expresie)
unde:
operator[] -Reprezinta numele functiei membru care supraincarca operatorul [] si ea este apelata pentru obiectul obiect si indicele expresie.
Interesul pentru formatul (2) fata de apelulexprimat prin (3) rezulta din faptul ca reprezinta o exprimare clara si care este incetatenita pentru tipurile predefinite de date.