A apresentação está carregando. Por favor, espere

A apresentação está carregando. Por favor, espere

Tipos Abstractos de Dados III

Apresentações semelhantes


Apresentação em tema: "Tipos Abstractos de Dados III"— Transcrição da apresentação:

1 Tipos Abstractos de Dados III
Aula 12 Tipos Abstractos de Dados III

2 Operadores a sobrecarregar
Feito, mas precisa ser refeito. 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. Introdução à Programação 2003/2004

3 Introdução à Programação
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? Introdução à Programação 2003/2004

4 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.) Introdução à Programação 2003/2004

5 Operação Racional::operator++()
/** … */ class Racional { public: /** Incrementa o racional. @pre *this = r. @post operator++ ≡ *this  *this = r + 1. */ Racional& operator++(); private: }; Introdução à Programação 2003/2004

6 Operação Racional::operator--()
/** … */ class Racional { public: /** Decrementa o racional. @pre *this = r. @post operator-- ≡ *this  *this = r - 1. */ Racional& operator--(); private: }; Introdução à Programação 2003/2004

7 Método Racional::operator++()
Racional& Racional::operator++() { assert(cumpreInvariante()); numerador += denominador; return *this; } Introdução à Programação 2003/2004

8 Método Racional::operator--()
Racional& Racional::operator--() { assert(cumpreInvariante()); numerador -= denominador; return *this; } Introdução à Programação 2003/2004

9 Operadores especiais de atribuição
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! Introdução à Programação 2003/2004

10 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: }; Introdução à Programação 2003/2004

11 Método Racional::operator*=()
Racional& Racional::operator*=(Racional const& r2) { assert(cumpreInvariante()); assert(r2.cumpreInvariante()); numerador *= r2.numerador; denominador *= r2.denominador; reduz(); return *this; } Introdução à Programação 2003/2004

12 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: }; Introdução à Programação 2003/2004

13 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(); return *this; } Não se pode dividir por zero. Asserção possível apenas quando se definir operador !=. Introdução à Programação 2003/2004

14 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: }; Introdução à Programação 2003/2004

15 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(); return *this; } Pode-se trocar a ordem destas atribuições? Introdução à Programação 2003/2004

16 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: }; Introdução à Programação 2003/2004

17 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(); return *this; } Introdução à Programação 2003/2004

18 Operadores aritméticos binários
Podem-se definir à custa dos operadores especiais de atribuição! Aliás, devem-se! Como? Introdução à Programação 2003/2004

19 Introdução à Programação
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. Devolução como constante?? Torna impossível Racional r1(1, 2), r2(3, 2); ++(r1 * r2); tal como acontece para os tipos básicos. Introdução à Programação 2003/2004

20 Introdução à Programação
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; } Introdução à Programação 2003/2004

21 Introdução à Programação
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; } Introdução à Programação 2003/2004

22 Introdução à Programação
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! Introdução à Programação 2003/2004

23 Introdução à Programação
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 Introdução à Programação 2003/2004

24 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; Introdução à Programação 2003/2004

25 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. Introdução à Programação 2003/2004

26 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 = 3 + r; Erro! Conversão impossível! Introdução à Programação 2003/2004

27 Conversões explícitas
class Racional { public: explicit Racional(int const valor = 0); }; Racional r(1, 3); Racional s = 4; Racional t(4); 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. Introdução à Programação 2003/2004

28 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) … Introdução à Programação 2003/2004

29 Introdução à Programação
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 Introdução à Programação 2003/2004

30 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. @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ê? Introdução à Programação 2003/2004

31 Dois inspectores úteis
int Racional::numerador() { assert(cumpreInvariante()); return numerador_; } int Racional::denominador() return denominador_; Introdução à Programação 2003/2004

32 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… Introdução à Programação 2003/2004

33 Introdução à Programação
Bronca… Racional& Racional::operator/=(Racional const& r2) { assert(cumpreInvariante()); assert(r2.cumpreInvariante()); assert(r2 != 0); numerador_ *= r2.denominador(); denominador_ *= r2.numerador(); reduz(); return *this; } Pois é… O numerador de r2 pode ser negativo! Introdução à Programação 2003/2004

34 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(); return *this; E se r2 for o mesmo que *this? Ou seja, se: Racional r(1, 2); r /= r; Introdução à Programação 2003/2004

35 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(); return *this; Introdução à Programação 2003/2004

36 Introdução à Programação
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); } Introdução à Programação 2003/2004

37 Introdução à Programação
Em falta Aritméticos: Unários: + e - Relacionais: <, <=, > e >= Incrementação: Sufixo: ++ e -- Introdução à Programação 2003/2004

38 Introdução à Programação
Coisas várias Uma trabalheira destas vale a pena? O código está errado! Introdução à Programação 2003/2004

39 Introdução à Programação
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 Introdução à Programação 2003/2004


Carregar ppt "Tipos Abstractos de Dados III"

Apresentações semelhantes


Anúncios Google