Aula 11 Tipos Abstractos de Dados II. 2003/2004 Introdução à Programação 2 Estrutura global do...

Preview:

Citation preview

Aula 11

Tipos Abstractos de Dados II

2003/2004Introdução à Programação2

Estrutura global do programa

#include <iostream>#include <cassert>

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ê?

2003/2004Introdução à Programação3

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)

2003/2004Introdução à Programação4

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!

2003/2004Introdução à Programação5

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; };

2003/2004Introdução à Programação6

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)

2003/2004Introdução à Programação7

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()

2003/2004Introdução à Programação8

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()

2003/2004Introdução à Programação9

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

2003/2004Introdução à Programação10

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&

2003/2004Introdução à Programação11

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&

2003/2004Introdução à Programação12

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&

2003/2004Introdução à Programação13

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&

2003/2004Introdução à Programação14

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&

2003/2004Introdução à Programação15

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.

2003/2004Introdução à Programação16

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&

2003/2004Introdução à Programação17

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&

2003/2004Introdução à Programação18

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

2003/2004Introdução à Programação19

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 = 0denominador = 1

r2: Racional

numerador = 0denominador = 1

2003/2004Introdução à Programação20

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 = 0denominador = 1

r2: Racional

numerador = 0denominador = 1

2003/2004Introdução à Programação21

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 = 0denominador = 1

r2: Racional

numerador = 0denominador = 1

2003/2004Introdução à Programação22

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 = 0denominador = 1

r2: Racional

numerador = 0denominador = 1

Racional::lê()

Sem asserções, para encurtar.

*this: Racional&

2003/2004Introdução à Programação23

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 = 0denominador = 1

r2: Racional

numerador = 0denominador = 1

Racional::lê()

n: int

?

d: int

?

*this: Racional&

2003/2004Introdução à Programação24

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 = 0denominador = 1

r2: Racional

numerador = 0denominador = 1

Racional::lê()

n: int

?

d: int

?

n: int

6

d: int

9

*this: Racional&

2003/2004Introdução à Programação25

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 = 0denominador = 1

r2: Racional

numerador = 0denominador = 1

Racional::lê()

n: int

6

d: int

9

*this: Racional&

2003/2004Introdução à Programação26

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 = 0denominador = 1

r2: Racional

numerador = 0denominador = 1

Racional::lê()

n: int

6

d: int

9

*this: Racional&

2003/2004Introdução à Programação27

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 = 0denominador = 1

r2: Racional

numerador = 0denominador = 1

Racional::lê()

n: int

6

d: int

9

*this: Racional&

2003/2004Introdução à Programação28

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 = 0denominador = 1

r2: Racional

numerador = 0denominador = 1

Racional::lê()

n: int

6

d: int

9

*this: Racional&

2003/2004Introdução à Programação29

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 = 0denominador = 1

r2: Racional

numerador = 0denominador = 1

Racional::lê()

n: int

6

d: int

9

*this: Racional&

2003/2004Introdução à Programação30

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 = 0denominador = 1

r2: Racional

numerador = 0denominador = 1

Racional::lê()

n: int

6

d: int

9

*this: Racional&

r1: Racional

numerador = 6denominador = 1

2003/2004Introdução à Programação31

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 = 0denominador = 1

Racional::lê()

n: int

6

d: int

9

*this: Racional&

r1: Racional

numerador = 6denominador = 1

r1: Racional

numerador = 6denominador = 9

2003/2004Introdução à Programação32

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 = 0denominador = 1

Racional::lê()

n: int

6

d: int

9

*this: Racional&

r1: Racional

numerador = 6denominador = 1

r1: Racional

numerador = 6denominador = 9

2003/2004Introdução à Programação33

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 = 0denominador = 1

Racional::reduz()

*this: Racional&

r1: Racional

numerador = 6denominador = 1

r1: Racional

numerador = 6denominador = 9

2003/2004Introdução à Programação34

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 = 0denominador = 1

Racional::reduz()

*this: Racional&

r1: Racional

numerador = 6denominador = 1

r1: Racional

numerador = 6denominador = 9

divisor: int {frozen}

3

Ignoram-se asserções, para encurtar.

2003/2004Introdução à Programação35

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 = 0denominador = 1

Racional::reduz()

*this: Racional&

r1: Racional

numerador = 6denominador = 1

r1: Racional

numerador = 6denominador = 9

divisor: int {frozen}

3

r1: Racional

numerador = 2denominador = 9

2003/2004Introdução à Programação36

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 = 0denominador = 1

Racional::reduz()

*this: Racional&

r1: Racional

numerador = 2denominador = 9

divisor: int {frozen}

3

r1: Racional

numerador = 2denominador = 3

2003/2004Introdução à Programação37

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 = 0denominador = 1

Racional::reduz()

*this: Racional&

divisor: int {frozen}

3

r1: Racional

numerador = 2denominador = 3

2003/2004Introdução à Programação38

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 = 0denominador = 1

Racional::lê()

n: int

6

d: int

9

*this: Racional&

r1: Racional

numerador = 6denominador = 1

r1: Racional

numerador = 2denominador = 3

2003/2004Introdução à Programação39

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 = 2denominador = 3

r2: Racional

numerador = 0denominador = 1

r2: Racional

numerador = 7denominador = 3

2003/2004Introdução à Programação40

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 = 2denominador = 3

r2: Racional

numerador = 7denominador = 3

2003/2004Introdução à Programação41

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 = 2denominador = 3

r2: Racional

numerador = 7denominador = 3

Medonho…

2003/2004Introdução à Programação42

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 = 7denominador = 3

Racional::somaCom()

*this: Racional&

r1: Racional

numerador = 6denominador = 1

r1: Racional

numerador = 2denominador = 3

r2: Racional const&

2003/2004Introdução à Programação43

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 = 7denominador = 3

Racional::somaCom()

*this: Racional&

r1: Racional

numerador = 6denominador = 1

r1: Racional

numerador = 2denominador = 3

r2: Racional const&

r: Racional

numerador = 0denominador = 1

2003/2004Introdução à Programação44

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 = 7denominador = 3

Racional::somaCom()

*this: Racional&

r1: Racional

numerador = 6denominador = 1

r1: Racional

numerador = 2denominador = 3

r2: Racional const&

r: Racional

numerador = 0denominador = 1

r: Racional

numerador = 27denominador = 1

2003/2004Introdução à Programação45

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 = 7denominador = 3

Racional::somaCom()

*this: Racional&

r1: Racional

numerador = 6denominador = 1

r1: Racional

numerador = 2denominador = 3

r2: Racional const&

r: Racional

numerador = 27denominador = 1

r: Racional

numerador = 27denominador = 9

2003/2004Introdução à Programação46

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 = 7denominador = 3

Racional::somaCom()

*this: Racional&

r1: Racional

numerador = 6denominador = 1

r1: Racional

numerador = 2denominador = 3

r2: Racional const&

r: Racional

numerador = 27denominador = 9

Qual será a instância implícita?

r: Racional

numerador = 3denominador = 1

2003/2004Introdução à Programação47

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 = 7denominador = 3

Racional::somaCom()

*this: Racional&

r1: Racional

numerador = 6denominador = 1

r1: Racional

numerador = 2denominador = 3

r2: Racional const&

r: Racional

numerador = 3denominador = 1

2003/2004Introdução à Programação48

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 = 2denominador = 3

r2: Racional

numerador = 7denominador = 3

r: Racional

numerador = 3denominador = 1

É igual ao racional devolvido por Racional::somaCom(), mas não é a mesma instância!

2003/2004Introdução à Programação49

Traçado

Etc…..

2003/2004Introdução à Programação50

O nosso objectivo

#include <iostream>

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…

2003/2004Introdução à Programação51

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!

2003/2004Introdução à Programação52

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: …

};

2003/2004Introdução à Programação53

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; }

2003/2004Introdução à Programação54

Função main()

int main(){ …

// Calcular racional soma:

Racional r = r1.operator+(r2);

… }

2003/2004Introdução à Programação55

Função main()

int main(){ …

// Calcular racional soma:

Racional r = r1 + r2;

… }

2003/2004Introdução à Programação56

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)

2003/2004Introdução à Programação57

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.

2003/2004Introdução à Programação58

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!

2003/2004Introdução à Programação59

Um caso bicudo

int main(){ int i = 0; ++(++i); cout << i << endl;}

2003/2004Introdução à Programação60

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.

2003/2004Introdução à Programação61

Correcção…

int incrementa(int& v){ v = v + 1;

return v;}

int main(){ int i = 0; incrementa(incrementa(i)); cout << i << endl;}

2003/2004Introdução à Programação62

Funcionará?

int incrementa(int& v){ v = v + 1;

return v;}

int main(){ int i = 0; incrementa(incrementa(i)); cout << i << endl;}

2003/2004Introdução à Programação63

Funcionará?

int incrementa(int& v){ v = v + 1;

return v;}

int main(){ int i = 0; incrementa(incrementa(i)); cout << i << endl;}

main()

2003/2004Introdução à Programação64

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

2003/2004Introdução à Programação65

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

2003/2004Introdução à Programação66

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&

2003/2004Introdução à Programação67

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

2003/2004Introdução à Programação68

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!

2003/2004Introdução à Programação69

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

2003/2004Introdução à Programação70

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&

2003/2004Introdução à Programação71

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

2003/2004Introdução à Programação72

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

: int

2

Valor devolvido é cópia de v, i.e., é cópia da cópia alterada de i.

2003/2004Introdução à Programação73

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

: int

2

2003/2004Introdução à Programação74

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

2003/2004Introdução à Programação75

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

2003/2004Introdução à Programação76

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

2003/2004Introdução à Programação77

Em abono da verdade…

… o código nem sequer compila!

C++ proíbe referência (não constante) para instância temporária!

2003/2004Introdução à Programação78

Outra correcção…

int& incrementa(int& v){ v = v + 1;

return v;}

int main(){ int i = 0; incrementa(incrementa(i)); cout << i << endl;}

2003/2004Introdução à Programação79

E agora?

int& incrementa(int& v){ v = v + 1;

return v;}

int main(){ int i = 0; incrementa(incrementa(i)); cout << i << endl;}

2003/2004Introdução à Programação80

E agora?

int& incrementa(int& v){ v = v + 1;

return v;}

int main(){ int i = 0; incrementa(incrementa(i)); cout << i << endl;}

main()

2003/2004Introdução à Programação81

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

2003/2004Introdução à Programação82

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

2003/2004Introdução à Programação83

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&

2003/2004Introdução à Programação84

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

2003/2004Introdução à Programação85

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&

2003/2004Introdução à Programação86

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&

2003/2004Introdução à Programação87

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&

2003/2004Introdução à Programação88

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

2003/2004Introdução à Programação89

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&

: int&

2003/2004Introdução à Programação90

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&

: int&

2003/2004Introdução à Programação91

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

2003/2004Introdução à Programação92

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

2003/2004Introdução à Programação93

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!

2003/2004Introdução à Programação94

Operação Racional::operator++()/** … */class Racional { public: …

/** Incrementa o racional.

@pre *this = r.

@post operator++ = ? *this = r + 1. */ Racional& operator++();

private: …

};

2003/2004Introdução à Programação95

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?

2003/2004Introdução à Programação96

Método Racional::operator++()Racional& Racional::operator++() { assert(cumpreInvariante());

numerador += denominador;

assert(cumpreInvariante());

return *this; }

2003/2004Introdução à Programação97

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.

2003/2004Introdução à Programação98

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

2003/2004Introdução à Programação99

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!

2003/2004Introdução à Programação100

lvalue

Lvalue é uma entidade à qual se pode atribuir um valor

Instâncias temporárias não são lvalues, são rvalues

2003/2004Introdução à Programação101

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

Recommended