Carregar apresentação
A apresentação está carregando. Por favor, espere
PublicouJonathan Canas Alterado mais de 10 anos atrás
1
Aula 11 Tipos Abstractos de Dados II
2
2003/2004 Introdução à Programação 2 Estrutura global do programa #include using namespace std; int mdc(int const m, int const n) { … } class Racional { … }; Racional::Racional(int const n) { … } Racional::Racional(int const n, int const d) { … } void Racional::escreve() { … } Racional Racional::somaCom(Racional const& r2) { … } void Racional::lê() { … } void Racional::reduz() { … } bool Racional::cumpreInvariante() { … } int main() { … } Diferente! Porquê?
3
2003/2004 Introdução à Programação 3 TAD Racional (I) /** Representa números racionais. @invariant 0 < denominador mdc( numerador, denominador ) = 1. */ class Racional { public: /** Constrói racional com valor inteiro. @pre V. @post * this = n. */ Racional(int const n = 0); /** Constrói racional correspondente a n / d. @pre d 0. @post * this = n / d. */ Racional(int const n, int const d); /** Escreve um racional no ecrã no formato de uma fracção. @pre V. @post cout. fail () ou cout contém n/d (ou simplesmente n, se d = 1) em que n e d são os valores de numerador e denominador. */ void escreve(); (continua)
4
2003/2004 Introdução à Programação 4 TAD Racional (II) (continuação) /** Devolve a soma de dois racionais. @pre V. @post somaDe = * this + r2. */ Racional somaCom(Racional const& r2); /** Lê do teclado um racional, na forma de dois inteiros sucessivos. @pre * this = r. @post Se cin. good () cin tem dois inteiros n e d disponíveis para leitura, com d <> 0, então * this = n/d cin. fail (), senão * this = r cin. fail (). */ void lê(); (continua) Diferente!
5
2003/2004 Introdução à Programação 5 TAD Racional (III) (continuação) private: /** Indica se a CIC se verifica. @pre V. @post cumpreInvariante = 0 < denominador mdc( numerador, denominador ) = 1. */ bool cumpreInvariante(); /** Reduz a fracção que representa o racional. @pre denominador 0 *this = r. @post denominador 0 mdc( numerador, denominador ) = 1 * this = r. */ void reduz(); int numerador; int denominador; };
6
2003/2004 Introdução à Programação 6 Traçado int main() { // Ler fracções: cout << "Introduza duas fracções (numer … Racional r1, r2; r1.lê(); r2.lê(); if(cin.fail()) { cout << "Opps! A leitura dos racion … return 1; } (continua)
7
2003/2004 Introdução à Programação 7 Traçado int main() { // Ler fracções: cout << "Introduza duas fracções (numer … Racional r1, r2; r1.lê(); r2.lê(); if(cin.fail()) { cout << "Opps! A leitura dos racion … return 1; } (continua) main()
8
2003/2004 Introdução à Programação 8 Traçado int main() { // Ler fracções: cout << "Introduza duas fracções (numer … Racional r1, r2; r1.lê(); r2.lê(); if(cin.fail()) { cout << "Opps! A leitura dos racion … return 1; } (continua) Introduza … main()
9
2003/2004 Introdução à Programação 9 Traçado int main() { // Ler fracções: cout << "Introduza duas fracções (numer … Racional r1, r2; r1.lê(); r2.lê(); if(cin.fail()) { cout << "Opps! A leitura dos racion … return 1; } (continua) Introduza … main() r1 : Racional
10
2003/2004 Introdução à Programação 10 Traçado Racional::Racional(int const n) : numerador(n), denominador(1) { assert(cumpreInvariante()); } Introduza … Racional:: Racional() main() r1 : Racional n : int {frozen} 0 *this : Racional&
11
2003/2004 Introdução à Programação 11 Traçado Racional::Racional(int const n) : numerador(n), denominador(1) { assert(cumpreInvariante()); } Introduza … Racional:: Racional() main() r1 : Racional n : int {frozen} 0 numerador : int 0 *this : Racional&
12
2003/2004 Introdução à Programação 12 Traçado Racional::Racional(int const n) : numerador(n), denominador(1) { assert(cumpreInvariante()); } Introduza … Racional:: Racional() main() r1 : Racional n : int {frozen} 0 numerador : int 0 denominador : int 1 *this : Racional&
13
2003/2004 Introdução à Programação 13 Traçado Racional::Racional(int const n) : numerador(n), denominador(1) { assert(cumpreInvariante()); } Introduza … Racional:: Racional() main() r1 : Racional n : int {frozen} 0 numerador : int 0 denominador : int 1 *this : Racional&
14
2003/2004 Introdução à Programação 14 Traçado bool Racional::cumpreInvariante() { return 0 < denominador and mdc(numerador, denominador) == 1; } Introduza … Racional:: cumpreInvariante() main() r1 : Racional numerador : int 0 denominador : int 1 *this : Racional&
15
2003/2004 Introdução à Programação 15 Traçado bool Racional::cumpreInvariante() { return 0 < denominador and mdc(numerador, denominador) == 1; } Introduza … Racional:: cumpreInvariante() main() r1 : Racional numerador : int 0 denominador : int 1 *this : Racional& Devolve verdadeiro.
16
2003/2004 Introdução à Programação 16 Traçado Racional::Racional(int const n) : numerador(n), denominador(1) { assert(cumpreInvariante()); } Introduza … Racional:: Racional() main() r1 : Racional n : int 0 numerador : int 0 denominador : int 1 *this : Racional&
17
2003/2004 Introdução à Programação 17 Traçado Racional::Racional(int const n) : numerador(n), denominador(1) { assert(cumpreInvariante()); } Introduza … Racional:: Racional() main() r1 : Racional n : int 0 numerador : int 0 denominador : int 1 *this : Racional&
18
2003/2004 Introdução à Programação 18 Traçado int main() { // Ler fracções: cout << "Introduza duas fracções (numer … Racional r1, r2; r1.lê(); r2.lê(); if(cin.fail()) { cout << "Opps! A leitura dos racion … return 1; } (continua) Introduza … main() r1 : Racional numerador : int 0 denominador : int 1 r2 : Racional numerador : int 0 denominador : int 1
19
2003/2004 Introdução à Programação 19 Traçado int main() { // Ler fracções: cout << "Introduza duas fracções (numer … Racional r1, r2; r1.lê(); r2.lê(); if(cin.fail()) { cout << "Opps! A leitura dos racion … return 1; } (continua) Introduza … main() r1 : Racional numerador = 0 denominador = 1 r2 : Racional numerador = 0 denominador = 1
20
2003/2004 Introdução à Programação 20 Traçado int main() { // Ler fracções: cout << "Introduza duas fracções (numer … Racional r1, r2; r1.lê(); r2.lê(); if(cin.fail()) { cout << "Opps! A leitura dos racion … return 1; } (continua) Introduza … 6 9 7 3 main() r1 : Racional numerador = 0 denominador = 1 r2 : Racional numerador = 0 denominador = 1
21
2003/2004 Introdução à Programação 21 Traçado int main() { // Ler fracções: cout << "Introduza duas fracções (numer … Racional r1, r2; r1.lê(); r2.lê(); if(cin.fail()) { cout << "Opps! A leitura dos racion … return 1; } (continua) Introduza … 6 9 7 3 main() r1 : Racional numerador = 0 denominador = 1 r2 : Racional numerador = 0 denominador = 1
22
2003/2004 Introdução à Programação 22 Traçado void Racional::lê() { int n, d; cin >> n >> d; if(not cin.fail()) if(d == 0) cin.setstate(ios_base::failbit); else { if(d < 0) { numerador = -n; denominador = -d; } else { numerador = n; denominador = d; } reduz(); } Introduza … 6 9 7 3 main() r1 : Racional numerador = 0 denominador = 1 r2 : Racional numerador = 0 denominador = 1 Racional::lê() Sem asserções, para encurtar. *this : Racional&
23
2003/2004 Introdução à Programação 23 Traçado void Racional::lê() { int n, d; cin >> n >> d; if(not cin.fail()) if(d == 0) cin.setstate(ios_base::failbit); else { if(d < 0) { numerador = -n; denominador = -d; } else { numerador = n; denominador = d; } reduz(); } Introduza … 6 9 7 3 main() r1 : Racional numerador = 0 denominador = 1 r2 : Racional numerador = 0 denominador = 1 Racional::lê() n : int ? d : int ? *this : Racional&
24
2003/2004 Introdução à Programação 24 Traçado void Racional::lê() { int n, d; cin >> n >> d; if(not cin.fail()) if(d == 0) cin.setstate(ios_base::failbit); else { if(d < 0) { numerador = -n; denominador = -d; } else { numerador = n; denominador = d; } reduz(); } Introduza … 6 9 7 3 main() r1 : Racional numerador = 0 denominador = 1 r2 : Racional numerador = 0 denominador = 1 Racional::lê() n : int ? d : int ? n : int 6 d : int 9 *this : Racional&
25
2003/2004 Introdução à Programação 25 Traçado void Racional::lê() { int n, d; cin >> n >> d; if(not cin.fail()) if(d == 0) cin.setstate(ios_base::failbit); else { if(d < 0) { numerador = -n; denominador = -d; } else { numerador = n; denominador = d; } reduz(); } Introduza … 6 9 7 3 main() r1 : Racional numerador = 0 denominador = 1 r2 : Racional numerador = 0 denominador = 1 Racional::lê() n : int 6 d : int 9 *this : Racional&
26
2003/2004 Introdução à Programação 26 Traçado void Racional::lê() { int n, d; cin >> n >> d; if(not cin.fail()) if(d == 0) cin.setstate(ios_base::failbit); else { if(d < 0) { numerador = -n; denominador = -d; } else { numerador = n; denominador = d; } reduz(); } Introduza … 6 9 7 3 main() r1 : Racional numerador = 0 denominador = 1 r2 : Racional numerador = 0 denominador = 1 Racional::lê() n : int 6 d : int 9 *this : Racional&
27
2003/2004 Introdução à Programação 27 Traçado void Racional::lê() { int n, d; cin >> n >> d; if(not cin.fail()) if(d == 0) cin.setstate(ios_base::failbit); else { if(d < 0) { numerador = -n; denominador = -d; } else { numerador = n; denominador = d; } reduz(); } Introduza … 6 9 7 3 main() r1 : Racional numerador = 0 denominador = 1 r2 : Racional numerador = 0 denominador = 1 Racional::lê() n : int 6 d : int 9 *this : Racional&
28
2003/2004 Introdução à Programação 28 Traçado void Racional::lê() { int n, d; cin >> n >> d; if(not cin.fail()) if(d == 0) cin.setstate(ios_base::failbit); else { if(d < 0) { numerador = -n; denominador = -d; } else { numerador = n; denominador = d; } reduz(); } Introduza … 6 9 7 3 main() r1 : Racional numerador = 0 denominador = 1 r2 : Racional numerador = 0 denominador = 1 Racional::lê() n : int 6 d : int 9 *this : Racional&
29
2003/2004 Introdução à Programação 29 Traçado void Racional::lê() { int n, d; cin >> n >> d; if(not cin.fail()) if(d == 0) cin.setstate(ios_base::failbit); else { if(d < 0) { numerador = -n; denominador = -d; } else { numerador = n; denominador = d; } reduz(); } Introduza … 6 9 7 3 main() r1 : Racional numerador = 0 denominador = 1 r2 : Racional numerador = 0 denominador = 1 Racional::lê() n : int 6 d : int 9 *this : Racional&
30
2003/2004 Introdução à Programação 30 Traçado void Racional::lê() { int n, d; cin >> n >> d; if(not cin.fail()) if(d == 0) cin.setstate(ios_base::failbit); else { if(d < 0) { numerador = -n; denominador = -d; } else { numerador = n; denominador = d; } reduz(); } Introduza … 6 9 7 3 main() r1 : Racional numerador = 0 denominador = 1 r2 : Racional numerador = 0 denominador = 1 Racional::lê() n : int 6 d : int 9 *this : Racional& r1 : Racional numerador = 6 denominador = 1
31
2003/2004 Introdução à Programação 31 Traçado void Racional::lê() { int n, d; cin >> n >> d; if(not cin.fail()) if(d == 0) cin.setstate(ios_base::failbit); else { if(d < 0) { numerador = -n; denominador = -d; } else { numerador = n; denominador = d; } reduz(); } Introduza … 6 9 7 3 main() r2 : Racional numerador = 0 denominador = 1 Racional::lê() n : int 6 d : int 9 *this : Racional& r1 : Racional numerador = 6 denominador = 1 r1 : Racional numerador = 6 denominador = 9
32
2003/2004 Introdução à Programação 32 Traçado void Racional::lê() { int n, d; cin >> n >> d; if(not cin.fail()) if(d == 0) cin.setstate(ios_base::failbit); else { if(d < 0) { numerador = -n; denominador = -d; } else { numerador = n; denominador = d; } reduz(); } Introduza … 6 9 7 3 main() r2 : Racional numerador = 0 denominador = 1 Racional::lê() n : int 6 d : int 9 *this : Racional& r1 : Racional numerador = 6 denominador = 1 r1 : Racional numerador = 6 denominador = 9
33
2003/2004 Introdução à Programação 33 Traçado void Racional::reduz() { assert(denominador != 0); int const divisor = mdc(numerador, denominador); numerador /= divisor; denominador /= divisor; assert(denominador != 0); assert(mdc(numerador, denominador) == 1); } Introduza … 6 9 7 3 main() r2 : Racional numerador = 0 denominador = 1 Racional::reduz() *this : Racional& r1 : Racional numerador = 6 denominador = 1 r1 : Racional numerador = 6 denominador = 9
34
2003/2004 Introdução à Programação 34 Traçado void Racional::reduz() { assert(denominador != 0); int const divisor = mdc(numerador, denominador); numerador /= divisor; denominador /= divisor; assert(denominador != 0); assert(mdc(numerador, denominador) == 1); } Introduza … 6 9 7 3 main() r2 : Racional numerador = 0 denominador = 1 Racional::reduz() *this : Racional& r1 : Racional numerador = 6 denominador = 1 r1 : Racional numerador = 6 denominador = 9 divisor : int {frozen} 3 Ignoram-se asserções, para encurtar.
35
2003/2004 Introdução à Programação 35 Traçado void Racional::reduz() { assert(denominador != 0); int const divisor = mdc(numerador, denominador); numerador /= divisor; denominador /= divisor; assert(denominador != 0); assert(mdc(numerador, denominador) == 1); } Introduza … 6 9 7 3 main() r2 : Racional numerador = 0 denominador = 1 Racional::reduz() *this : Racional& r1 : Racional numerador = 6 denominador = 1 r1 : Racional numerador = 6 denominador = 9 divisor : int {frozen} 3 r1 : Racional numerador = 2 denominador = 9
36
2003/2004 Introdução à Programação 36 Traçado void Racional::reduz() { assert(denominador != 0); int const divisor = mdc(numerador, denominador); numerador /= divisor; denominador /= divisor; assert(denominador != 0); assert(mdc(numerador, denominador) == 1); } Introduza … 6 9 7 3 main() r2 : Racional numerador = 0 denominador = 1 Racional::reduz() *this : Racional& r1 : Racional numerador = 2 denominador = 9 divisor : int {frozen} 3 r1 : Racional numerador = 2 denominador = 3
37
2003/2004 Introdução à Programação 37 Traçado void Racional::reduz() { assert(denominador != 0); int const divisor = mdc(numerador, denominador); numerador /= divisor; denominador /= divisor; assert(denominador != 0); assert(mdc(numerador, denominador) == 1); } Introduza … 6 9 7 3 main() r2 : Racional numerador = 0 denominador = 1 Racional::reduz() *this : Racional& divisor : int {frozen} 3 r1 : Racional numerador = 2 denominador = 3
38
2003/2004 Introdução à Programação 38 Traçado void Racional::lê() { int n, d; cin >> n >> d; if(not cin.fail()) if(d == 0) cin.setstate(ios_base::failbit); else { if(d < 0) { numerador = -n; denominador = -d; } else { numerador = n; denominador = d; } reduz(); } Introduza … 6 9 7 3 main() r2 : Racional numerador = 0 denominador = 1 Racional::lê() n : int 6 d : int 9 *this : Racional& r1 : Racional numerador = 6 denominador = 1 r1 : Racional numerador = 2 denominador = 3
39
2003/2004 Introdução à Programação 39 Traçado int main() { // Ler fracções: cout << "Introduza duas fracções (numer … Racional r1, r2; r1.lê(); r2.lê(); if(cin.fail()) { cout << "Opps! A leitura dos racion … return 1; } (continua) Introduza … 6 9 7 3 main() r1 : Racional numerador = 2 denominador = 3 r2 : Racional numerador = 0 denominador = 1 r2 : Racional numerador = 7 denominador = 3
40
2003/2004 Introdução à Programação 40 Traçado int main() { // Ler fracções: cout << "Introduza duas fracções (numer … Racional r1, r2; r1.lê(); r2.lê(); if(cin.fail()) { cout << "Opps! A leitura dos racion … return 1; } (continua) Introduza … 6 9 7 3 main() r1 : Racional numerador = 2 denominador = 3 r2 : Racional numerador = 7 denominador = 3
41
2003/2004 Introdução à Programação 41 Traçado (continuação) // Calcular racional soma: Racional r = r1.somaCom(r2); // Escrever resultado: cout << "A soma de "; r1.escreve(); cout << " com "; r2.escreve(); cout << " é "; r.escreve(); cout << '.' << endl; } Introduza … 6 9 7 3 main() r1 : Racional numerador = 2 denominador = 3 r2 : Racional numerador = 7 denominador = 3 Medonho…
42
2003/2004 Introdução à Programação 42 Traçado Racional Racional::somaCom(Racional const& r2) { assert(cumpreInvariante()); assert(r2.cumpreInvariante()); Racional r; r.numerador = numerador * r2.denominador + r2.numerador * denominador; r.denominador = denominador * r2.denominador; r.reduz(); assert(cumpreInvariante()); assert(r.cumpreInvariante()); return r; } Introduza … 6 9 7 3 main() r2 : Racional numerador = 7 denominador = 3 Racional::somaCom() *this : Racional& r1 : Racional numerador = 6 denominador = 1 r1 : Racional numerador = 2 denominador = 3 r2 : Racional const&
43
2003/2004 Introdução à Programação 43 Traçado Racional Racional::somaCom(Racional const& r2) { assert(cumpreInvariante()); assert(r2.cumpreInvariante()); Racional r; r.numerador = numerador * r2.denominador + r2.numerador * denominador; r.denominador = denominador * r2.denominador; r.reduz(); assert(cumpreInvariante()); assert(r.cumpreInvariante()); return r; } Introduza … 6 9 7 3 main() r2 : Racional numerador = 7 denominador = 3 Racional::somaCom() *this : Racional& r1 : Racional numerador = 6 denominador = 1 r1 : Racional numerador = 2 denominador = 3 r2 : Racional const& r : Racional numerador = 0 denominador = 1
44
2003/2004 Introdução à Programação 44 Traçado Racional Racional::somaCom(Racional const& r2) { assert(cumpreInvariante()); assert(r2.cumpreInvariante()); Racional r; r.numerador = numerador * r2.denominador + r2.numerador * denominador; r.denominador = denominador * r2.denominador; r.reduz(); assert(cumpreInvariante()); assert(r.cumpreInvariante()); return r; } Introduza … 6 9 7 3 main() r2 : Racional numerador = 7 denominador = 3 Racional::somaCom() *this : Racional& r1 : Racional numerador = 6 denominador = 1 r1 : Racional numerador = 2 denominador = 3 r2 : Racional const& r : Racional numerador = 0 denominador = 1 r : Racional numerador = 27 denominador = 1
45
2003/2004 Introdução à Programação 45 Traçado Racional Racional::somaCom(Racional const& r2) { assert(cumpreInvariante()); assert(r2.cumpreInvariante()); Racional r; r.numerador = numerador * r2.denominador + r2.numerador * denominador; r.denominador = denominador * r2.denominador; r.reduz(); assert(cumpreInvariante()); assert(r.cumpreInvariante()); return r; } Introduza … 6 9 7 3 main() r2 : Racional numerador = 7 denominador = 3 Racional::somaCom() *this : Racional& r1 : Racional numerador = 6 denominador = 1 r1 : Racional numerador = 2 denominador = 3 r2 : Racional const& r : Racional numerador = 27 denominador = 1 r : Racional numerador = 27 denominador = 9
46
2003/2004 Introdução à Programação 46 Traçado Racional Racional::somaCom(Racional const& r2) { assert(cumpreInvariante()); assert(r2.cumpreInvariante()); Racional r; r.numerador = numerador * r2.denominador + r2.numerador * denominador; r.denominador = denominador * r2.denominador; r.reduz(); assert(cumpreInvariante()); assert(r.cumpreInvariante()); return r; } Introduza … 6 9 7 3 main() r2 : Racional numerador = 7 denominador = 3 Racional::somaCom() *this : Racional& r1 : Racional numerador = 6 denominador = 1 r1 : Racional numerador = 2 denominador = 3 r2 : Racional const& r : Racional numerador = 27 denominador = 9 Qual será a instância implícita? r : Racional numerador = 3 denominador = 1
47
2003/2004 Introdução à Programação 47 Traçado Racional Racional::somaCom(Racional const& r2) { assert(cumpreInvariante()); assert(r2.cumpreInvariante()); Racional r; r.numerador = numerador * r2.denominador + r2.numerador * denominador; r.denominador = denominador * r2.denominador; r.reduz(); assert(cumpreInvariante()); assert(r.cumpreInvariante()); return r; } Introduza … 6 9 7 3 main() r2 : Racional numerador = 7 denominador = 3 Racional::somaCom() *this : Racional& r1 : Racional numerador = 6 denominador = 1 r1 : Racional numerador = 2 denominador = 3 r2 : Racional const& r : Racional numerador = 3 denominador = 1
48
2003/2004 Introdução à Programação 48 Traçado (continuação) // Calcular racional soma: Racional r = r1.somaCom(r2); // Escrever resultado: cout << "A soma de "; r1.escreve(); cout << " com "; r2.escreve(); cout << " é "; r.escreve(); cout << '.' << endl; } Introduza … 6 9 7 3 main() r1 : Racional numerador = 2 denominador = 3 r2 : Racional numerador = 7 denominador = 3 r : Racional numerador = 3 denominador = 1 É igual ao racional devolvido por Racional::somaCom(), mas não é a mesma instância!
49
2003/2004 Introdução à Programação 49 Traçado Etc…..
50
2003/2004 Introdução à Programação 50 O nosso objectivo #include using namespace std; … int main() { cout << "Introduza duas fracções (numerador denominador): "; Racional r1, r2; cin >> r1 >> r2; if(cin.fail()) { cout << "Opps! A leitura dos racionais falhou!" << endl; return 1; } Racional r = r1 + r2; cout << "A soma de " << r1 << " com " << r2 << " é " << r << '.' << endl; } Hoje ficaremos mais próximos…
51
2003/2004 Introdução à Programação 51 Sobrecarga de operadores Sobrecarga de rotinas possível: int soma() int soma(int const a) int soma(int const a, int const b) Sobrecarga de operadores também!
52
2003/2004 Introdução à Programação 52 Operação Racional::operator+() /** … */ class Racional { public: … /** Devolve a soma de dois racionais. @pre V. @post somaDe = * this + r2. */ Racional operator+(Racional const& r2); … private: … };
53
2003/2004 Introdução à Programação 53 Método Racional::operator+() Racional Racional::operator+(Racional const& r2) { assert(cumpreInvariante()); assert(r2.cumpreInvariante()); Racional r; r.numerador = numerador * r2.denominador + r2.numerador * denominador; r.denominador = denominador * r2.denominador; r.reduz(); assert(cumpreInvariante()); assert(r.cumpreInvariante()); return r; }
54
2003/2004 Introdução à Programação 54 Função main() int main() { … // Calcular racional soma: Racional r = r1.operator+(r2); … }
55
2003/2004 Introdução à Programação 55 Função main() int main() { … // Calcular racional soma: Racional r = r1 + r2; … }
56
2003/2004 Introdução à Programação 56 Sobrecarga de operadores Como membro de classe: Primeiro operando é instância implícita! Outros operandos são passados como argumentos Racional Racional::operator+(Racional const& r2) Como rotina livre: Todos os operandos passados como argumentos Racional operator+(Racional const& r1, Racional const& r2)
57
2003/2004 Introdução à Programação 57 Operadores a sobrecarregar Aritméticos: Binários: *, /, + e - Unários: + e - Relacionais: e >= Igualdade e diferença: == e != Incrementação: Prefixo: ++ e -- Sufixo: ++ e -- Especiais de atribuição: *=, /=, += e -= Vamos começar por aqui.
58
2003/2004 Introdução à Programação 58 Um problema Que devolve o operador ++ prefixo? Exemplo: int i = 0; ++(++i); cout << i << endl; 2 Tem de resultar no próprio i, e não numa cópia. É um exemplo do que é possível fazer, e não uma sugestão de que é recomendável!
59
2003/2004 Introdução à Programação 59 Um caso bicudo int main() { int i = 0; ++(++i); cout << i << endl; }
60
2003/2004 Introdução à Programação 60 E um regresso às origens void incrementa(int& v) { v = v + 1; } int main() { int i = 0; incrementa(incrementa(i)); cout << i << endl; } Invocação impossível! incrementa() não devolve nada.
61
2003/2004 Introdução à Programação 61 Correcção… int incrementa(int& v) { v = v + 1; return v; } int main() { int i = 0; incrementa(incrementa(i)); cout << i << endl; }
62
2003/2004 Introdução à Programação 62 Funcionará? int incrementa(int& v) { v = v + 1; return v; } int main() { int i = 0; incrementa(incrementa(i)); cout << i << endl; }
63
2003/2004 Introdução à Programação 63 Funcionará? int incrementa(int& v) { v = v + 1; return v; } int main() { int i = 0; incrementa(incrementa(i)); cout << i << endl; } main()
64
2003/2004 Introdução à Programação 64 Funcionará? int incrementa(int& v) { v = v + 1; return v; } int main() { int i = 0; incrementa(incrementa(i)); cout << i << endl; } main() i : int 0
65
2003/2004 Introdução à Programação 65 Funcionará? int incrementa(int& v) { v = v + 1; return v; } int main() { int i = 0; incrementa(incrementa(i)); cout << i << endl; } main() i : int 0
66
2003/2004 Introdução à Programação 66 Funcionará? int incrementa(int& v) { v = v + 1; return v; } int main() { int i = 0; incrementa(incrementa(i)); cout << i << endl; } main() i : int 0 incrementa() v : int&
67
2003/2004 Introdução à Programação 67 Funcionará? int incrementa(int& v) { v = v + 1; return v; } int main() { int i = 0; incrementa(incrementa(i)); cout << i << endl; } main() i : int 0 incrementa() v : int& i : int 1
68
2003/2004 Introdução à Programação 68 Funcionará? int incrementa(int& v) { v = v + 1; return v; } int main() { int i = 0; incrementa(incrementa(i)); cout << i << endl; } main() incrementa() v : int& i : int 1 : int 1 Valor devolvido é cópia de v, i.e., é cópia de i. É instância temporária!
69
2003/2004 Introdução à Programação 69 Funcionará? int incrementa(int& v) { v = v + 1; return v; } int main() { int i = 0; incrementa(incrementa(i)); cout << i << endl; } main() i : int 1 : int 1
70
2003/2004 Introdução à Programação 70 Funcionará? int incrementa(int& v) { v = v + 1; return v; } int main() { int i = 0; incrementa(incrementa(i)); cout << i << endl; } main() i : int 1 : int 1 incrementa() v : int&
71
2003/2004 Introdução à Programação 71 Funcionará? int incrementa(int& v) { v = v + 1; return v; } int main() { int i = 0; incrementa(incrementa(i)); cout << i << endl; } main() i : int 1 : int 1 incrementa() v : int& : int 2
72
2003/2004 Introdução à Programação 72 Funcionará? int incrementa(int& v) { v = v + 1; return v; } int main() { int i = 0; incrementa(incrementa(i)); cout << i << endl; } main() i : int 1 incrementa() v : int& : int 2 2 Valor devolvido é cópia de v, i.e., é cópia da cópia alterada de i.
73
2003/2004 Introdução à Programação 73 Funcionará? int incrementa(int& v) { v = v + 1; return v; } int main() { int i = 0; incrementa(incrementa(i)); cout << i << endl; } main() i : int 1 : int 2 2
74
2003/2004 Introdução à Programação 74 Funcionará? int incrementa(int& v) { v = v + 1; return v; } int main() { int i = 0; incrementa(incrementa(i)); cout << i << endl; } main() i : int 1 1
75
2003/2004 Introdução à Programação 75 Funcionará? int incrementa(int& v) { v = v + 1; return v; } int main() { int i = 0; incrementa(incrementa(i)); cout << i << endl; } main() i : int 1 1
76
2003/2004 Introdução à Programação 76 Moral da história Segunda incrementação falhou Ou melhor, incrementou cópia Porque devolução faz-se por valor Necessário devolver por referência
77
2003/2004 Introdução à Programação 77 Em abono da verdade… … o código nem sequer compila! C++ proíbe referência (não constante) para instância temporária!
78
2003/2004 Introdução à Programação 78 Outra correcção… int& incrementa(int& v) { v = v + 1; return v; } int main() { int i = 0; incrementa(incrementa(i)); cout << i << endl; }
79
2003/2004 Introdução à Programação 79 E agora? int& incrementa(int& v) { v = v + 1; return v; } int main() { int i = 0; incrementa(incrementa(i)); cout << i << endl; }
80
2003/2004 Introdução à Programação 80 E agora? int& incrementa(int& v) { v = v + 1; return v; } int main() { int i = 0; incrementa(incrementa(i)); cout << i << endl; } main()
81
2003/2004 Introdução à Programação 81 E agora? int& incrementa(int& v) { v = v + 1; return v; } int main() { int i = 0; incrementa(incrementa(i)); cout << i << endl; } main() i : int 0
82
2003/2004 Introdução à Programação 82 E agora? int& incrementa(int& v) { v = v + 1; return v; } int main() { int i = 0; incrementa(incrementa(i)); cout << i << endl; } main() i : int 0
83
2003/2004 Introdução à Programação 83 E agora? int& incrementa(int& v) { v = v + 1; return v; } int main() { int i = 0; incrementa(incrementa(i)); cout << i << endl; } main() i : int 0 incrementa() v : int&
84
2003/2004 Introdução à Programação 84 E agora? int& incrementa(int& v) { v = v + 1; return v; } int main() { int i = 0; incrementa(incrementa(i)); cout << i << endl; } main() i : int 0 incrementa() v : int& i : int 1
85
2003/2004 Introdução à Programação 85 E agora? int& incrementa(int& v) { v = v + 1; return v; } int main() { int i = 0; incrementa(incrementa(i)); cout << i << endl; } main() incrementa() v : int& i : int 1 : int&
86
2003/2004 Introdução à Programação 86 E agora? int& incrementa(int& v) { v = v + 1; return v; } int main() { int i = 0; incrementa(incrementa(i)); cout << i << endl; } main() i : int 1 : int&
87
2003/2004 Introdução à Programação 87 E agora? int& incrementa(int& v) { v = v + 1; return v; } int main() { int i = 0; incrementa(incrementa(i)); cout << i << endl; } main() i : int 1 incrementa() v : int& : int&
88
2003/2004 Introdução à Programação 88 E agora? int& incrementa(int& v) { v = v + 1; return v; } int main() { int i = 0; incrementa(incrementa(i)); cout << i << endl; } main() i : int 1 incrementa() v : int& : int& i : int 2
89
2003/2004 Introdução à Programação 89 E agora? int& incrementa(int& v) { v = v + 1; return v; } int main() { int i = 0; incrementa(incrementa(i)); cout << i << endl; } main() i : int 2 incrementa() v : int& : int&
90
2003/2004 Introdução à Programação 90 E agora? int& incrementa(int& v) { v = v + 1; return v; } int main() { int i = 0; incrementa(incrementa(i)); cout << i << endl; } main() i : int 2 : int&
91
2003/2004 Introdução à Programação 91 E agora? int& incrementa(int& v) { v = v + 1; return v; } int main() { int i = 0; incrementa(incrementa(i)); cout << i << endl; } main() i : int 2 2
92
2003/2004 Introdução à Programação 92 E agora? int& incrementa(int& v) { v = v + 1; return v; } int main() { int i = 0; incrementa(incrementa(i)); cout << i << endl; } main() i : int 2 2
93
2003/2004 Introdução à Programação 93 Finalmente… sobrecarga! int& operator++(int& v) { v = v + 1; return v; } int main() { int i = 0; ++(++i); cout << i << endl; } Era doce… Não se pode redefinir os operadores dos tipos básicos! Mas para um TAD pode-se sobrecarregar!
94
2003/2004 Introdução à Programação 94 Operação Racional::operator++() /** … */ class Racional { public: … /** Incrementa o racional. @pre *this = r. @post operator++ = ? *this = r + 1. */ Racional& operator++(); … private: … };
95
2003/2004 Introdução à Programação 95 Método Racional::operator++() Racional& Racional::operator++() { assert(cumpreInvariante()); numerador += denominador; assert(cumpreInvariante()); return ?; } Porque não é necessário reduzir a fracção? Os TAD devem ter comportamente semelhante aos tipos básicos. Por isso, devia-se devolver o racional incrementado. Como?
96
2003/2004 Introdução à Programação 96 Método Racional::operator++() Racional& Racional::operator++() { assert(cumpreInvariante()); numerador += denominador; assert(cumpreInvariante()); return *this; }
97
2003/2004 Introdução à Programação 97 Operação Racional::operator++() /** … */ class Racional { public: … /** Incrementa o racional. @pre *this = r. @post operator++ *this *this = r + 1. */ Racional& operator++(); … private: … }; O que se devolve é a instância implícita ela própria, e não uma instância temporária com igual valor.
98
2003/2004 Introdução à Programação 98 Igualdade vs. identidade Duas instâncias São idênticas se forem a mesma instância São iguais se tiverem o mesmo valor Se são idênticas, são também iguais. Podem ser iguais, mas não ser idênticas
99
2003/2004 Introdução à Programação 99 Igualdade vs. identidade int cópia(int const& v) { return v; } int& mesmo(int& v) { return v; } int main() { int i = 0; mesmo(i) = 10; cópia(i) = 20; } Ok. Erro!
100
2003/2004 Introdução à Programação 100 lvalue Lvalue é uma entidade à qual se pode atribuir um valor Instâncias temporárias não são lvalues, são rvalues
101
2003/2004 Introdução à Programação 101 Aula 11: Sumário Revisões sobre a aula anterior *this como referência Construção dos atributos: lista de inicializadores Devolução por valor e por referência Noções de identidade e igualdade Diferença entre lvalue e rvalue Introdução à sobrecarga de operadores para TAD: operadores + binário e ++ prefixo
Apresentações semelhantes
© 2024 SlidePlayer.com.br Inc.
All rights reserved.