39
Aula 12 Tipos Abstractos de Dados III

Aula 12 Tipos Abstractos de Dados III. 2003/2004 Introdução à Programação 2 Operadores a sobrecarregar Aritméticos: Binários: *, /, + e - Unários: + e

Embed Size (px)

Citation preview

Page 1: Aula 12 Tipos Abstractos de Dados III. 2003/2004 Introdução à Programação 2 Operadores a sobrecarregar Aritméticos: Binários: *, /, + e - Unários: + e

Aula 12

Tipos Abstractos de Dados III

Page 2: Aula 12 Tipos Abstractos de Dados III. 2003/2004 Introdução à Programação 2 Operadores a sobrecarregar Aritméticos: Binários: *, /, + e - Unários: + e

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

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

Feito.

Feito, mas precisa ser refeito.

Page 3: Aula 12 Tipos Abstractos de Dados III. 2003/2004 Introdução à Programação 2 Operadores a sobrecarregar Aritméticos: Binários: *, /, + e - Unários: + e

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

Por onde começar?

Devemos começar pelos operadores com efeitos laterais

Quais são?

Racional a(1,2), b(3,5); a + b; // altera a? e b?

a++; // altera a?

Page 4: Aula 12 Tipos Abstractos de Dados III. 2003/2004 Introdução à Programação 2 Operadores a sobrecarregar Aritméticos: Binários: *, /, + e - Unários: + e

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

Operadores com efeitos laterais

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

Especiais de atribuição: *=, /=, += e -=

De atribuição: =

Feito.

Fica para POO. (Aliás, aqui é desnecessário.)

Page 5: Aula 12 Tipos Abstractos de Dados III. 2003/2004 Introdução à Programação 2 Operadores a sobrecarregar Aritméticos: Binários: *, /, + e - Unários: + e

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

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

/** Incrementa o racional.

@pre *this = r.

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

private: …

};

Page 6: Aula 12 Tipos Abstractos de Dados III. 2003/2004 Introdução à Programação 2 Operadores a sobrecarregar Aritméticos: Binários: *, /, + e - Unários: + e

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

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

/** Decrementa o racional.

@pre *this = r.

@post operator-- ≡ *this *this = r - 1. */ Racional& operator--();

private: …

};

Page 7: Aula 12 Tipos Abstractos de Dados III. 2003/2004 Introdução à Programação 2 Operadores a sobrecarregar Aritméticos: Binários: *, /, + e - Unários: + e

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

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

numerador += denominador;

assert(cumpreInvariante());

return *this; }

Page 8: Aula 12 Tipos Abstractos de Dados III. 2003/2004 Introdução à Programação 2 Operadores a sobrecarregar Aritméticos: Binários: *, /, + e - Unários: + e

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

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

numerador -= denominador;

assert(cumpreInvariante());

return *this; }

Page 9: Aula 12 Tipos Abstractos de Dados III. 2003/2004 Introdução à Programação 2 Operadores a sobrecarregar Aritméticos: Binários: *, /, + e - Unários: + e

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

Operadores especiais de atribuição

*=, /=, += e -=

Como membros da classe (porquê?)

Primeiro operando é instância implícita

Devolvem primeiro operando por referência:

Racional a(3), b(1, 2); (a *= b) *= b;

Se é possível com tipos básicos, também o deve ser com os nossos TAD.

Isso não significa que este código seja recomendável!

Page 10: Aula 12 Tipos Abstractos de Dados III. 2003/2004 Introdução à Programação 2 Operadores a sobrecarregar Aritméticos: Binários: *, /, + e - Unários: + e

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

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

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

private: …};

Page 11: Aula 12 Tipos Abstractos de Dados III. 2003/2004 Introdução à Programação 2 Operadores a sobrecarregar Aritméticos: Binários: *, /, + e - Unários: + e

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

Método Racional::operator*=()Racional& Racional::operator*=(Racional const& r2) { assert(cumpreInvariante()); assert(r2.cumpreInvariante());

numerador *= r2.numerador; denominador *= r2.denominador;

reduz();

assert(cumpreInvariante());

return *this; }

Page 12: Aula 12 Tipos Abstractos de Dados III. 2003/2004 Introdução à Programação 2 Operadores a sobrecarregar Aritméticos: Binários: *, /, + e - Unários: + e

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

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

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

private: …};

Page 13: Aula 12 Tipos Abstractos de Dados III. 2003/2004 Introdução à Programação 2 Operadores a sobrecarregar Aritméticos: Binários: *, /, + e - Unários: + e

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

Método Racional::operator/=()Racional& Racional::operator/=(Racional const& r2) { assert(cumpreInvariante()); assert(r2.cumpreInvariante());

assert(r2 != 0);

numerador *= r2.denominador; denominador *= r2.numerador;

reduz();

assert(cumpreInvariante());

return *this; }

Não se pode dividir por zero.

Asserção possível apenas quando se definir operador !=.

Page 14: Aula 12 Tipos Abstractos de Dados III. 2003/2004 Introdução à Programação 2 Operadores a sobrecarregar Aritméticos: Binários: *, /, + e - Unários: + e

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

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

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

private: …};

Page 15: Aula 12 Tipos Abstractos de Dados III. 2003/2004 Introdução à Programação 2 Operadores a sobrecarregar Aritméticos: Binários: *, /, + e - Unários: + e

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

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

numerador = numerador * r2.denominador + r2.numerador * denominador; denominador *= r2.denominador;

reduz();

assert(cumpreInvariante());

return *this; }

Pode-se trocar a ordem destas atribuições?

Page 16: Aula 12 Tipos Abstractos de Dados III. 2003/2004 Introdução à Programação 2 Operadores a sobrecarregar Aritméticos: Binários: *, /, + e - Unários: + e

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

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

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

private: …};

Page 17: Aula 12 Tipos Abstractos de Dados III. 2003/2004 Introdução à Programação 2 Operadores a sobrecarregar Aritméticos: Binários: *, /, + e - Unários: + e

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

Método Racional::operator-=()Racional& Racional::operator-=(Racional const& r2) { assert(cumpreInvariante()); assert(r2.cumpreInvariante());

numerador = numerador * r2.denominador - r2.numerador * denominador; denominador *= r2.denominador;

reduz();

assert(cumpreInvariante());

return *this; }

Page 18: Aula 12 Tipos Abstractos de Dados III. 2003/2004 Introdução à Programação 2 Operadores a sobrecarregar Aritméticos: Binários: *, /, + e - Unários: + e

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

Operadores aritméticos binários

*, /, + e –

Podem-se definir à custa dos operadores especiais de atribuição!

Aliás, devem-se!

Como?

Page 19: Aula 12 Tipos Abstractos de Dados III. 2003/2004 Introdução à Programação 2 Operadores a sobrecarregar Aritméticos: Binários: *, /, + e - Unários: + e

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

Devolução como constante??

Torna impossívelRacional r1(1, 2), r2(3, 2);

++(r1 * r2);

tal como acontece para os tipos básicos.

Função operator*()

/** Produto de dois racionais.

@pre V.

@post operator* = r1 × r2. */Racional const operator*(Racional r1, Racional const& r2) { r1 *= r2;

return r1; }

Passagem por valor! Alteração de r1 é alteração de cópia do argumento.

Page 20: Aula 12 Tipos Abstractos de Dados III. 2003/2004 Introdução à Programação 2 Operadores a sobrecarregar Aritméticos: Binários: *, /, + e - Unários: + e

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

Função operator/()

/** Quociente de dois racionais.

@pre r2 ≠ 0.

@post operator/ = r1 / r2. */Racional const operator/(Racional r1, Racional const& r2) { assert(r2 != 0);

r1 /= r2;

return r1; }

Page 21: Aula 12 Tipos Abstractos de Dados III. 2003/2004 Introdução à Programação 2 Operadores a sobrecarregar Aritméticos: Binários: *, /, + e - Unários: + e

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

Função operator+()

/** Soma de dois racionais.

@pre V.

@post operator+ = r1 + r2. */Racional const operator+(Racional r1, Racional const& r2) { r1 += r2;

return r1; }

Page 22: Aula 12 Tipos Abstractos de Dados III. 2003/2004 Introdução à Programação 2 Operadores a sobrecarregar Aritméticos: Binários: *, /, + e - Unários: + e

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

Função operator-()

/** Subtracção de dois racionais.

@pre V.

@post operator- = r1 - r2. */Racional const operator-(Racional r1, Racional const& r2) { r1 -= r2;

return r1; }

Operadores ou rotinas não-membro, são externas à classe C++, mas fazem parte da definição do TAD!

Page 23: Aula 12 Tipos Abstractos de Dados III. 2003/2004 Introdução à Programação 2 Operadores a sobrecarregar Aritméticos: Binários: *, /, + e - Unários: + e

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

Discussão

Quase regra: Se rotina pode não ser membro, não o deve ser

Métodos devem recorrer a operações existentes *= à custa de * ou * à custa de *=?

Obriga a cópia desnecessária

Page 24: Aula 12 Tipos Abstractos de Dados III. 2003/2004 Introdução à Programação 2 Operadores a sobrecarregar Aritméticos: Binários: *, /, + e - Unários: + e

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

Conversões implícitas

Definidas por construtores invocáveis com apenas um argumento

Convertem entre o tipo do parâmetro desse construtor e a classe

Permitem:Racional r(1, 3);

Racional s = r + 3;

Page 25: Aula 12 Tipos Abstractos de Dados III. 2003/2004 Introdução à Programação 2 Operadores a sobrecarregar Aritméticos: Binários: *, /, + e - Unários: + e

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

Conversões implícitas

Definidas por construtores invocáveis com apenas um argumento

Convertem entre o tipo do parâmetro desse construtor e a classe

Permitem:Racional r(1, 3);

Racional s = r + Racional(3);

Conversão implícita, colocada pelo compilador.

Page 26: Aula 12 Tipos Abstractos de Dados III. 2003/2004 Introdução à Programação 2 Operadores a sobrecarregar Aritméticos: Binários: *, /, + e - Unários: + e

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

Membro ou não membro, eis a questão

Conversões implícitas não ocorrem para instâncias através das quais se

invocam operações

(que são implícitas na execução do respectivo método)

Se operator+() fosse membro de Racional:

Racional r(1, 3);

Racional s = 33 + r;

Erro! Conversão impossível!

Page 27: Aula 12 Tipos Abstractos de Dados III. 2003/2004 Introdução à Programação 2 Operadores a sobrecarregar Aritméticos: Binários: *, /, + e - Unários: + e

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

Conversões explícitas

class Racional { public: …

explicit Racional(int const valor = 0);

… };

Racional r(1, 3); Racional s = 4;Racional s = 4; Racional t(4); Racional u = r + 3;Racional u = r + 3; Racional v = r + Racional(3);

Neste caso conversões implícitas são desejáveis. Não se deve usar explicit.

Page 28: Aula 12 Tipos Abstractos de Dados III. 2003/2004 Introdução à Programação 2 Operadores a sobrecarregar Aritméticos: Binários: *, /, + e - Unários: + e

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

Operadores de igualdade e diferença

Membros ou não membros?

Precisam de aceder aos atributos: membros

Convinha que tivessem comportamento comutativo no que diz respeito às conversões: não membros

Racional r(1, 2);

if(r == 1) …if(1 == r) …

Page 29: Aula 12 Tipos Abstractos de Dados III. 2003/2004 Introdução à Programação 2 Operadores a sobrecarregar Aritméticos: Binários: *, /, + e - Unários: + e

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

Inspectores

Operações que permitem obter informações acerca de uma instância de um TAD

Muitas vezes permitem saber o valor de atributos

Revelam informação sem violar encapsulamento

Page 30: Aula 12 Tipos Abstractos de Dados III. 2003/2004 Introdução à Programação 2 Operadores a sobrecarregar Aritméticos: Binários: *, /, + e - Unários: + e

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

Dois inspectores úteis

class Racional { public: …

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

private: …

    int numerador_;    int denominador_; };

Não pode haver operações com mesmo nome de atributos.

Optou-se por alterar nome de atributos. Porquê?

Page 31: Aula 12 Tipos Abstractos de Dados III. 2003/2004 Introdução à Programação 2 Operadores a sobrecarregar Aritméticos: Binários: *, /, + e - Unários: + e

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

Dois inspectores úteis

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

assert(cumpreInvariante());

return numerador_; }

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

assert(cumpreInvariante());

return denominador_; }

Page 32: Aula 12 Tipos Abstractos de Dados III. 2003/2004 Introdução à Programação 2 Operadores a sobrecarregar Aritméticos: Binários: *, /, + e - Unários: + e

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

Predicado operator==()

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

@pre V.

@post operator== = (r1 = r2). */bool operator==(Racional const& r1, Racional const& r2) { return r1.numerador() == r2.numerador() and r1.denominador() == r2.denominador(); }

Funciona porque os inspectores se limitam a devolver os atributos e estes cumprem sempre a CIC, ou seja,

0 < denominador_ mdc(numerador_, denominador_) = 1

Sempre? De certeza?

As instruções de asserção não o garantem?

Sim, mas…

Page 33: Aula 12 Tipos Abstractos de Dados III. 2003/2004 Introdução à Programação 2 Operadores a sobrecarregar Aritméticos: Binários: *, /, + e - Unários: + e

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

Bronca…

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

assert(r2 != 0);

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

reduz();

assert(cumpreInvariante());

return *this; }

Pois é… O numerador de r2 pode ser negativo!

Page 34: Aula 12 Tipos Abstractos de Dados III. 2003/2004 Introdução à Programação 2 Operadores a sobrecarregar Aritméticos: Binários: *, /, + e - Unários: + e

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

Correcção e… nova bronca!

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

assert(r2 != 0);

if(r2.numerador() < 0) { numerador_ *= -r2.denominador(); denominador_ *= -r2.numerador(); } else { numerador_ *= r2.denominador(); denominador_ *= r2.numerador(); }

reduz();

assert(cumpreInvariante());

return *this; }

E se r2 for o mesmo que *this? Ou seja, se:

Racional r(1, 2);

r /= r;

Page 35: Aula 12 Tipos Abstractos de Dados III. 2003/2004 Introdução à Programação 2 Operadores a sobrecarregar Aritméticos: Binários: *, /, + e - Unários: + e

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

Correcção e… nova bronca!

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

assert(r2 != 0);

int numerador = r2.numerador();

if(numerador < 0) { numerador_ *= -r2.denominador(); denominador_ *= -numerador; } else { numerador_ *= r2.denominador(); denominador_ *= numerador; }

reduz();

assert(cumpreInvariante());

return *this; }

Page 36: Aula 12 Tipos Abstractos de Dados III. 2003/2004 Introdução à Programação 2 Operadores a sobrecarregar Aritméticos: Binários: *, /, + e - Unários: + e

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

E o operador !=?

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

@pre V.

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

Page 37: Aula 12 Tipos Abstractos de Dados III. 2003/2004 Introdução à Programação 2 Operadores a sobrecarregar Aritméticos: Binários: *, /, + e - Unários: + e

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

Em falta

Aritméticos: Unários: + e -

Relacionais: <, <=, > e >=

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

Page 38: Aula 12 Tipos Abstractos de Dados III. 2003/2004 Introdução à Programação 2 Operadores a sobrecarregar Aritméticos: Binários: *, /, + e - Unários: + e

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

Coisas várias

Uma trabalheira destas vale a pena?

O código está errado!

Page 39: Aula 12 Tipos Abstractos de Dados III. 2003/2004 Introdução à Programação 2 Operadores a sobrecarregar Aritméticos: Binários: *, /, + e - Unários: + e

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

Aula 12: Sumário

Sobrecarga de operadores para o TAD Racional Operadores com efeitos laterais Regra: uma rotina só deve ser membro se precisar de o ser Conversões implícitas:

Construtores invocáveis com um único argumento Excepções

Evitando as conversões implícitas com explicit Comutatividade quanto a conversões Devolução de constantes Implementação de operações à custa de outras Inspectores e sua utilidade Vantagens e desvantagens de definir um TAD completo:

trabalho do produtor vs. trabalho do consumidor