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

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

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.

Apresentações semelhantes


Apresentação em tema: "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."— Transcrição da apresentação:

1 Aula 12 Tipos Abstractos de Dados III

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

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

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

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

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

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

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

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

10 2003/2004 Introdução à Programação 10 Operação Racional::operator*=() /** … */ class Racional { public: … /** Multiplica por um *this = operator*= *this *this = r × r2. */ Racional& operator*=(Racional const& r2); … private: … };

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

12 2003/2004 Introdução à Programação 12 Operação Racional::operator/=() /** … */ class Racional { public: … /** Divide por um *this = r r2 operator/= *this *this = r / r2. */ Racional& operator/=(Racional const& r2); … private: … };

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

14 2003/2004 Introdução à Programação 14 Operação Racional::operator+=() /** … */ class Racional { public: … /** Adiciona de um *this = operator+= *this *this = r + r2. */ Racional& operator+=(Racional const& r2); … private: … };

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

16 2003/2004 Introdução à Programação 16 Operação Racional::operator-=() /** … */ class Racional { public: … /** Subtrai de um *this = operator-= *this *this = r - r2. */ Racional& operator-=(Racional const& r2); … private: … };

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

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

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

20 2003/2004 Introdução à Programação 20 Função operator/() /** Quociente de dois r2 operator/ = r1 / r2. */ Racional const operator/(Racional r1, Racional const& r2) { assert(r2 != 0); r1 /= r2; return r1; }

21 2003/2004 Introdução à Programação 21 Função operator+() /** Soma de dois operator+ = r1 + r2. */ Racional const operator+(Racional r1, Racional const& r2) { r1 += r2; return r1; }

22 2003/2004 Introdução à Programação 22 Função operator-() /** Subtracção de dois 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!

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

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

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

26 2003/2004 Introdução à Programação 26 Membro ou não membro, eis a questão Erro! Conversão impossível!

27 2003/2004 Introdução à Programação 27 Conversões explícitas Neste caso conversões implícitas são desejáveis. Não se deve usar explicit.

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

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

30 2003/2004 Introdução à Programação 30 Dois inspectores úteis class Racional { public: … /** Devolve numerador da fracção mínima correspondente ao numerador / denominador () = *this. */ int numerador(); /** Devolve denominador da fracção mínima correspondente ao 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ê?

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

32 2003/2004 Introdução à Programação 32 Predicado operator==() /** Indica se dois racionais são 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…

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

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

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

36 2003/2004 Introdução à Programação 36 E o operador != ? /** Indica se dois racionais são operator!= = ( r1 r2 ). */ bool operator!=(Racional const& r1, Racional const& r2) { return not (r1 == r2); }

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

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

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


Carregar ppt "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."

Apresentações semelhantes


Anúncios Google