aula 10 tipos abstractos de dados i. 2003/2004 introdução à programação 2 flashback lembram-se...

71
Aula 10 Tipos Abstractos de Dados I

Upload: internet

Post on 17-Apr-2015

107 views

Category:

Documents


0 download

TRANSCRIPT

Page 1: Aula 10 Tipos Abstractos de Dados I. 2003/2004 Introdução à Programação 2 Flashback Lembram-se da Aula 4?

Aula 10

Tipos Abstractos de Dados I

Page 2: Aula 10 Tipos Abstractos de Dados I. 2003/2004 Introdução à Programação 2 Flashback Lembram-se da Aula 4?

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

Flashback

Lembram-se da Aula 4?

Page 3: Aula 10 Tipos Abstractos de Dados I. 2003/2004 Introdução à Programação 2 Flashback Lembram-se da Aula 4?

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

Soma de fracções (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) { assert(m != 0 or n != 0);

… }

(continua)

PC relaxada para aceitar inteiros negativos e nulos(ver folhas teóricas)

Page 4: Aula 10 Tipos Abstractos de Dados I. 2003/2004 Introdução à Programação 2 Flashback Lembram-se da Aula 4?

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

Soma de fracções (II)

/** Reduz a fracção recebida como argumento. @pre denominador ≠ 0 numerador = n denominador = d. @post denominador ≠ 0 mdc(numerador, denominador ) = 1 numerador/denominador = n/d. */ void reduzFracção(int& numerador, int& denominador) { assert(denominador != 0);

int const divisor = mdc(numerador, denominador);

numerador /= divisor; denominador /= divisor;

assert(denominador != 0); assert(mdc(numerador, denominador) == 1);}

(continua)

Page 5: Aula 10 Tipos Abstractos de Dados I. 2003/2004 Introdução à Programação 2 Flashback Lembram-se da Aula 4?

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

Soma de fracções (III)

/** Lê do teclado uma fracção, na forma de dois inteiros sucessivos. @pre numerador = n denominador = d. @post Se cin.good() cin tem dois inteiros n' e d' disponíveis para leitura, com d' ≠ 0, então 0 < denominador mdc(numerador, denominador) = 1 numerador/denominador = n'/d' cin.fail(), senão numerador = n denominador = d cin.fail(). */void lêFracção(int& numerador, int& denominador){ …}

(continua)

int n, d; cin >> n >> d; if(cin.good()) if(d == 0) cin.setstate(ios_base::failbit); else { if(d < 0) { numerador = -n; denominador = -d; } else { numerador = n; denominador = d; }     reduzFracção(numerador, denominador);

assert(0 < denominador); assert(mdc(numerador, denominador) == 1); assert(numerador * d == n * denominador); assert(not cin.fail());

return; }

assert(cin.fail());

Não existia na Aula 4!

Garante-se denominador positivo e representação em termos mínimos.

Page 6: Aula 10 Tipos Abstractos de Dados I. 2003/2004 Introdução à Programação 2 Flashback Lembram-se da Aula 4?

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

Soma de fracções (IV)

/** Soma duas fracções. @pre denominador1 ≠ 0 denominador2 ≠ 0. @post numerador/ denominador = numerador1/denominador1 + numerador2/denominador2 denominador ≠ 0 mdc(numerador, denominador) = 1. */void somaFracção(int& numerador, int& denominador,  int const numerador1, int const denominador1,                  int const numerador2, int const denominador2) { assert(denominador1 != 0); assert(denominador2 != 0);

numerador = numerador1 * denominador2 + numerador2 * denominador1; denominador = denominador1 * denominador2; reduzFracção(numerador, denominador);

assert(denominador != 0); assert(mdc(numerador, denominador) == 1); }

(continua)

Não existia na Aula 4!

Page 7: Aula 10 Tipos Abstractos de Dados I. 2003/2004 Introdução à Programação 2 Flashback Lembram-se da Aula 4?

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

Soma de fracções (V)

/** Escreve uma fracção no ecrã no formato usual. @pre V. @post cout.fail() 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 escreveFracção(int const numerador, int const denominador) { cout << numerador; if(denominador != 1) cout << '/' << denominador; }

(continua)

Page 8: Aula 10 Tipos Abstractos de Dados I. 2003/2004 Introdução à Programação 2 Flashback Lembram-se da Aula 4?

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

Soma de fracções (VI)

int main(){ // Ler fracções: cout << "Introduza duas fracções (numerador denominador): "; int n1, d1, n2, d2; lêFracção(n1, d1); lêFracção(n2, d2);

if(cin.fail()) { cout << "Opps! A leitura das fracções falhou!" << endl; return 1; }

(continua)

Page 9: Aula 10 Tipos Abstractos de Dados I. 2003/2004 Introdução à Programação 2 Flashback Lembram-se da Aula 4?

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

Soma de fracções (VII)

// Calcular fracção soma reduzida: int n, d; somaFracção(n, d, n1, d1, n2, d2);

// Escrever resultado: cout << "A soma de "; escreveFracção(n1, d1); cout << " com "; escreveFracção(n2, d2); cout << " é "; escreveFracção(n, d); cout << '.' << endl; }

Page 10: Aula 10 Tipos Abstractos de Dados I. 2003/2004 Introdução à Programação 2 Flashback Lembram-se da Aula 4?

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

Problemas

Dois inteiros para cada fracção Não é possível desenvolver funções para

somar fracções: funções só devolvem um valor

Código complexo e difícil de perceber

Page 11: Aula 10 Tipos Abstractos de Dados I. 2003/2004 Introdução à Programação 2 Flashback Lembram-se da Aula 4?

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

Objectivo

Escrever programa para somar fracções tão simples como para somar inteiros

Ou seja…

Page 12: Aula 10 Tipos Abstractos de Dados I. 2003/2004 Introdução à Programação 2 Flashback Lembram-se da Aula 4?

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

O nosso objectivo

#include <iostream>

using namespace std;

int main() { cout << "Introduza duas fracções (numerador denominador): "; Racional r1, r2; cin >> r1 >> r2; if(cin.fail()) { cout << "Opps! A leitura dos racionais falhou!" << endl; return 1; } Racional r = r1 + r2; cout << "A soma de " << r1 << " com " << r2 << " é " << r << '.' << endl; }

Lá chegaremos, lá chegaremos…

Page 13: Aula 10 Tipos Abstractos de Dados I. 2003/2004 Introdução à Programação 2 Flashback Lembram-se da Aula 4?

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

Solução

Criar um novo tipo de dados que permita representar um número racional (fracção) com uma só instância

Ou seja, criar um Tipo Abstracto de Dados (TAD)

Page 14: Aula 10 Tipos Abstractos de Dados I. 2003/2004 Introdução à Programação 2 Flashback Lembram-se da Aula 4?

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

Tipos Abstractos de Dados (TAD)

Ou Tipos de Primeira Categoria

Características: Tipo definido pelo programador Comporta-se como os tipos básicos Serve para definir variáveis e constantes com

que se pode operar Representado pelas classes C++

Não confundir “classe C++” com “classe” (propriamente dita)…Pormenores só em POO

Page 15: Aula 10 Tipos Abstractos de Dados I. 2003/2004 Introdução à Programação 2 Flashback Lembram-se da Aula 4?

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

TAD Racional

/** Representa números racionais. */class Racional { public: int numerador; int denominador;};

Variáveis membro ou atributos

Variáveis membro ou atributos

Atenção ao ; final!

Page 16: Aula 10 Tipos Abstractos de Dados I. 2003/2004 Introdução à Programação 2 Flashback Lembram-se da Aula 4?

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

TAD Racional

#include <iostream>#include <cassert>

using namespace std;

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

/** Representa números racionais. */class Racional { public: int numerador; int denominador;};

Page 17: Aula 10 Tipos Abstractos de Dados I. 2003/2004 Introdução à Programação 2 Flashback Lembram-se da Aula 4?

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

Representação gráfica do TAD

Racional

numerador: intdenominador: int

Atributos: instânciasmembro

Operações: rotinasmembro

Nome

Page 18: Aula 10 Tipos Abstractos de Dados I. 2003/2004 Introdução à Programação 2 Flashback Lembram-se da Aula 4?

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

Utilização do TAD

Racional r1;Racional r2;

r1.numerador = 6;r1.denominador = 9;

r2.numerador = 7;r2.denominador = 3;

Cada instância de Racional tem os seus próprios atributos!

Page 19: Aula 10 Tipos Abstractos de Dados I. 2003/2004 Introdução à Programação 2 Flashback Lembram-se da Aula 4?

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

Representações gráficas (I)

r1: Racional

numerador = ?denominador = ?

r2: Racional

numerador = ?denominador = ?

ObjectosInstâncias do TAD

Há quem lhes chame objectos, mas reservaremos esse nome para as classes propriamente ditas.

r1: Racional

numerador = 6denominador = 9

r2: Racional

numerador = 7denominador = 3

Page 20: Aula 10 Tipos Abstractos de Dados I. 2003/2004 Introdução à Programação 2 Flashback Lembram-se da Aula 4?

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

Representações gráficas (II)

r1: Racional

numerador: int

6

denominador: int

9

r2: Racional

numerador: int

7

denominador: int

3

Page 21: Aula 10 Tipos Abstractos de Dados I. 2003/2004 Introdução à Programação 2 Flashback Lembram-se da Aula 4?

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

Acesso a membros de instâncias de um TAD

Operador de selecção de membro: .

instância.membro

Page 22: Aula 10 Tipos Abstractos de Dados I. 2003/2004 Introdução à Programação 2 Flashback Lembram-se da Aula 4?

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

Função somaDe()

/** Devolve a soma de dois racionais. @pre r1.denominador ≠ 0 r2.denominador ≠ 0. @post somaDe = r1 + r2 somaDe.denominador ≠ 0 mdc(somaDe.numerador, somaDe.denominador) = 1. */ Racional somaDe(Racional const r1, Racional const r2) { assert(r1.denominador != 0); assert(r2.denominador != 0);

Racional r;

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

reduz(r);

assert(r.denominador != 0); assert(mdc(r.numerador, r.denominador) == 1);

return r; }

A fazer.

Nome sem sufixo Fracção: redundante dado tipo dos parâmetros.

Page 23: Aula 10 Tipos Abstractos de Dados I. 2003/2004 Introdução à Programação 2 Flashback Lembram-se da Aula 4?

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

Procedimento reduz()

/** Reduz a fracção que representa o racional recebido como argumento. @pre r.denominador ≠ 0 r = r. @post r.denominador ≠ 0 mdc(r.numerador, r.denominador) = 1 r = r. */void reduz(Racional const r){ assert(r.denominador != 0);

int const divisor = mdc(r.numerador, r.denominador);

r.numerador /= divisor; r.denominador /= divisor;

assert(r.denominador != 0); assert(mdc(r.numerador, r.denominador) == 1);}

Nome sem sufixo Fracção: redundante dado tipo dos parâmetros.

Page 24: Aula 10 Tipos Abstractos de Dados I. 2003/2004 Introdução à Programação 2 Flashback Lembram-se da Aula 4?

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

Procedimento lêPara()

/** Lê do teclado um racional, na forma de dois inteiros sucessivos. @pre r = r.

@post Se cin.good() cin tem dois inteiros n e d disponíveis para

leitura, com d <> 0, então r = n/d cin.fail() 0 < r.denominador mdc(r.numerador, r.denominador) = 1,

senão r = r cin.fail(). */void lêPara(Racional& r) { …}

Page 25: Aula 10 Tipos Abstractos de Dados I. 2003/2004 Introdução à Programação 2 Flashback Lembram-se da Aula 4?

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

Procedimento lêPara()

int n, d;

cin >> n >> d; if(not cin.fail()) if(d == 0) cin.setstate(ios_base::failbit); else { if(d < 0) { r.numerador = -n; r.denominador = -d; } else { r.numerador = n; r.denominador = d; } reduz(r);

assert(0 < r.denominador); assert(mdc(r.numerador, r. denominador) == 1); assert(r.numerador * d == n * r.denominador); assert(not cin.fail());

return; }

assert(cin.fail());

Page 26: Aula 10 Tipos Abstractos de Dados I. 2003/2004 Introdução à Programação 2 Flashback Lembram-se da Aula 4?

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

Procedimento escreve()

/** Escreve um racional no ecrã no formato de uma fracção. @pre V. @post cout.fail() cout contém n/d (ou simplesmente n, se d = 1) em que n e d são os valores de r.numerador e r.denominador. */ void escreve(Racional const r) { cout << r.numerador; if(r.denominador != 1) cout << '/' << r.denominador; }

Page 27: Aula 10 Tipos Abstractos de Dados I. 2003/2004 Introdução à Programação 2 Flashback Lembram-se da Aula 4?

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

Programa principal (I)

int main() { // Ler fracções: cout << "Introduza duas fracções (numerador denominador): "; Racional r1, r2; lêPara(r1); lêPara(r2);

if(cin.fail()) { cout << "Opps! A leitura dos racionais falhou!" << endl; return 1; }

(continua)

Page 28: Aula 10 Tipos Abstractos de Dados I. 2003/2004 Introdução à Programação 2 Flashback Lembram-se da Aula 4?

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

Programa principal (II)

// Calcular racional soma: Racional r = somaDe(r1, r2);

// Escrever resultado: cout << "A soma de "; escreve(r1); cout << " com "; escreve(r2); cout << " é "; escreve(r); cout << '.' << endl; }

Page 29: Aula 10 Tipos Abstractos de Dados I. 2003/2004 Introdução à Programação 2 Flashback Lembram-se da Aula 4?

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

Inicialização

Para inicializar um racional:

Racional a;a.numerador = 10;a.denominador = 0;

Para inicializar um inteiro:

int a = 10;int a(10);

Mas como inicializar um racional tão simplesmente como um inteiro?

Como evitar inicializações inválidas?

Page 30: Aula 10 Tipos Abstractos de Dados I. 2003/2004 Introdução à Programação 2 Flashback Lembram-se da Aula 4?

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

Rotinas membro?

Sim! Classes C++ podem ter rotinas membro! Operação: declaração de rotina membro Método: definição de rotina membro

Diz-se que as classes C++ têm operações que são implementadas por métodos

Page 31: Aula 10 Tipos Abstractos de Dados I. 2003/2004 Introdução à Programação 2 Flashback Lembram-se da Aula 4?

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

Construtores (I)

Construir uma instância de um TAD é instanciá-lo

Durante a construção é invocada uma operação especial: um construtor

Como não definimos um construtor, o compilador forneceu um que não faz nada

Page 32: Aula 10 Tipos Abstractos de Dados I. 2003/2004 Introdução à Programação 2 Flashback Lembram-se da Aula 4?

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

Construtores: declaração

/** Representa números racionais. */class Racional { public: /** Constrói racional com valor inteiro. @pre V. @post *this = n 0 < denominador mdc(numerador, denominador) = 1. */ Racional(int const n = 0);

/** Constrói racional correspondente a n/d. @pre d ≠ 0. @post *this = n/d 0 < denominador mdc(numerador, denominador) = 1. */ Racional(int const n, int const d);

int numerador; int denominador; };

Construtor invocável sem argumentos: constrói racional 0/1

Construtor que recebe como argumento o numerador: constrói racional n/1

Construtor que recebe como argumentos o numerador e o denominador: constrói racional n/d

Page 33: Aula 10 Tipos Abstractos de Dados I. 2003/2004 Introdução à Programação 2 Flashback Lembram-se da Aula 4?

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

Construtores: implementação (I)

class Racional { …

};

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

assert(0 < denominador); assert(mdc(numerador, denominador) == 1); }

(continua)

Lista de inicializadores

Prefixo identifica classe a que o método pertence

Page 34: Aula 10 Tipos Abstractos de Dados I. 2003/2004 Introdução à Programação 2 Flashback Lembram-se da Aula 4?

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

Construtores: implementação (II)

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

if(d < 0) { numerador = -n; denominador = -d; } else { numerador = n; denominador = d; }

reduz(*this);

assert(0 < denominador); assert(mdc(numerador, denominador) == 1); assert(numerador * d == n * denominador);}

Variável, ou melhor, instância implícita, ou seja, a instância que está em construção

Acesso directo a atributos da instância impícita

Page 35: Aula 10 Tipos Abstractos de Dados I. 2003/2004 Introdução à Programação 2 Flashback Lembram-se da Aula 4?

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

Construtores: implementação (III)

if(d < 0) { numerador = -n; denominador = -d; } else { numerador = n; denominador = d; }

reduz(*this);

Garante-se denominador positivo e representação em termos mínimos.Para quê?

Page 36: Aula 10 Tipos Abstractos de Dados I. 2003/2004 Introdução à Programação 2 Flashback Lembram-se da Aula 4?

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

A reter...

*this: explicitação da instância implícita Construtores:

operações com mesmo nome da classe não têm tipo de devolução sobrecarregáveis

Se não forem definidos construtores: C++ fornece um sem parâmetros e que não faz nada

Atributos da instância implícita directamente acessíveis dentro de métodos

Operações declaradas dentro da classe Métodos definidos fora da classe

Page 37: Aula 10 Tipos Abstractos de Dados I. 2003/2004 Introdução à Programação 2 Flashback Lembram-se da Aula 4?

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

O que já podemos fazer

Racional r1;Racional r2(6, 9);

escreve(r1);

escreve(r2);

Aparece 0! TAD nunca têm lixo!

Aparece 2/3

Construtores invocados automaticamente

Page 38: Aula 10 Tipos Abstractos de Dados I. 2003/2004 Introdução à Programação 2 Flashback Lembram-se da Aula 4?

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

O que ainda podemos fazer...

Racional r(6, 9);r.denominador = 0;

O denominador tem de ser diferente de zero.

Como impedir acesso indevidos?

Page 39: Aula 10 Tipos Abstractos de Dados I. 2003/2004 Introdução à Programação 2 Flashback Lembram-se da Aula 4?

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

Categorias de acesso

Os membros podem ser públicos (public) protegidos (protected) privados (private)

Page 40: Aula 10 Tipos Abstractos de Dados I. 2003/2004 Introdução à Programação 2 Flashback Lembram-se da Aula 4?

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

Categorias de acesso

Os membros podem ser públicos (public) protegidos (protegidos (protectedprotected)) privados (private)

POO!

Acessíveis por todos

Acessíveis apenas pelos membros da classe

Page 41: Aula 10 Tipos Abstractos de Dados I. 2003/2004 Introdução à Programação 2 Flashback Lembram-se da Aula 4?

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

Princípio do encapsulamento

Tudo o que pode ser privado, deve ser privado!

Regra: Todos os atributos das classes devem ser privados

Os construtores da classe foram feitos públicos: porquê?

Excepção: constantes podem ocasionalmente ser públicas

Page 42: Aula 10 Tipos Abstractos de Dados I. 2003/2004 Introdução à Programação 2 Flashback Lembram-se da Aula 4?

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

Atributos privados

/** Representa números racionais. */class Racional { public: /** Constrói racional com valor inteiro. @pre V. @post *this = n 0 < denominador mdc(numerador, denominador) = 1. */ Racional(int const n = 0);

/** Constrói racional correspondente a n/d. @pre d ≠ 0. @post *this = n/d 0 < denominador mdc(numerador, denominador) = 1. */ Racional(int const n, int const d);

private: int numerador; int denominador; };

Page 43: Aula 10 Tipos Abstractos de Dados I. 2003/2004 Introdução à Programação 2 Flashback Lembram-se da Aula 4?

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

Continua tudo a funcionar?

Racional r(6, 9);

escreve(r);Não tem acesso aos atributos por serem privados.

Faça-se o procedimento membro!

Page 44: Aula 10 Tipos Abstractos de Dados I. 2003/2004 Introdução à Programação 2 Flashback Lembram-se da Aula 4?

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

Operação Racional::escreve()/** Representa números racionais. */class Racional { public: …

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

private: int numerador; int denominador; }; Operação pública.

Porquê?

Page 45: Aula 10 Tipos Abstractos de Dados I. 2003/2004 Introdução à Programação 2 Flashback Lembram-se da Aula 4?

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

Método Racional::escreve()

void Racional::escreve() { cout << numerador; if(denominador != 1) cout << '/' << denominador; }

Page 46: Aula 10 Tipos Abstractos de Dados I. 2003/2004 Introdução à Programação 2 Flashback Lembram-se da Aula 4?

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

Invocação de operações

Operador de selecção de membro: .

Racional r1();Racional r2(6, 9);

r1.escreve();r2.escreve();

Numerador de quem?

void Racional::escreve() { cout << numerador; if(denominador != 1) cout << '/' << denominador; }

Page 47: Aula 10 Tipos Abstractos de Dados I. 2003/2004 Introdução à Programação 2 Flashback Lembram-se da Aula 4?

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

Operação Racional::somaCom()/** Representa números racionais. */class Racional { public: …

/** Devolve a soma de dois racionais. @pre denominador ≠ 0 r2.denominador ≠ 0. @post somaDe = *this + r2 denominador ≠ 0 somaDe.denominador ≠ 0 mdc(somaDe.numerador, somaDe.denominador) = 1. */ Racional somaCom(Racional const r2);

private: int numerador; int denominador; };

Page 48: Aula 10 Tipos Abstractos de Dados I. 2003/2004 Introdução à Programação 2 Flashback Lembram-se da Aula 4?

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

Método Racional::somaCom()

Racional Racional::somaCom(Racional const r2) { assert(denominador != 0); assert(r2.denominador != 0);

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

r.reduz();

assert(denominador != 0); assert(r.denominador != 0); assert(mdc(r.numerador, r.denominador) == 1);

return r; }

Soma da instância implícita com r2.

Page 49: Aula 10 Tipos Abstractos de Dados I. 2003/2004 Introdução à Programação 2 Flashback Lembram-se da Aula 4?

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

Operação Racional::lê()

/** Representa números racionais. */class Racional { public: …

/** 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() 0 < denominador mdc(numerador, denominador) = 1, senão *this = r cin.fail(). */ void lê();

private: int numerador; int denominador; };

Page 50: Aula 10 Tipos Abstractos de Dados I. 2003/2004 Introdução à Programação 2 Flashback Lembram-se da Aula 4?

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

Método Racional::lê()

void Racional::lê() { …}

int n, d;

cin >> n >> d; if(not cin.fail()) if(d == 0) cin.setstate(ios_base::failbit); else { if(d < 0) { numerador = -n; denominador = -d; } else { numerador = n; denominador = d; } reduz();

assert(0 < denominador); assert(mdc(numerador, denominador) == 1); assert(numerador * d == n * denominador); assert(not cin.fail());

return; }

assert(cin.fail());

Page 51: Aula 10 Tipos Abstractos de Dados I. 2003/2004 Introdução à Programação 2 Flashback Lembram-se da Aula 4?

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

Operação Racional::reduz()

/** Representa números racionais. */class Racional { public: …

private: /** Reduz a fracção que representa o racional recebido como argumento. @pre denominador ≠ 0 r = r. @post denominador ≠ 0 mdc(numerador, denominador) = 1 *this = r. */ void reduz();

int numerador; int denominador; };

Operação privada. Porquê?

Page 52: Aula 10 Tipos Abstractos de Dados I. 2003/2004 Introdução à Programação 2 Flashback Lembram-se da Aula 4?

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

Método Racional::reduz()

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

int const divisor = mdc(numerador, denominador); numerador /= divisor; denominador /= divisor;

assert(denominador != 0); assert(mdc(numerador, denominador) == 1);}

Page 53: Aula 10 Tipos Abstractos de Dados I. 2003/2004 Introdução à Programação 2 Flashback Lembram-se da Aula 4?

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

Programa principal (I)

int main() { // Ler fracções: cout << "Introduza duas fracções (numerador denominador): "; Racional r1, r2; r1.lê(); r2.lê();

if(cin.fail()) { cout << "Opps! A leitura dos racionais falhou!" << endl; return 1; }

(continua)

Page 54: Aula 10 Tipos Abstractos de Dados I. 2003/2004 Introdução à Programação 2 Flashback Lembram-se da Aula 4?

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

Programa principal (II)

(continuação)

// Calcular racional soma: Racional r = r1.somaCom(r2);

// Escrever resultado: cout << "A soma de "; r1.escreve(); cout << " com "; r2.escreve(); cout << " é "; r.escreve(); cout << '.' << endl; }

Horrendo!

Page 55: Aula 10 Tipos Abstractos de Dados I. 2003/2004 Introdução à Programação 2 Flashback Lembram-se da Aula 4?

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

E mdc()?

Deveria passar a membro?

Porquê?

Page 56: Aula 10 Tipos Abstractos de Dados I. 2003/2004 Introdução à Programação 2 Flashback Lembram-se da Aula 4?

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

Classe é módulo por excelência

Interface Parte pública

Implementação Parte privada Métodos (implementação das operações)

Manual de utilização (contrato) Comentário de documentação da classe Manual de utilização de cada operação pública

Page 57: Aula 10 Tipos Abstractos de Dados I. 2003/2004 Introdução à Programação 2 Flashback Lembram-se da Aula 4?

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

Desenho de TAD

Começar sempre:

pela interface e

pelo contrato.

Page 58: Aula 10 Tipos Abstractos de Dados I. 2003/2004 Introdução à Programação 2 Flashback Lembram-se da Aula 4?

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

Condição Invariante da Classe

Condição Invariante da Classe (CIC) Racional:

0 < denominador mdc(numerador, denominador) = 1

Condição mais forte que se verifica sempre para todas as instâncias de uma classe

Reflecte as assunções do produtor da classe acerca da sua implementação

Objectivo: verificar erros do programador Deve verificar-se no início e no fim de cada método não-

privado (no final dos construtores)

Page 59: Aula 10 Tipos Abstractos de Dados I. 2003/2004 Introdução à Programação 2 Flashback Lembram-se da Aula 4?

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

Operação Racional::cumpreInvariante()

/** Representa números racionais. @invariant 0 < denominador mdc(numerador, denominador) = 1. */class Racional { public: …

private: /** Indica se a CIC se verifica.      @pre V.      @post  cumpreInvariante = 0 < denominador mdc(numerador, denominador) = 1. */ bool cumpreInvariante();

int numerador; int denominador; };

Page 60: Aula 10 Tipos Abstractos de Dados I. 2003/2004 Introdução à Programação 2 Flashback Lembram-se da Aula 4?

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

Método Racional::cumpreInvariante()

bool Racional::cumpreInvariante() { return 0 < denominador and mdc(numerador, denominador) == 1;}

Page 61: Aula 10 Tipos Abstractos de Dados I. 2003/2004 Introdução à Programação 2 Flashback Lembram-se da Aula 4?

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

Operação Racional::Racional()/** … */class Racional { public: /** Constrói racional com valor inteiro. @pre V. @post *this = n. */ Racional(int const n = 0);

private: …};

Page 62: Aula 10 Tipos Abstractos de Dados I. 2003/2004 Introdução à Programação 2 Flashback Lembram-se da Aula 4?

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

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

assert(cumpreInvariante()); }

Page 63: Aula 10 Tipos Abstractos de Dados I. 2003/2004 Introdução à Programação 2 Flashback Lembram-se da Aula 4?

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

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

/** Constrói racional correspondente a n/d. @pre d ≠ 0. @post *this = n/d. */ Racional(int const n, int const d);

private: …};

Page 64: Aula 10 Tipos Abstractos de Dados I. 2003/2004 Introdução à Programação 2 Flashback Lembram-se da Aula 4?

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

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

if(d < 0) { numerador = -n; denominador = -d; } else { numerador = n; denominador = d; }

reduz();

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

Page 65: Aula 10 Tipos Abstractos de Dados I. 2003/2004 Introdução à Programação 2 Flashback Lembram-se da Aula 4?

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

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

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

private: …};

Page 66: Aula 10 Tipos Abstractos de Dados I. 2003/2004 Introdução à Programação 2 Flashback Lembram-se da Aula 4?

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

Método Racional::escreve()

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

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

assert(cumpreInvariante());}

Page 67: Aula 10 Tipos Abstractos de Dados I. 2003/2004 Introdução à Programação 2 Flashback Lembram-se da Aula 4?

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

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

/** Devolve a soma de dois racionais. @pre V. @post somaDe = *this + r2. */ Racional somaCom(Racional const r2);

private: …};

Page 68: Aula 10 Tipos Abstractos de Dados I. 2003/2004 Introdução à Programação 2 Flashback Lembram-se da Aula 4?

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

Método Racional::somaCom()

Racional Racional::somaCom(Racional const r2) { assert(cumpreInvariante()); assert(r2.cumpreInvariante());

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

r.reduz();

assert(cumpreInvariante()); assert(r.cumpreInvariante());

return r; }

Page 69: Aula 10 Tipos Abstractos de Dados I. 2003/2004 Introdução à Programação 2 Flashback Lembram-se da Aula 4?

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

Operação Racional::lê()

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

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

private: …};

Page 70: Aula 10 Tipos Abstractos de Dados I. 2003/2004 Introdução à Programação 2 Flashback Lembram-se da Aula 4?

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

Método Racional::lê()

void Racional::lê() { …}

assert(cumpreInvariante());

int n, d;

cin >> n >> d; if(not cin.fail()) if(d == 0) cin.setstate(ios_base::failbit); else { if(d < 0) { numerador = -n; denominador = -d; } else { numerador = n; denominador = d; } reduz();

assert(cumpreInvariante()); assert(numerador * d == n * denominador); assert(not cin.fail());

return; }

assert(cumpreInvariante()); assert(cin.fail());

Page 71: Aula 10 Tipos Abstractos de Dados I. 2003/2004 Introdução à Programação 2 Flashback Lembram-se da Aula 4?

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

Aula 10: Sumário

Necessidade de TAD: acrescentando tipos ao C++ Sintaxe da definição de classes C++ Sintaxe da definição de variáveis e constantes de uma classe C++: as instâncias e a

instanciação Variáveis e constantes membro: instâncias membro ou atributos Acesso a atributos membro de uma classe C++: operador de selecção de membro. Rotinas membro:

Operações e métodos Declaração vs. definição. A construção TAD::

Acesso a membros de uma classe C++: a instância implícita Construtores:

Sintaxe Utilização

Parâmetros com argumentos por omissão de novo Categorias e políticas de acesso:

Membros públicos Membros privados

Princípio do encapsulamento: aplicação aos TAD Noção de condição invariante de classe (CIC): regras e vantagens Exemplos com o TAD Racional, para concretização do conceito de número racional