Metode evoluate de programare Limbajele c şi C++


Conversii definite de programator



Yüklə 1,64 Mb.
səhifə39/44
tarix07.04.2018
ölçüsü1,64 Mb.
#46828
1   ...   36   37   38   39   40   41   42   43   44

16.8. Conversii definite de programator




16.8.1. Efectuarea conversiilor

În mod automat în limbajele C şi C++ se aplică o conversie în următoarele trei situaţii:




  1. dacă un operator se referă la operanzi de tipuri diferite;

  2. dacă tipul parametrului actual al unei funcţii diferă de tipul parametrului formal corespunzător;

  3. dacă tipul valorii returnate de o funcţie, tip specificat în antetul funcţiei, diferă de tipul expresiei din instrucţiunea return.

În primul caz, dacă operatorul nu este de atribuire, se va folosi regula conversiilor implicite. Deci mai întâi tipurile char şi enum se convertesc în int, după care tipurile "inferioare" se convertesc spre cele "superioare" (de exemplu int în double). Dacă operatorul este de atribuire, atunci tipul expresiei din partea dreaptă se converteşte spre tipul expresiei din partea stângă. În cazul al doilea tipul parametrului actual se converteşte spre tipul parametrului formal. În cazul al treilea tipul expresiei din instrucţiunea return se converteşte spre tipul specificat în antetul funcţiei.



16.8.2. Conversii implicite definite de programator

Considerăm următorul exemplu referitor la clasa numerelor raţionale. Clasa va avea două date membru de tip long pentru memorarea numărătorului şi numitorului. Obiectele clasei se vor iniţializa printr-un constructor. Se va supraîncărca operatorul ~, care va efectua simplificarea fracţiei, şi operatorul *, pentru înmulţirea a două fracţii. Deasmenea, se va defini o funcţie membru afiseaza, pentru afişarea unei fracţii. Fişierul conv2.cpp:




Prin executarea programului se obţine:




Observăm că operatorul de înmulţire se poate folosi numai pentru înmulţirea a două numere raţionale. Deci în cazul unei expresii de forma următoare


z = x * 4;
compilatorul ar semnala o eroare. Totuşi ar fi de dorit ca expresiile de forma de mai sus, să fie corecte. Pentru a realiza acest lucru, trebuie definită o conversie implicită din tipul long în tipul fractie.

În general, conversiile dintr-un tip standard într-un tip abstract se realizează cu ajutorul unui constructor al tipului abstract. Constructorul trebuie să aibă un parametru, care aparţine tipului standard, iar dacă sunt şi alţi parametri, ei trebuie să fie iniţializaţi.

În cazul de mai sus constructorul, care realizează conversia din tipul long în tipul fractie, poate fi declarat sub forma:
fractie(long a, long b = 1);

sau


fractie(long a = 0, long b = 1);

sau


fractie(long a);
De exemplu, dacă fişierul conv2.cpp se modifică astfel încât constructorul să fie declarat în forma:

fractie(long a = 0, long b = 1);

atunci expresia

z = x * 4;

este corectă şi se obţine numărul raţional 8 / 5. Al doilea operand al operatorului de înmulţire trebuie să aparţină tipului fracţie. Cu ajutorul constructorului se va crea un obiect anonim fractie(4, 1), care se va folosi în locul operandului al doilea. Menţionăm, că de fapt s-au făcut două conversii. Constanta 4 este de tipul int, deci la apelarea constructorului s-a făcut o conversie de la tipul int la tipul long, după care s-a făcut o conversie din tipul long în tipul fractie, prin crearea obiectului anonim.

Totuşi compilatorul semnalizează o eroare la întâlnirea unei expresii de forma următoare:

z = 4 * x;

Explicaţia este, că în cazul expresiei x * 4, se apelează funcţia membru operator* pentru obiectul x. Însă în cazul expresiei 4 * x, se încearcă apelarea unei funcţii membru (operatorul de înmulţire) pentru constanta 4, ceea ce conduce la eroare.

O soluţie ar putea fi ca operatorul de înmulţire să se defineasă printr-o funcţie prieten, de exemplu în modul următor:
class fractie {

long numarator;

long numitor;

public:


...

friend fractie operator*(fractie p, fractie q);

...

};
fractie operator*(fractie p, fractie q)



{

return ~fractie(p.numarator*q.numarator,

p.numitor*q.numitor);

}
Dacă operatorul de înmulţire se defineşte în modul de mai sus, atunci ambele expresii x * 4 şi 4 * x vor fi corecte. Dezavantajul acestei metode este, că prin utilizarea unei funcţii prieten, gradul de protecţie a datelor scade. În continuare prezentăm o altă metodă de înlăturare a erorii de mai sus, astfel încât să nu fie nevoie de introducerea unei funcţii prieten. Vom defini o funcţie membru inmultire, care se va apela de către funcţia, care supraîncarcă operatorul de înmulţire.


class fractie {

long numarator;

long numitor;

public:


...

fractie inmultire(fractie r);

...

};
inline fractie fractie::inmultire(fractie r)



{

return ~fractie(numarator*r.numarator,

numitor*r.numitor);

}
fractie operator*(fractie p, fractie q)

{

return p.inmultire( q );



}
Observăm că şi în acest caz, ambele expresii sunt corecte şi nu s-a folosit funcţie prieten.

Definirea adecvată a constructorului poate să conducă şi la conversii dintr-un tip abstract într-un alt tip abstract. Prezentăm un exemplu pentru măsurarea unei lungimi, în care sunt definite două clase, folosind două unităţi de măsură diferite. Cu ajutorul clasei Lungime_m se va memora lungimea în metri (mm, cm, dm şi m), iar folosind clasa Lungime_inch memorarea lungimii se va realiza în inch (line, inch, foot şi yard). Relaţiile dintre cele două unităţi de măsură sunt următoarele:


1 line=2.54 mm1 inch=10 lines=2.54 cm1 foot=12 inches=30.48 cm1 yard=3 feet=91.44 cm

Deasemenea, programul va realiza conversia din inch în metri. Fişierul lung1.cpp:




Prin executarea programului se obţine:




Observăm, că şi în acest caz s-a folosit un constructor pentru realizarea conversiei din tipul Lungime_inch în tipul Lungime_m. Clasa Lungime_inch s a declarat înainte de clasa Lungime_m, deoarece constructorul, care realizează conversia, foloseşte tipul Lungime_inch.



16.8.3. Supraîncărcarea operatorului de conversie explicită

Conversia dintr-un tip abstract într-un tip standard se poate realiza prin supraîncărcarea operatorului de conversie explicită. Pentru a realiza conversia din tipul abstract Clasa în tipul standard tip_standard este necesară o funcţie membru de forma următoare:


class Clasa {

...


public:

...


operator tip_standard(); // declaraţie

...


};

Clasa::operator tip_standard()

{

...


return expresie; // se returnează o expresie având tipul

// tip_standard

}
Obiectul de tip Clasa se va converti în valoarea expresiei returnate de către funcţia membru, care supraîncarcă operatorul de conversie explicită. Menţionăm că în declaraţia funcţiei membru, care supraîncarcă operatorul de conversie explicită, nu trebuie specificat tipul, care se returnează, deoarece acest tip va fi întotdeauna tipul standard la care se face conversia. Dacă se încearcă specificarea tipului returnat, atunci compilatorul va semnala eroare. În următorul exemplu se va efectua conversia unui număr raţional într un număr de tip double. Fişierul conv3.cpp:


Prin executarea programului obţinem:




Menţionăm că dacă parametrul formal b al constructorului clasei fractie ar fi fost iniţializat, atunci ar fi apărut o eroare la compilare. Într-adevăr, în acest caz expresia x * 4.5 se poate evalua în următoarele două moduri:



  1. conversia variabilei x în tipul double şi efectuarea înmulţirii a două date de tip double;

  2. conversia constantei de tip double 4.5 în tipul long (cu trunchiere), urmată de conversia în tipul abstract fractie prin apelarea constructorului, şi efectuarea înmulţirii a două numere raţionale.

Deoarece evaluarea expresiei x * 4.5 se poate face în două moduri diferite, compilatorul nu poate evalua expresia, şi se va semnala o eroare.

Supraîncărcarea operatorului de conversie explicită se poate folosi şi pentru conversii dintr-un tip abstract într-un alt tip abstract. În continuare se va relua exemplul referitor la măsurarea unei lungimi în metri, respectiv în inch. Se va supraîncărca operatorul de conversie explicită din inch în metri. Fişierul lung2.cpp:




Observăm, că rezultatul obţinut după execuţie este identic cu cel al fişierului lung1.cpp. Menţionăm că în acest caz clasa Lungime_m trebuie declarată înainte de clasa Lungime_inch, deoarece tipul Lungime_m se foloseşte în cadrul clasei Lungime_inch.

În principiu conversia dintr-un tip abstract într-un alt tip abstract se poate realiza în două moduri: cu ajutorul unui constructor şi prin supraîncărcarea operatorul de conversie explicită. Însă în cazul unei aplicaţii concrete, numai unul din aceste două moduri poate fi folosit. În caz contrar compilatorul va semnala o eroare.


Yüklə 1,64 Mb.

Dostları ilə paylaş:
1   ...   36   37   38   39   40   41   42   43   44




Verilənlər bazası müəlliflik hüququ ilə müdafiə olunur ©muhaz.org 2024
rəhbərliyinə müraciət

gir | qeydiyyatdan keç
    Ana səhifə


yükləyin