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

Post on 17-Apr-2015

104 views 0 download

Transcript of Aula 13 Tipos Abstractos de Dados IV. 2003/2004 Introdução à Programação 2 Estrutura global do...

Aula 13

Tipos Abstractos de Dados IV

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

Estrutura global do programa (I)

#include <iostream>#include <cassert>

using namespace std;

/** Devolve o máximo divisor comum dos inteiros passados como argumento. @pre m ≠ 0 ou n ≠ 0. @post mdc = mdc(m, n). */int mdc(int const m, int const n) {…}

class Racional {…};

Racional::Racional(int const n) {…}

Racional::Racional(int const n, int const d) {…}

int Racional::numerador() {…}

int Racional::denominador() {…}

void Racional::escreve() {…}

(continua)(continua)

Construtores

Inspectores

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

Estrutura global do programa (II)

(continuação)(continuação)

void Racional::lê() {…}

Racional& Racional::operator++() {…}

Racional& Racional::operator--() {…}

Racional& Racional::operator*=(Racional const& r2) {…}

Racional& Racional::operator/=(Racional const& r2) {…}

Racional& Racional::operator+=(Racional const& r2) {…}

Racional& Racional::operator-=(Racional const& r2) {…}

void Racional::reduz() {…}

bool Racional::cumpreInvariante() {…}

(continua)(continua)

Modificadores

Auxiliares

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

Estrutura global do programa (III)

(continuação)(continuação)

/** Produto de dois racionais. @pre V. @post operator* = r1 × r2. */Racional const operator*(Racional r1, Racional const& r2) {…}

/** Divisão de dois racionais. @pre r2 ≠ 0. @post operator/ = r1 / r2. */Racional const operator/(Racional r1, Racional const& r2) {…} /** Soma de dois racionais. @pre V. @post operator+ = r1 + r2. */Racional const operator+(Racional r1, Racional const& r2) {…}

/** Subtracção de dois racionais. @pre V. @post operator- = r1 - r2. */Racional const operator-(Racional r1, Racional const& r2) {…}

(continua)(continua)

Operadores aritméticos

não-membro

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

Estrutura global do programa (IV)

(continuação)(continuação)

/** Indica se dois racionais são iguais.

@pre V.

@post operator== = (r1 = r2). */bool operator==(Racional const& r1, Racional const& r2) {…} /** Indica se dois racionais são diferentes.

@pre V.

@post operator!= = (r1 ≠ r2). */bool operator!=(Racional const& r1, Racional const& r2) {…}

int main() {…}

Operadores de igualdade e

diferençanão-membro

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

TAD Racional (construtores)

/** Representa números racionais.

@invariant 0 < denominador_ mdc(numerador_, denominador_) = 1. */class Racional { public: /** Constrói racional com valor inteiro.

@pre V.

@post *this = valor. */ Racional(int const valor = 0);

/** Constrói racional correspondente a numerador/denominador.

@pre denominador ≠ 0.

@post *this = numerador/denominador. */ Racional(int const numerador, int const denominador);

(continua)(continua)

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

TAD Racional (inspectores)

(continuação)(continuação) /** Devolve numerador da fracção mínima correspondente ao racional. @pre V. @post numerador/denominador() = *this. */ int numerador();

/** Devolve denominador da fracção mínima correspondente ao racional. @pre V. @post 0 < denominador (E n : V : n/denominador = *this mdc(n, denominador) = 1). */ int denominador();

/** 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)(continua)

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

TAD Racional (modificadores)

(continuação)(continuação) /** 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ê();

/** Incrementa o racional. @pre *this = r. @post operator++ ≡ *this *this = r + 1. */ Racional& operator++();

/** Decrementa o racional. @pre *this = r. @post operator-- ≡ *this *this = r - 1. */ Racional& operator--(); (continua)(continua)

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

TAD Racional (modificadores)

(continuação)(continuação) /** Multiplica por um racional.     @pre *this = r.     @post operator*= ≡ *this *this = r × r2. */ Racional& operator*=(Racional const& r2);

/** Divide por um racional.     @pre *this = r r2 ≠ 0.     @post operator/= ≡ *this *this = r / r2. */ Racional& operator/=(Racional const& r2);

/** Adiciona de um racional.     @pre *this = r.     @post operator+= ≡ *this *this = r + r2. */ Racional& operator+=(Racional const& r2);

/** Subtrai de um racional.     @pre *this = r.     @post operator-= ≡ *this *this = r - r2. */ Racional& operator-=(Racional const& r2);(continua)(continua)

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

TAD Racional (implementação)

(continuação)(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ção11

Constantes de TAD

Possível definir constantes de TAD:

Racional const um_terço(1, 3);

Mas é necessário ter alguns cuidados:

cout << um_terço.numerador() << endl;

Porque não

Racional const um_terço(1 / 3);

?

Dá erro!

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

Constantes de TAD

Compilador admite, por omissão, que as operações alteram a instância implícita

Se a instância implícita for constante, não se podem invocar operações??

Podem, mas apenas as operações que declararem explicitamente que não alteram a instância implícita, pois a tratam como constante

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

Operações que garantem constância: Sintaxe

class Classe { …

tipo operação(parâmetros) const; …

};

tipo Classe::operação(parâmetros) const { …

}

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

Operações que garantem constância: Semântica

Podem ser invocadas usando constantes:

Classe const constante;

constante.operação(argumentos);

Proibido para operações não constantes.

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

Operações que garantem constância: Semântica

Compilador impede método de fazer alterações aos atributos:

tipo Classe::operação(parâmetros) const{ …

atributoatributo = = ……;; …

} Proibido!

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

Operações que garantem constância: Semântica

Métodos não-constantes

*this é Classe&

Métodos constantes

*this é Classe const&

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

TAD Racional (construtores)

/** Representa números racionais.

@invariant 0 < denominador_ mdc(numerador_, denominador_) = 1. */class Racional { public: /** Constrói racional com valor inteiro.

@pre V.

@post *this = valor. */ Racional(int const valor = 0);

/** Constrói racional correspondente a numerador/denominador.

@pre denominador ≠ 0.

@post *this = numerador/denominador. */ Racional(int const numerador, int const denominador);

(continua)(continua)

Construtores não podem ser const, pois instância implícita é por eles inicializada!

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

TAD Racional (inspectores)

(continuação)(continuação) /** Devolve numerador da fracção mínima correspondente ao racional. @pre V. @post numerador/denominador() = *this. */ int numerador() const;

/** Devolve denominador da fracção mínima correspondente ao racional. @pre V. @post 0 < denominador (E n : V : n/denominador = *this mdc(n, denominador) = 1). */ int denominador() const;

/** 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() const; (continua)(continua)

Inspectores são sempre const!

Aos inspectores também se chama interrogações (queries)

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

TAD Racional (modificadores)

(continuação)(continuação) /** 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ê();

/** Incrementa o racional. @pre *this = r. @post operator++ ≡ *this *this = r + 1. */ Racional& operator++();

/** Decrementa o racional. @pre *this = r. @post operator-- ≡ *this *this = r - 1. */ Racional& operator--(); (continua)(continua)

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

TAD Racional (modificadores)

(continuação)(continuação) /** Multiplica por um racional.     @pre *this = r.     @post operator*= ≡ *this *this = r × r2. */ Racional& operator*=(Racional const& r2);

/** Divide por um racional.     @pre *this = r r2 ≠ 0.     @post operator/= ≡ *this *this = r / r2. */ Racional& operator/=(Racional const& r2);

/** Adiciona de um racional.     @pre *this = r.     @post operator+= ≡ *this *this = r + r2. */ Racional& operator+=(Racional const& r2);

/** Subtrai de um racional.     @pre *this = r.     @post operator-= ≡ *this *this = r - r2. */ Racional& operator-=(Racional const& r2);(continua)(continua)

Modificadores nunca são const!

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

TAD Racional (implementação)

(continuação)(continuação) private: /** Indica se a CIC se verifica.      @pre V.      @post  cumpreInvariante = 0 < denominador_ mdc(numerador_, denominador_) = 1. */ bool cumpreInvariante() const;

/** 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ção22

Métodos afectados

int Racional::numerador() const {…}

int Racional::denominador() const {…}

void Racional::escreve() const {…}

bool Racional::cumpreInvariante() const {…}

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

Métodos afectados

void Racional::escreve() const { assert(cumpreInvariante());

cout << numerador(); if(denominador() != 1) cout << '/' << denominador();

assert(cumpreInvariante());} Desnecessário! Num método

constante, se o invariante se verifica no início (para a instância implícita), também se verifica no fim.

(Hmmm… Há excepções. )

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

Métodos afectados

void Racional::escreve() const { assert(cumpreInvariante());

cout << numerador(); if(denominador() != 1) cout << '/' << denominador(); }

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

Atenção!

Utilização sistemática de const tem grandes vantagens: Obriga programador a pensar

(menos erros) Programador explicita informação acerca do

programa, que o compilador usa para detectar incoerências (erros detectados mais facilmente)

Erros ocorrem mais cedo, durante compilação (erros detectados mais cedo)

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

Desafio

Quantas invocações de rotinas estão envolvidas em

Racional r(1, 3);

Racional s = r + 2;

ignorando asserções?

Dica:

Quando se constrói um racional à custa de outro, é invocado um construtor por cópia, fornecido automaticamente pelo compilador, e que se limita a copiar os atributos um a um.

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

Construtor Racional::Racional()Racional::Racional(int const n) : numerador(n), denominador(1){

assert(cumpreInvariante()); assert(cumpreInvariante());

assert(numerador() == n * denominador());assert(numerador() == n * denominador());}

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

Construtor Racional::Racional()Racional::Racional(int const n, int const d){ assert(d != 0); assert(d != 0);

if(d < 0) { numerador_ = -n; denominador_ = -d; } else { numerador_ = n; denominador_ = d; }

reduz();

assert(cumpreInvariante());assert(cumpreInvariante()); assert(numerador() * d == n * denominador());assert(numerador() * d == n * denominador());}

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

Inspector Racional::numerador()int Racional::numerador() const{ assert(cumpreInvariante()); assert(cumpreInvariante());

return numerador_; }

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

Inspector Racional::denominador()int Racional::denominador() const{ assert(cumpreInvariante()); assert(cumpreInvariante());

return denominador_; }

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

Operador Racional::operator+=()Racional& Racional::operator+=(Racional const& r2) { assert(cumpreInvariante());assert(cumpreInvariante()); assert(r2.cumpreInvariante()); assert(r2.cumpreInvariante());

numerador_ = numerador() * r2.denominador() + r2.numerador() * denominador(); denominador_ *= r2.denominador();

reduz();

assert(cumpreInvariante()); assert(cumpreInvariante());

return *this; }

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

Método auxiliar Racional::reduz()void Racional::reduz(){ assert(denominador_ != 0); assert(denominador_ != 0);

int const divisor = mdc(numerador_, denominador_);

numerador_ /= divisor; denominador_ /= divisor;

assert(denominador_ != 0);assert(denominador_ != 0);

assert(mdc(numerador_, denominador_) == 1);assert(mdc(numerador_, denominador_) == 1);}

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

Operador Racional::operator+()Racional const operator+(Racional r1, Racional const& r2) { r1 += r2;

return r1; }

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

Operador Racional::operator==()bool operator==(Racional const& r1, Racional const& r2) { return r1.numerador() == r2.numerador() and r1.denominador() == r2.denominador(); }

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

Traçado

Racional r(1, 3);

Racional s = r + 2;

Número de invocações:

0

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

Traçado

Racional::Racional(int const n, int const d){ assert(d != 0); assert(d != 0);

if(d < 0) { numerador_ = -n; denominador_ = -d; } else { numerador_ = n; denominador_ = d; }

reduz();

assert(cumpreInvariante());assert(cumpreInvariante()); assert(numerador() * d == n * denominador());assert(numerador() * d == n * denominador());}

Número de invocações:

1

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

Traçado

Racional::Racional(int const n, int const d){ assert(d != 0); assert(d != 0);

if(d < 0) { numerador_ = -n; denominador_ = -d; } else { numerador_ = n; denominador_ = d; }

reduz();

assert(cumpreInvariante());assert(cumpreInvariante()); assert(numerador() * d == n * denominador());assert(numerador() * d == n * denominador());}

Número de invocações:

1

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

Traçado

Racional::Racional(int const n, int const d){ assert(d != 0); assert(d != 0);

if(d < 0) { numerador_ = -n; denominador_ = -d; } else { numerador_ = n; denominador_ = d; }

reduz();

assert(cumpreInvariante());assert(cumpreInvariante()); assert(numerador() * d == n * denominador());assert(numerador() * d == n * denominador());}

Número de invocações:

1

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

Traçado

Racional::Racional(int const n, int const d){ assert(d != 0); assert(d != 0);

if(d < 0) { numerador_ = -n; denominador_ = -d; } else { numerador_ = n; denominador_ = d; }

reduz();

assert(cumpreInvariante());assert(cumpreInvariante()); assert(numerador() * d == n * denominador());assert(numerador() * d == n * denominador());}

Número de invocações:

1

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

Traçado

Racional::Racional(int const n, int const d){ assert(d != 0); assert(d != 0);

if(d < 0) { numerador_ = -n; denominador_ = -d; } else { numerador_ = n; denominador_ = d; }

reduz();

assert(cumpreInvariante());assert(cumpreInvariante()); assert(numerador() * d == n * denominador());assert(numerador() * d == n * denominador());}

Número de invocações:

1

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

Traçado

Racional::Racional(int const n, int const d){ assert(d != 0); assert(d != 0);

if(d < 0) { numerador_ = -n; denominador_ = -d; } else { numerador_ = n; denominador_ = d; }

reduz();

assert(cumpreInvariante());assert(cumpreInvariante()); assert(numerador() * d == n * denominador());assert(numerador() * d == n * denominador());}

Número de invocações:

1

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

Traçado

void Racional::reduz(){ assert(denominador_ != 0); assert(denominador_ != 0);

int const divisor = mdc(numerador_, denominador_);

numerador_ /= divisor; denominador_ /= divisor;

assert(denominador_ != 0);assert(denominador_ != 0);

assert(mdc(numerador_, denominador_) == 1);assert(mdc(numerador_, denominador_) == 1);}

Número de invocações:

2

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

Traçado

void Racional::reduz(){ assert(denominador_ != 0); assert(denominador_ != 0);

int const divisor = mdc(numerador_, denominador_);

numerador_ /= divisor; denominador_ /= divisor;

assert(denominador_ != 0);assert(denominador_ != 0);

assert(mdc(numerador_, denominador_) == 1);assert(mdc(numerador_, denominador_) == 1);}

Número de invocações:

2

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

Traçado

int mdc(int const m, int const n){ …

}

Número de invocações:

3

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

Traçado

int mdc(int const m, int const n){ …

}

Número de invocações:

3

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

Traçado

void Racional::reduz(){ assert(denominador_ != 0); assert(denominador_ != 0);

int const divisor = mdc(numerador_, denominador_);

numerador_ /= divisor; denominador_ /= divisor;

assert(denominador_ != 0);assert(denominador_ != 0);

assert(mdc(numerador_, denominador_) == 1);assert(mdc(numerador_, denominador_) == 1);}

Número de invocações:

3

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

Traçado

void Racional::reduz(){ assert(denominador_ != 0); assert(denominador_ != 0);

int const divisor = mdc(numerador_, denominador_);

numerador_ /= divisor; denominador_ /= divisor;

assert(denominador_ != 0);assert(denominador_ != 0);

assert(mdc(numerador_, denominador_) == 1);assert(mdc(numerador_, denominador_) == 1);}

Número de invocações:

3

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

Traçado

void Racional::reduz(){ assert(denominador_ != 0); assert(denominador_ != 0);

int const divisor = mdc(numerador_, denominador_);

numerador_ /= divisor; denominador_ /= divisor;

assert(denominador_ != 0);assert(denominador_ != 0);

assert(mdc(numerador_, denominador_) == 1);assert(mdc(numerador_, denominador_) == 1);}

Número de invocações:

3

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

Traçado

void Racional::reduz(){ assert(denominador_ != 0); assert(denominador_ != 0);

int const divisor = mdc(numerador_, denominador_);

numerador_ /= divisor; denominador_ /= divisor;

assert(denominador_ != 0);assert(denominador_ != 0);

assert(mdc(numerador_, denominador_) == 1);assert(mdc(numerador_, denominador_) == 1);}

Número de invocações:

3

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

Traçado

Racional::Racional(int const n, int const d){ assert(d != 0); assert(d != 0);

if(d < 0) { numerador_ = -n; denominador_ = -d; } else { numerador_ = n; denominador_ = d; }

reduz();

assert(cumpreInvariante());assert(cumpreInvariante()); assert(numerador() * d == n * denominador());assert(numerador() * d == n * denominador());}

Número de invocações:

3

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

Traçado

Racional r(1, 3);

Racional s = r + 2;

Número de invocações:

3

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

Traçado

Racional::Racional(int const n) : numerador(n), denominador(1){

assert(cumpreInvariante()); assert(cumpreInvariante());

assert(numerador() == n * denominador());assert(numerador() == n * denominador());}

Número de invocações:

4

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

Traçado

Racional::Racional(int const n) : numerador(n), denominador(1){

assert(cumpreInvariante()); assert(cumpreInvariante());

assert(numerador() == n * denominador());assert(numerador() == n * denominador());}

Número de invocações:

4

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

Traçado

Racional r(1, 3);

Racional s = r + 2;

Número de invocações:

4

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

Traçado

Racional const operator+(Racional r1, Racional const& r2) { r1 += r2;

return r1; }

Passagem por valor implica cópia!

Número de invocações:

5

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

Traçado

Racional::Racional(Racional const& original) : numerador_(original.numerador_), denominador_(original.denominador_){}

Construtor por cópia fornecido automaticamente pelo compilador.

Número de invocações:

6

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

Traçado

Racional::Racional(Racional const& original) : numerador_(original.numerador_), denominador_(original.denominador_){}

Número de invocações:

6

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

Traçado

Racional const operator+(Racional r1, Racional const& r2) { r1 += r2;

return r1; }

Número de invocações:

6

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

Traçado

Racional& Racional::operator+=(Racional const& r2) { assert(cumpreInvariante());assert(cumpreInvariante()); assert(r2.cumpreInvariante()); assert(r2.cumpreInvariante());

numerador_ = numerador() * r2.denominador() + r2.numerador() * denominador(); denominador_ *= r2.denominador();

reduz();

assert(cumpreInvariante()); assert(cumpreInvariante());

return *this; }

Número de invocações:

7

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

Traçado

Racional& Racional::operator+=(Racional const& r2) { assert(cumpreInvariante());assert(cumpreInvariante()); assert(r2.cumpreInvariante()); assert(r2.cumpreInvariante());

numerador_ = numerador() * r2.denominador() + r2.numerador() * denominador(); denominador_ *= r2.denominador();

reduz();

assert(cumpreInvariante()); assert(cumpreInvariante());

return *this; }

Número de invocações:

7

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

Traçado

int Racional::numerador() const{ assert(cumpreInvariante()); assert(cumpreInvariante());

return numerador_; }

Número de invocações:

8

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

Traçado

int Racional::numerador() const{ assert(cumpreInvariante()); assert(cumpreInvariante());

return numerador_; }

Número de invocações:

8

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

Traçado

Racional& Racional::operator+=(Racional const& r2) { assert(cumpreInvariante());assert(cumpreInvariante()); assert(r2.cumpreInvariante()); assert(r2.cumpreInvariante());

numerador_ = numerador() * r2.denominador() + r2.numerador() * denominador(); denominador_ *= r2.denominador();

reduz();

assert(cumpreInvariante()); assert(cumpreInvariante());

return *this; }

Número de invocações:

8

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

Traçado

int Racional::denominador() const{ assert(cumpreInvariante()); assert(cumpreInvariante());

return denominador_; }

Número de invocações:

9

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

Traçado

int Racional::denominador() const{ assert(cumpreInvariante()); assert(cumpreInvariante());

return denominador_; }

Número de invocações:

9

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

Traçado

Racional& Racional::operator+=(Racional const& r2) { assert(cumpreInvariante());assert(cumpreInvariante()); assert(r2.cumpreInvariante()); assert(r2.cumpreInvariante());

numerador_ = numerador() * r2.denominador() + r2.numerador() * denominador(); denominador_ *= r2.denominador();

reduz();

assert(cumpreInvariante()); assert(cumpreInvariante());

return *this; }

Número de invocações:

9

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

Traçado

int Racional::numerador() const{ assert(cumpreInvariante()); assert(cumpreInvariante());

return numerador_; }

Número de invocações:

10

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

Traçado

int Racional::numerador() const{ assert(cumpreInvariante()); assert(cumpreInvariante());

return numerador_; }

Número de invocações:

10

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

Traçado

Racional& Racional::operator+=(Racional const& r2) { assert(cumpreInvariante());assert(cumpreInvariante()); assert(r2.cumpreInvariante()); assert(r2.cumpreInvariante());

numerador_ = numerador() * r2.denominador() + r2.numerador() * denominador(); denominador_ *= r2.denominador();

reduz();

assert(cumpreInvariante()); assert(cumpreInvariante());

return *this; }

Número de invocações:

10

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

Traçado

int Racional::denominador() const{ assert(cumpreInvariante()); assert(cumpreInvariante());

return denominador_; }

Número de invocações:

11

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

Traçado

int Racional::denominador() const{ assert(cumpreInvariante()); assert(cumpreInvariante());

return denominador_; }

Número de invocações:

11

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

Traçado

Racional& Racional::operator+=(Racional const& r2) { assert(cumpreInvariante());assert(cumpreInvariante()); assert(r2.cumpreInvariante()); assert(r2.cumpreInvariante());

numerador_ = numerador() * r2.denominador() + r2.numerador() * denominador(); denominador_ *= r2.denominador();

reduz();

assert(cumpreInvariante()); assert(cumpreInvariante());

return *this; }

Número de invocações:

11

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

Traçado

Racional& Racional::operator+=(Racional const& r2) { assert(cumpreInvariante());assert(cumpreInvariante()); assert(r2.cumpreInvariante()); assert(r2.cumpreInvariante());

numerador_ = numerador() * r2.denominador() + r2.numerador() * denominador(); denominador_ *= r2.denominador();

reduz();

assert(cumpreInvariante()); assert(cumpreInvariante());

return *this; }

Número de invocações:

11

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

Traçado

int Racional::denominador() const{ assert(cumpreInvariante()); assert(cumpreInvariante());

return denominador_; }

Número de invocações:

12

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

Traçado

int Racional::denominador() const{ assert(cumpreInvariante()); assert(cumpreInvariante());

return denominador_; }

Número de invocações:

12

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

Traçado

Racional& Racional::operator+=(Racional const& r2) { assert(cumpreInvariante());assert(cumpreInvariante()); assert(r2.cumpreInvariante()); assert(r2.cumpreInvariante());

numerador_ = numerador() * r2.denominador() + r2.numerador() * denominador(); denominador_ *= r2.denominador();

reduz();

assert(cumpreInvariante()); assert(cumpreInvariante());

return *this; }

Número de invocações:

12

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

Traçado

Racional& Racional::operator+=(Racional const& r2) { assert(cumpreInvariante());assert(cumpreInvariante()); assert(r2.cumpreInvariante()); assert(r2.cumpreInvariante());

numerador_ = numerador() * r2.denominador() + r2.numerador() * denominador(); denominador_ *= r2.denominador();

reduz();

assert(cumpreInvariante()); assert(cumpreInvariante());

return *this; }

Número de invocações:

12

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

Traçado

void Racional::reduz(){ assert(denominador_ != 0); assert(denominador_ != 0);

int const divisor = mdc(numerador_, denominador_);

numerador_ /= divisor; denominador_ /= divisor;

assert(denominador_ != 0);assert(denominador_ != 0);

assert(mdc(numerador_, denominador_) == 1);assert(mdc(numerador_, denominador_) == 1);}

Número de invocações:

13

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

Traçado

void Racional::reduz(){ assert(denominador_ != 0); assert(denominador_ != 0);

int const divisor = mdc(numerador_, denominador_);

numerador_ /= divisor; denominador_ /= divisor;

assert(denominador_ != 0);assert(denominador_ != 0);

assert(mdc(numerador_, denominador_) == 1);assert(mdc(numerador_, denominador_) == 1);}

Número de invocações:

13

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

Traçado

int mdc(int const m, int const n){ …

}

Número de invocações:

14

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

Traçado

int mdc(int const m, int const n){ …

}

Número de invocações:

14

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

Traçado

void Racional::reduz(){ assert(denominador_ != 0); assert(denominador_ != 0);

int const divisor = mdc(numerador_, denominador_);

numerador_ /= divisor; denominador_ /= divisor;

assert(denominador_ != 0);assert(denominador_ != 0);

assert(mdc(numerador_, denominador_) == 1);assert(mdc(numerador_, denominador_) == 1);}

Número de invocações:

14

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

Traçado

void Racional::reduz(){ assert(denominador_ != 0); assert(denominador_ != 0);

int const divisor = mdc(numerador_, denominador_);

numerador_ /= divisor; denominador_ /= divisor;

assert(denominador_ != 0);assert(denominador_ != 0);

assert(mdc(numerador_, denominador_) == 1);assert(mdc(numerador_, denominador_) == 1);}

Número de invocações:

14

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

Traçado

void Racional::reduz(){ assert(denominador_ != 0); assert(denominador_ != 0);

int const divisor = mdc(numerador_, denominador_);

numerador_ /= divisor; denominador_ /= divisor;

assert(denominador_ != 0);assert(denominador_ != 0);

assert(mdc(numerador_, denominador_) == 1);assert(mdc(numerador_, denominador_) == 1);}

Número de invocações:

14

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

Traçado

void Racional::reduz(){ assert(denominador_ != 0); assert(denominador_ != 0);

int const divisor = mdc(numerador_, denominador_);

numerador_ /= divisor; denominador_ /= divisor;

assert(denominador_ != 0);assert(denominador_ != 0);

assert(mdc(numerador_, denominador_) == 1);assert(mdc(numerador_, denominador_) == 1);}

Número de invocações:

14

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

Traçado

Racional& Racional::operator+=(Racional const& r2) { assert(cumpreInvariante());assert(cumpreInvariante()); assert(r2.cumpreInvariante()); assert(r2.cumpreInvariante());

numerador_ = numerador() * r2.denominador() + r2.numerador() * denominador(); denominador_ *= r2.denominador();

reduz();

assert(cumpreInvariante()); assert(cumpreInvariante());

return *this; }

Número de invocações:

14

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

Traçado

Racional const operator+(Racional r1, Racional const& r2) { r1 += r2;

return r1; }

Devolução por valor implica cópia!

Número de invocações:

14

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

Traçado

Racional::Racional(Racional const& original) : numerador_(original.numerador_), denominador_(original.denominador_){}

Número de invocações:

15

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

Traçado

Racional::Racional(Racional const& original) : numerador_(original.numerador_), denominador_(original.denominador_){}

Número de invocações:

15

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

Traçado

Racional r(1, 3);

Racional s = r + 2;

Número de invocações:

15

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

Traçado

Racional::Racional(Racional const& original) : numerador_(original.numerador_), denominador_(original.denominador_){}

Número de invocações:

16

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

Traçado

Racional::Racional(Racional const& original) : numerador_(original.numerador_), denominador_(original.denominador_){}

Número de invocações:

16

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

Traçado

Racional r(1, 3);

Racional s = r + 2;

// Fim!

Número de invocações:

16

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

Conclusão

Há muito mais invocações do que suspeitávamos: 16!

Cada invocação implica: Colocar endereço de retorno na pilha Construir parâmetros na pilha Executar corpo Destruir parâmetros da pilha Construir instância de devolução (se for o caso) Retornar ao local de invocação

Ok, ok… Uma das cópias provavelmente não seria feita…

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

Eficiência

Dados Programa passa 80% do tempo em 20% do

código 20% críticos desconhecidos a priori

Conclusões Esforços de optimização antecipados são perda

de tempo

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

Mas…

Há hábitos que contribuem para eficiência do programa e não têm qualquer desvantagem:

1. Usar passagem de argumentos por referência constante onde apropriado

2. Usar a palavra chave inline onde apropriado

Já se lá irá, já se lá irá…

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

Rotinas em-linha (inline)

Corpo não existe num único local, sendo executado sempre que desejado

Corpo é substituído pelo compilador em todos os locais onde a rotina é invocada

Rotinas curtas e sem ciclos devem ser em-linha!

Duas ou três linhas, digamos, excluindo asserções.

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

Exemplo

inline int soma(int const a, int const b){ return a + b; }

int x1 = 10;int x2 = 30;int x3 = 50;int r = 0;

int main(){ r = soma(x1, x2); r = soma(r, x3); }

int x1 = 10;int x2 = 30;int x3 = 50;int r = 0;

int main(){ r = x1 + x2; r = r + x3; }

Geram mesmo código máquina!Geram mesmo código máquina!

Usar variáveis globais é má ideia! Isto é só um

exemplo!

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

Exemplo em MAC-1

int soma(int const a, int const b){ return a + b; }

int x1 = 10;int x2 = 30;int x3 = 50;int r = 0;

int main(){ r = soma(x1, x2); r = soma(r, x3); }

jump main # Variáveis: x1 = 10 x2 = 30 x3 = 50 r = 0 # Aqui faz-se a soma:main: lodd x1 # Carrega variável x1 no acumulador. push # Coloca acumulador no topo da pilha. lodd x2 # Carrega variável x2 no acumulador. push # Coloca acumulador no topo da pilha. # Aqui a pilha tem os dois argumentos x1 e x2: call soma # Invoca a função soma. insp 2 # Repõe a pilha (limpeza da casa). # Aqui o acumulador tem o valor devolvido. stod r # Guarda o acumulador na variável r. lodd r # Carrega variável r no acumulador. push # Coloca acumulador no topo da pilha. lodd x3 # Carrega variável x3 no acumulador. push # Coloca acumulador no topo da pilha. # Aqui a pilha tem os dois argumentos r e x3: call soma # Invoca a função soma. insp 2 # Repõe a pilha (limpeza da casa). # Aqui o acumulador tem o valor devolvido. stod r # Guarda o acumulador na variável r. haltsoma: lodl 2 addl 1 retn

Sem inline (nem optimização).

compilação

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

jump main1030500

lodd x1push

lodd x2push

call somainsp 2stod rlodd rpush

lodd x3push

call somainsp2stod rhalt

lodl 2addl 1retn

????????

soma: 202122

0x1: 1x2: 2x3: 3

r: 4main: 5

6789

10111213141516171819

0pc

?ac

100sp

10099989796959493

pilha

Instruções executadas:

0

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

jump main10

0lodd x1push

lodd x2push

call somainsp 2stod rlodd rpush

lodd x3push

call somainsp2stod rhalt

lodl 2addl 1retn

soma: 202122

0x1: 1x2: 2x3: 3

r: 4main: 5

6789

10111213141516171819

5pc

?ac

100sp

10099989796959493

3050

????????

Instruções executadas:

1

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

jump main10

0lodd x1push

lodd x2push

call somainsp 2stod rlodd rpush

lodd x3push

call somainsp2stod rhalt

lodl 2addl 1retn

soma: 202122

0x1: 1x2: 2x3: 3

r: 4main: 5

6789

10111213141516171819

6pc

10ac

100sp

10099989796959493

3050

????????

Instruções executadas:

2

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

jump main10

0lodd x1push

lodd x2push

call somainsp 2stod rlodd rpush

lodd x3push

call somainsp2stod rhalt

lodl 2addl 1retn

10

soma: 202122

0x1: 1x2: 2x3: 3

r: 4main: 5

6789

10111213141516171819

7pc

10ac

99sp

10099989796959493

3050

??????

?

Instruções executadas:

3

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

jump main10

0lodd x1push

lodd x2push

call somainsp 2stod rlodd rpush

lodd x3push

call somainsp2stod rhalt

lodl 2addl 1retn

10

soma: 202122

0x1: 1x2: 2x3: 3

r: 4main: 5

6789

10111213141516171819

8pc

30ac

99sp

10099989796959493

3050

??????

?

Instruções executadas:

4

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

jump main10

0lodd x1push

lodd x2push

call somainsp 2stod rlodd rpush

lodd x3push

call somainsp2stod rhalt

lodl 1addl 2retn

3010

soma: 202122

0x1: 1x2: 2x3: 3

r: 4main: 5

6789

10111213141516171819

9pc

30ac

98sp

10099989796959493

3050

?????

?

Instruções executadas:

5

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

jump main10

0lodd x1push

lodd x2push

call somainsp 2stod rlodd rpush

lodd x3push

call somainsp2stod rhalt

lodl 2addl 1retn

103010

soma: 202122

0x1: 1x2: 2x3: 3

r: 4main: 5

6789

10111213141516171819

20pc

30ac

97sp

10099989796959493

3050

????

?

Instruções executadas:

6

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

jump main10

0lodd x1push

lodd x2push

call somainsp 2stod rlodd rpush

lodd x3push

call somainsp2stod rhalt

lodl 2addl 1retn

103010

soma: 202122

0x1: 1x2: 2x3: 3

r: 4main: 5

6789

10111213141516171819

21pc

10ac

97sp

10099989796959493

3050

????

?

Instruções executadas:

7

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

jump main10

0lodd x1push

lodd x2push

call somainsp 2stod rlodd rpush

lodd x3push

call somainsp2stod rhalt

lodl 2addl 1retn

103010

soma: 202122

0x1: 1x2: 2x3: 3

r: 4main: 5

6789

10111213141516171819

22pc

40ac

97sp

10099989796959493

3050

????

?

Instruções executadas:

8

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

jump main10

0lodd x1push

lodd x2push

call somainsp 2stod rlodd rpush

lodd x3push

call somainsp2stod rhalt

lodl 2addl 1retn

103010

soma: 202122

0x1: 1x2: 2x3: 3

r: 4main: 5

6789

10111213141516171819

10pc

40ac

98sp

10099989796959493

3050

????

?

Instruções executadas:

9

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

jump main10

0lodd x1push

lodd x2push

call somainsp 2stod rlodd rpush

lodd x3push

call somainsp2stod rhalt

lodl 2addl 1retn

103010

soma: 202122

0x1: 1x2: 2x3: 3

r: 4main: 5

6789

10111213141516171819

11pc

40ac

100sp

10099989796959493

3050

????

?

Instruções executadas:

10

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

jump main10

40lodd x1push

lodd x2push

call somainsp 2stod rlodd rpush

lodd x3push

call somainsp2stod rhalt

lodl 2addl 1retn

103010

soma: 202122

0x1: 1x2: 2x3: 3

r: 4main: 5

6789

10111213141516171819

12pc

40ac

100sp

10099989796959493

3050

????

?

Instruções executadas:

11

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

jump main10

40lodd x1push

lodd x2push

call somainsp 2stod rlodd rpush

lodd x3push

call somainsp2stod rhalt

lodl 2addl 1retn

103010

soma: 202122

0x1: 1x2: 2x3: 3

r: 4main: 5

6789

10111213141516171819

13pc

40ac

100sp

10099989796959493

3050

????

?

Instruções executadas:

12

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

jump main10

40lodd x1push

lodd x2push

call somainsp 2stod rlodd rpush

lodd x3push

call somainsp2stod rhalt

lodl 2addl 1retn

103040

soma: 202122

0x1: 1x2: 2x3: 3

r: 4main: 5

6789

10111213141516171819

14pc

40ac

99sp

10099989796959493

3050

????

?

Instruções executadas:

13

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

jump main10

40lodd x1push

lodd x2push

call somainsp 2stod rlodd rpush

lodd x3push

call somainsp2stod rhalt

lodl 2addl 1retn

103040

soma: 202122

0x1: 1x2: 2x3: 3

r: 4main: 5

6789

10111213141516171819

15pc

50ac

99sp

10099989796959493

3050

????

?

Instruções executadas:

14

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

jump main10

40lodd x1push

lodd x2push

call somainsp 2stod rlodd rpush

lodd x3push

call somainsp2stod rhalt

lodl 2addl 1retn

105040

soma: 202122

0x1: 1x2: 2x3: 3

r: 4main: 5

6789

10111213141516171819

16pc

50ac

98sp

10099989796959493

3050

????

?

Instruções executadas:

15

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

jump main10

40lodd x1push

lodd x2push

call somainsp 2stod rlodd rpush

lodd x3push

call somainsp2stod rhalt

lodl 2addl 1retn

175040

soma: 202122

0x1: 1x2: 2x3: 3

r: 4main: 5

6789

10111213141516171819

20pc

50ac

97sp

10099989796959493

3050

????

?

Instruções executadas:

16

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

jump main10

40lodd x1push

lodd x2push

call somainsp 2stod rlodd rpush

lodd x3push

call somainsp2stod rhalt

lodl 2addl 1retn

175040

soma: 202122

0x1: 1x2: 2x3: 3

r: 4main: 5

6789

10111213141516171819

21pc

40ac

97sp

10099989796959493

3050

????

?

Instruções executadas:

17

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

jump main10

40lodd x1push

lodd x2push

call somainsp 2stod rlodd rpush

lodd x3push

call somainsp2stod rhalt

lodl 2addl 1retn

175040

soma: 202122

0x1: 1x2: 2x3: 3

r: 4main: 5

6789

10111213141516171819

22pc

90ac

97sp

10099989796959493

3050

????

?

Instruções executadas:

18

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

jump main10

40lodd x1push

lodd x2push

call somainsp 2stod rlodd rpush

lodd x3push

call somainsp2stod rhalt

lodl 2addl 1retn

175040

soma: 202122

0x1: 1x2: 2x3: 3

r: 4main: 5

6789

10111213141516171819

17pc

90ac

98sp

10099989796959493

3050

????

?

Instruções executadas:

19

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

jump main10

40lodd x1push

lodd x2push

call somainsp 2stod rlodd rpush

lodd x3push

call somainsp2stod rhalt

lodl 2addl 1retn

175040

soma: 202122

0x1: 1x2: 2x3: 3

r: 4main: 5

6789

10111213141516171819

18pc

90ac

100sp

10099989796959493

3050

????

?

Instruções executadas:

20

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

jump main10

90lodd x1push

lodd x2push

call somainsp 2stod rlodd rpush

lodd x3push

call somainsp2stod rhalt

lodl 2addl 1retn

175040

soma: 202122

0x1: 1x2: 2x3: 3

r: 4main: 5

6789

10111213141516171819

19pc

90ac

100sp

10099989796959493

3050

????

?

Instruções executadas:

21

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

Exemplo em MAC-1

inline int soma(int const a, int const b){ return a + b; }

int x1 = 10;int x2 = 30;int x3 = 50;int r = 0;

int main(){ r = soma(x1, x2); r = soma(r, x3); }

jump main # Variáveis: x1 = 10 x2 = 20 x3 = 30 r = 0 # Aqui faz-se a soma:main: lodd x1 # Carrega variável x1 no acumulador. addd x2 # Adiciona variável x2 ao acumulador. stod r # Guarda o acumulador na variável r. lodd r # Carrega variável r no acumulador. addd x3 # Adiciona variável x3 ao acumulador. stod r # Guarda o acumulador na variável r. halt

Com inline.

compilação

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

jump main1030500

lodd x1addd x2stod rlodd r

addd x3stod rhalt

????????

0x1: 1x2: 2x3: 3

r: 4main: 5

6789

1011

0pc

?ac

100sp

10099989796959493

pilha

Instruções executadas:

0

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

jump main1030500

lodd x1addd x2stod rlodd r

addd x3stod rhalt

????????

0x1: 1x2: 2x3: 3

r: 4main: 5

6789

1011

5pc

?ac

100sp

10099989796959493

Instruções executadas:

1

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

jump main1030500

lodd x1addd x2stod rlodd r

addd x3stod rhalt

????????

0x1: 1x2: 2x3: 3

r: 4main: 5

6789

1011

6pc

10ac

100sp

10099989796959493

Instruções executadas:

2

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

jump main1030500

lodd x1addd x2stod rlodd r

addd x3stod rhalt

????????

0x1: 1x2: 2x3: 3

r: 4main: 5

6789

1011

7pc

40ac

100sp

10099989796959493

Instruções executadas:

3

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

jump main10305040

lodd x1addd x2stod rlodd r

addd x3stod rhalt

????????

0x1: 1x2: 2x3: 3

r: 4main: 5

6789

1011

8pc

40ac

100sp

10099989796959493

Instruções executadas:

4

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

jump main10305040

lodd x1addd x2stod rlodd r

addd x3stod rhalt

????????

0x1: 1x2: 2x3: 3

r: 4main: 5

6789

1011

9pc

40ac

100sp

10099989796959493

Instruções executadas:

5

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

jump main10305040

lodd x1addd x2stod rlodd r

addd x3stod rhalt

????????

0x1: 1x2: 2x3: 3

r: 4main: 5

6789

1011

10pc

90ac

100sp

10099989796959493

Instruções executadas:

6

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

jump main10305090

lodd x1addd x2stod rlodd r

addd x3stod rhalt

????????

0x1: 1x2: 2x3: 3

r: 4main: 5

6789

1011

11pc

90ac

100sp

10099989796959493

Instruções executadas:

7Sem inline eram 21…

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

Comparação

Sem inline:

jump main # Variáveis: x1 = 10 x2 = 30 x3 = 50 r = 0 # Aqui faz-se a soma:main: lodd x1 # Carrega variável x1 no acumulador. push # Coloca acumulador no topo da pilha. lodd x2 # Carrega variável x2 no acumulador. push # Coloca acumulador no topo da pilha. # Aqui a pilha tem os dois argumentos x1 e x2: call soma # Invoca a função soma. insp 2 # Repõe a pilha (limpeza da casa). # Aqui o acumulador tem o valor devolvido. stod r # Guarda o acumulador na variável r. lodd r # Carrega variável r no acumulador. push # Coloca acumulador no topo da pilha. lodd x3 # Carrega variável x3 no acumulador. push # Coloca acumulador no topo da pilha. # Aqui a pilha tem os dois argumentos r e x3: call soma # Invoca a função soma. insp 2 # Repõe a pilha (limpeza da casa). # Aqui o acumulador tem o valor devolvido. stod r # Guarda o acumulador na variável r. haltsoma: lodl 2 addl 1 retn

Com inline:

jump main # Variáveis: x1 = 10 x2 = 20 x3 = 30 r = 0 # Aqui faz-se a soma:main: lodd x1 # Carrega variável x1 no acumulador. addd x2 # Adiciona variável x2 ao acumulador. stod r # Guarda o acumulador na variável r. lodd r # Carrega variável r no acumulador. addd x3 # Adiciona variável x3 ao acumulador. stod r # Guarda o acumulador na variável r. halt

Sempre mais rápido!

Sempre mais curto?

Não! Por vezes é mais longo. Depende da dimensão do código das rotinas, do número de invocações, etc.

Código demasiado longo pode tornar a execução mais lenta, pois obriga a recorrer à memória virtual.

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

Sintaxe

Colocar a palavra chave inline antes do cabeçalho na definição da rotina:

inline tipo nome(parâmetros) … { … }

ou

inline tipo Classe::nome(parâmetros) … { … }

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

Estrutura global do programa (I)

#include <iostream>#include <cassert>

using namespace std;

/** Devolve o máximo divisor comum dos inteiros passados como argumento. @pre m ≠ 0 ou n ≠ 0. @post mdc = mdc(m, n). */int mdc(int const m, int const n) {…}

class Racional {…};

inline Racional::Racional(int const n) {…}

inline Racional::Racional(int const n, int const d) {…}

inline int Racional::numerador() const {…}

inline int Racional::denominador() const {…}

inline Racional::escreve() const {…}

(continua)(continua)

Construtores

Inspectores

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

Estrutura global do programa (II)

(continuação)(continuação)

void Racional::lê() {…}

inline Racional& Racional::operator++() {…}

inline Racional& Racional::operator--() {…}

inline Racional& Racional::operator*=(Racional const& r2) {…}

inline Racional& Racional::operator/=(Racional const& r2) {…}

inline Racional& Racional::operator+=(Racional const& r2) {…}

inline Racional& Racional::operator-=(Racional const& r2) {…}

inline void Racional::reduz() {…}

inline bool Racional::cumpreInvariante() const {…}

(continua)(continua)

Modificadores

Auxiliares

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

Estrutura global do programa (III)

(continuação)(continuação)

/** Produto de dois racionais. @pre V. @post operator* = r1 × r2. */inline Racional const operator*(Racional r1, Racional const& r2) {…}

/** Divisão de dois racionais. @pre r2 ≠ 0. @post operator/ = r1 / r2. */inline Racional const operator/(Racional r1, Racional const& r2) {…} /** Soma de dois racionais. @pre V. @post operator+ = r1 + r2. */inline Racional const operator+(Racional r1, Racional const& r2) {…}

/** Subtracção de dois racionais. @pre V. @post operator- = r1 - r2. */inline Racional const operator-(Racional r1, Racional const& r2) {…}

(continua)(continua)

Operadores aritméticos

não-membro

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

Estrutura global do programa (IV)

(continuação)(continuação)

/** Indica se dois racionais são iguais.

@pre V.

@post operator== = (r1 = r2). */inline bool operator==(Racional const& r1, Racional const& r2) {…} /** Indica se dois racionais são diferentes.

@pre V.

@post operator!= = (r1 ≠ r2). */inline bool operator!=(Racional const& r1, Racional const& r2) {…}

int main() {…}

Operadores de igualdade e

diferença

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

Operadores em falta

Aritméticos: Unários: + e -

Relacionais: <, <=, > e >=

Incrementação: Sufixo: ++ e --

Inserção e extracção de canais: << e >>

Começamos aqui.

Fica por fazer...

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

Incrementação prefixa

class Racional { public: …

/** Incrementa o racional. @pre *this = r. @post operator++ ≡ *this *this = r + 1. */ Racional& operator++();

};

Racional& Racional::operator++() { assert(cumpreInvariante());

numerador_ += denominador();

assert(cumpreInvariante());

return *this; }

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

Incrementação sufixa

?

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

Incrementação sufixa: a solução

/** Incrementa o racional, devolvendo o seu valor antes de incrementado. @pre r = r. @post operator++ = r r = r + 1. */inline Racional const operator++(Racional& r, int){ Racional const cópia = r; ++r;

return cópia;}

Devolve-se por valor um racional com o valor antes de incrementado, i.e., devolve-se a cópia do racional r.

Faz-se uma cópia de r antes de se incrementar, recorrendo à incrementação prefixa, já definida.

Aha! Cá está a diferença! Trata-se o operador como se fosse binário, recebendo como argumento um inteiro com valor não especificado e irrelevante.

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

Decrementação sufixa: a solução

/** Decrementa o racional, devolvendo o seu valor antes de decrementado. @pre r = r. @post operator-- = r r = r - 1. */inline Racional const operator--(Racional& r, int){ Racional const cópia = r; --r;

return cópia;}

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

Operador - unário: operação

/** … */class Racional { public: …

/** Devolve simétrico do racional. @pre V. @post operator- = -*this. */ Racional const operator-() const;

private: …};

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

Operador - unário: método

inline Racional const Racional::operator-() const{ assert(cumpreInvariante());

Racional r;

r.numerador_ = -numerador(); r.denominador_ = denominador();

assert(r.cumpreInvariante());

return r;}

Não é fundamental usar uma rotina membro, mas permite código mais eficiente, pois pode-se mudar o sinal do numerador directamente, evitando-se invocações espúrias do redutor de fracções.

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

Operador + unário

/** Devolve o racional. @pre V. @post operator+ ≡ r. */inline Racional const& operator+(Racional const& r){ return r;}

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

Operador <

/** Devolve verdadeiro se o primeiro racional for menor que o segundo. @pre V. @post operator< = r1 < r2. */inline bool operator<(Racional const& r1, Racional const& r2){ return r1.numerador() * r2.denominador() <  r2.numerador() * r1.denominador();}

Como 0 < r1.d 0 < r2.d,

r1.n / r1.d < r2.n / r2.d r1.n x r2.d < r2.n * r1.d

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

Operadores <=, > e >=

Podem-se definir à custa do operador <

Como?

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

Operador >

/** Devolve verdadeiro se o primeiro racional for maior que o segundo. @pre V. @post operator> = r1 > r2. */inline bool operator>(Racional const& r1, Racional const& r2){ return r2 < r1;}

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

Operador <=

/** Devolve verdadeiro se o primeiro racional for menor ou igual ao segundo. @pre V. @post operator<= = r1 <= r2. */inline bool operator<=(Racional const& r1, Racional const& r2){ return not (r1 > r2);}

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

Operador >=

/** Devolve verdadeiro se o primeiro racional for menor ou igual ao segundo. @pre V. @post operator>= = r1 >= r2. */inline bool operator>=(Racional const& r1, Racional const& r2){ return not (r1 < r2);}

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

Outro desafio (fácil)

Definir o operador == à custa do operador <

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

Último problema

Operador /= usa o operador !=, definido mais tarde

Melhor solução: concentrar declarações de rotinas não-membro

após definição da classe Definir rotinas não-membro mais tarde

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

Preâmbulo e definição da classe C++

#include <iostream>#include <cassert>

using namespace std;

/** Devolve o máximo divisor comum dos inteiros passados como argumento.

@pre m ≠ 0 ou n ≠ 0.

@post mdc = mdc(m, n). */int mdc(int const m, int const n) {…}

class Racional {…};

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

Declaração de rotinas não-membro (I)

/** Incrementa o racional, devolvendo o seu valor antes de incrementado.

@pre r = r.

@post operator++ = r r = r + 1. */Racional const operator++(Racional& r, int);

/** Decrementa o racional, devolvendo o seu valor antes de decrementado.

@pre r = r.

@post operator-- = r r = r - 1. */Racional const operator--(Racional& r, int);

Incrementação e decrementação

sufixas

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

Declaração de rotinas não-membro (II)

/** Produto de dois racionais. @pre V. @post operator* = r1 × r2. */Racional const operator*(Racional r1, Racional const& r2);

/** Divisão de dois racionais. @pre r2 ≠ 0. @post operator/ = r1 / r2. */Racional const operator/(Racional r1, Racional const& r2); /** Soma de dois racionais. @pre V. @post operator+ = r1 + r2. */Racional const operator+(Racional r1, Racional const& r2);

/** Subtracção de dois racionais. @pre V. @post operator- = r1 - r2. */Racional const operator-(Racional r1, Racional const& r2);

Operadores aritméticos

binários

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

Declaração de rotinas não-membro (III)

/** Devolve o racional.

@pre V.

@post operator+ ≡ r. */Racional const& operator+(Racional const& r);

/** Indica se dois racionais são iguais.

@pre V.

@post operator== = (r1 = r2). */bool operator==(Racional const& r1, Racional const& r2); /** Indica se dois racionais são diferentes.

@pre V.

@post operator!= = (r1 ≠ r2). */bool operator!=(Racional const& r1, Racional const& r2);

Operadores de igualdade e

diferença

Operador identidade

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

Declaração de rotinas não-membro (IV)/** Devolve verdadeiro se o primeiro racional for menor que o segundo. @pre V. @post operator< = r1 < r2. */bool operator<(Racional const& r1, Racional const& r2);

/** Devolve verdadeiro se o primeiro racional for maior que o segundo. @pre V. @post operator> = r1 > r2. */bool operator>(Racional const& r1, Racional const& r2);

/** Devolve verdadeiro se o primeiro racional for menor ou igual ao segundo. @pre V. @post operator<= = r1 <= r2. */bool operator<=(Racional const& r1, Racional const& r2);

/** Devolve verdadeiro se o primeiro racional for maior ou igual ao segundo. @pre V. @post operator>= = r1 >= r2. */bool operator>=(Racional const& r1, Racional const& r2);

Operadores relacionais

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

Definição de métodos (I)

inline Racional::Racional(int const n) {…}

inline Racional::Racional(int const n, int const d) {…}

inline int Racional::numerador() const {…}

inline int Racional::denominador() const {…}

inline void Racional::escreve() const {…}

inline Racional const Racional::operator-() const {…}

void Racional::lê() {…}

inline Racional& Racional::operator++() {…}

inline Racional& Racional::operator--() {…}

inline Racional& Racional::operator*=(Racional const& r2) {…}

inline Racional& Racional::operator/=(Racional const& r2) {…}

inline Racional& Racional::operator+=(Racional const& r2) {…}

inline Racional& Racional::operator-=(Racional const& r2) {…}

inline void Racional::reduz() {…}

inline bool Racional::cumpreInvariante() const {…}

(continua)(continua)

Construtores

Inspectores

Modificadores

Auxiliares

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

Definição de rotinas não-membro

inline Racional const operator++(Racional& r, int) {…}

inline Racional const operator--(Racional& r, int) {…}

inline Racional const operator*(Racional r1, Racional const& r2) {…}

inline Racional const operator/(Racional r1, Racional const& r2) {…} inline Racional const operator+(Racional r1, Racional const& r2) {…}

inline Racional const operator-(Racional r1, Racional const& r2) {…}

inline Racional const& operator+(Racional const& r) {…}

inline bool operator==(Racional const& r1, Racional const& r2) {…} inline bool operator!=(Racional const& r1, Racional const& r2) {…}

inline bool operator<(Racional const& r1, Racional const& r2) {…}

inline bool operator>(Racional const& r1, Racional const& r2) {…}

inline bool operator<=(Racional const& r1, Racional const& r2) {…}

inline bool operator>=(Racional const& r1, Racional const& r2) {…}

int main() {…}

Operadores aritméticos

binários

Incrementação e decrementação

sufixas

Operadores de igualdade e

diferença

Operador identidade

Operadores relacionais

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

TAD Racional (construtores)

/** Representa números racionais.

@invariant 0 < denominador_ mdc(numerador_, denominador_) = 1. */class Racional { public: /** Constrói racional com valor inteiro.

@pre V.

@post *this = valor. */ Racional(int const valor = 0);

/** Constrói racional correspondente a numerador/denominador.

@pre denominador ≠ 0.

@post *this = numerador/denominador. */ Racional(int const numerador, int const denominador);

(continua)(continua)

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

TAD Racional (inspectores)

(continuação)(continuação)

/** Devolve numerador da fracção mínima correspondente ao racional.

@pre V.

@post numerador/denominador() = *this. */ int numerador() const;

/** Devolve denominador da fracção mínima correspondente ao racional.

@pre V.

@post 0 < denominador (E n : V : n/denominador = *this mdc(n, denominador) = 1). */ int denominador() const;

(continua)(continua)

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

TAD Racional (inspectores)

(continuação)(continuação)

/** 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() const;

/** Devolve simétrico do racional. @pre V. @post operator- = -*this. */ Racional const operator-() const;

(continua)(continua)

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

TAD Racional (modificadores)

(continuação)(continuação) /** 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ê();

/** Incrementa o racional. @pre *this = r. @post operator++ ≡ *this *this = r + 1. */ Racional& operator++();

/** Decrementa o racional. @pre *this = r. @post operator-- ≡ *this *this = r - 1. */ Racional& operator--(); (continua)(continua)

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

TAD Racional (modificadores)

(continuação)(continuação) /** Multiplica por um racional.     @pre *this = r.     @post operator*= ≡ *this *this = r × r2. */ Racional& operator*=(Racional const& r2);

/** Divide por um racional.     @pre *this = r r2 ≠ 0.     @post operator/= ≡ *this *this = r / r2. */ Racional& operator/=(Racional const& r2);

/** Adiciona de um racional.     @pre *this = r.     @post operator+= ≡ *this *this = r + r2. */ Racional& operator+=(Racional const& r2);

/** Subtrai de um racional.     @pre *this = r.     @post operator-= ≡ *this *this = r - r2. */ Racional& operator-=(Racional const& r2);(continua)(continua)

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

TAD Racional (implementação)

(continuação)(continuação) private: /** Indica se a CIC se verifica.      @pre V.      @post  cumpreInvariante = 0 < denominador_ mdc(numerador_, denominador_) = 1. */ bool cumpreInvariante() const;

/** 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ção165

Aula 13: Sumário

Definindo constantes de uma classe: Necessidade de declarar operações como constantes (que não alteram a instância

implícita). Sintaxe. Devolução por valor constante. Vantagens da utilização de const.

Evitando o mecanismo de invocação de rotinas no código máquina produzido pelo compilador:

Rotinas inline. Sintaxe. Regras de utilização. Explicação do efeito de inline sobre o código máquina produzido. Exemplo com programa em C++ e respectiva tradução para MAC-1 (ver

Arquitectura de Computadores). Quando optimizar.

Incrementação e decrementação sufixa: sobrecarga. Ordem de declaração/definição de operações/métodos e rotinas não-membro

associados a um TAD.