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

Slides:



Advertisements
Apresentações semelhantes
Um programa em C Bibliotecas Variáveis globais
Advertisements

Recursividade Função recursiva é aquela que chama a si própria.
Métodos, Parâmetros, Argumentos e Contratos
Recursividade Prof. Rosana Palazon.
Recursividade e Iteração Factorial, Fibonacci e Maior Divisor Comum
Exercícios de revisão.
LINGUAGEM ESTRUTURADA TURBO C
Curso de Programação em C++
Linguagem C Estruturas de Seleção.
Funções.
Modularização: funções e procedimentos
1 Aula 5 Instâncias dinâmicas. 2003/2004 Programação Orientada para Objectos 2 Instâncias… int j = 20; int f() { int const i = 10; // … } Constante automática.
Matrizes clássicas e vectores em C++
1 Aula 4 Ponteiros. 2003/2004 Programação Orientada para Objectos 2 Instâncias de um programa C++ int i = 10; Nome: i Tipo: int Valor: 10.
Aula 7 Instrução de iteração while. 2003/2004 Introdução à Programação 2 passo [G][G] [¬G][¬G] Início da actividade Fim da actividade Actividade Transição.
Aula 11 Tipos Abstractos de Dados II. 2003/2004 Introdução à Programação 2 Estrutura global do programa #include using namespace std; int mdc(int const.
Modularização: funções e procedimentos (continuação)
1 Aula 3 Listas e iteradores (cont.). 2003/2004 Programação Orientada para Objectos 2 ListaDeInt : interface class ListaDeInt { public: typedef int Item;
Aula 8 Polimorfismo.
Metodologia de Dijkstra para desenvolvimento de ciclos
Programação Baseada em Objectos Desenho de TAD
Aula 6 Instruções de selecção e instruções condicionais.
1 Aula 7 Herança. 2003/2004 Programação Orientada para Objectos 2 Conceitos fundamentais: Herança Polimorfismo Ligação dinâmica.
Sobrecarga de nomes de rotinas Rotinas recursivas Invocação de rotinas
Aula 13 Tipos Abstractos de Dados IV. 2003/2004 Introdução à Programação 2 Estrutura global do programa (I) Construtores Inspectores.
Algoritmos e linguagens de programação 1 (aula 05)
Revisão /*======================================================*/
1 programa dados Utilização de ficheiros externos A maneira mais simples de escrever para um ficheiro externo é redireccionar a saída de um programa: em.
1 programa dados Utilização de ficheiros externos A maneira mais simples de escrever para um ficheiro externo é redireccionar a saída de um programa: em.
Informática e Computação Estrutura de Repetição aula 13
Exercício 1 Faça um programa que receba como entrada o nome e o salário de um funcionário de uma empresa e que calcule o novo valor do salário do.
Aula 07.
PROGRAMAÇÃO ESTRUTURADA II
Linguagem de Programação I Parte II
Uma classe para vectores
Professor: Bruno Moser de Alvarenga
Linguagem de Programação II
Programação II Estruturas de Dados Aula 02 - continuação
VETORES Roteiro da aula Referência ao Programa: Estrutura de Dados
Programação em C++ Compiladores
Procedural vs. OO (Figuras Geométricas: Área do triângulo)
CES-10 INTRODUÇÃO À COMPUTAÇÃO Aulas Práticas – 2014
Técnicas de Desenvolvimento de Programas
Linguagem de Programação
Roteiro Jogo de adivinhação Tarefa Desafio Algoritmo do jogo
Informática e Computação Estrutura de Repetição aula 12
FACULDADE DE CIÊNCIAS SOCIAIS E TECNOLÓGICAS Tecnologia em Redes de Computadores Algoritmos e linguagens de programação 1 (aula 07) Prof. Alessandro Bernardo.
Introdução à Linguagem C
Algoritmos – Exercícios no Visualg
 São utilizadas para dividir um código maior (mais complexo) em partes menores (mais simples).  Quando uma mesma tarefa é realizada várias vezes em um.
CES-10 INTRODUÇÃO À COMPUTAÇÃO Aulas Práticas – 2014 Capítulo VII Variáveis Indexadas Numéricas.
Estruturas de Dados Aula 6: Cadeias de Caracteres
CES-10 INTRODUÇÃO À COMPUTAÇÃO Aulas Práticas – 2013
Revisão Luis Antonio Tavares
CES-10 INTRODUÇÃO À COMPUTAÇÃO Aulas Práticas – 2014 Capítulo III Comandos de Controle.
CES-10 INTRODUÇÃO À COMPUTAÇÃO Aulas Práticas – 2014 Capítulo IX Subprogramação e Recursividade.
CONHECER MELHOR OS NÚMEROS
1Unidade – Estrutura Condicional CASE Algoritmos e Linguagens de Programação Estrutura Condicional CASE Faculdade INED – Abril 2007 Prof. Edwar.
Programação II Prof. Mateus Raeder Universidade do Vale do Rio dos Sinos - São Leopoldo - Transparências baseadas nos originais da profa. Renata Galante.
Informática e Computação Aula 12 Estrutura de Repetição
FACULDADE DE CIÊNCIAS SOCIAIS E TECNOLÓGICAS Tecnologia em Redes de Computadores Algoritmos e linguagens de programação 1 (aula 08) Prof. Alessandro Bernardo.
VETORES AULA 01 Roteiro da aula Referência ao Programa: Estrutura de Dados.  Variáveis Compostas homogenias   Objetivo: apresentar VETOR.
Linguaguem de Programação II
Fundamentos de Programação 1 Aula N. 02 Prof. SIMÃO Jean Marcelo SIMÃO Linguagem C “Laços de Repetição em C”
1 Aula 07 Strings Prof. Filipe Mutz. 2 Em nossos programas ainda não vimos como armazenar palavras e textos, e eles são muito importantes! Exemplos: Programas.
Not good.
Introdução a Programação
CES-11 ALGORITMOS E ESTRUTURAS DE DADOS Aulas Práticas
Ponteiros Parte III.
CES-11 ALGORITMOS E ESTRUTURAS DE DADOS Aulas Práticas
Transcrição da apresentação:

Aula 10 Tipos Abstractos de Dados I

2003/2004 Introdução à Programação 2 Flashback Lembram-se da Aula 4?

2003/2004 Introdução à Programação 3 Soma de fracções (I) #include using namespace std; /** Devolve o máximo divisor comum dos inteiros passados como m 0 ou n 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)

2003/2004 Introdução à Programação 4 Soma de fracções (II) /** Reduz a fracção recebida como denominador 0 numerador = n denominador = 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)

2003/2004 Introdução à Programação 5 Soma de fracções (III) /** Lê do teclado uma fracção, na forma de dois inteiros numerador = n denominador = 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.

2003/2004 Introdução à Programação 6 Soma de fracções (IV) /** Soma duas denominador1 0 denominador2 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!

2003/2004 Introdução à Programação 7 Soma de fracções (V) /** Escreve uma fracção no ecrã no formato 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)

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

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

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

2003/2004 Introdução à Programação 11 Objectivo Escrever programa para somar fracções tão simples como para somar inteiros Ou seja…

2003/2004 Introdução à Programação 12 O nosso objectivo #include 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…

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

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

2003/2004 Introdução à Programação 15 TAD Racional /** Representa números racionais. */ class Racional { public: int numerador; int denominador; }; Variáveis membro ou atributos Atenção ao ; final!

2003/2004 Introdução à Programação 16 TAD Racional #include using namespace std; int mdc(int const m, int const n) { … } /** Representa números racionais. */ class Racional { public: int numerador; int denominador; }; …

2003/2004 Introdução à Programação 17 Representação gráfica do TAD Racional numerador : int denominador : int Atributos: instâncias membro Operações: rotinas membro Nome

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

2003/2004 Introdução à Programação 19 Representações gráficas (I) r1 : Racional numerador = ? denominador = ? r2 : Racional numerador = ? denominador = ? Objectos Instâncias do TAD Há quem lhes chame objectos, mas reservaremos esse nome para as classes propriamente ditas. r1 : Racional numerador = 6 denominador = 9 r2 : Racional numerador = 7 denominador = 3

2003/2004 Introdução à Programação 20 Representações gráficas (II) r1 : Racionalnumerador : int 6 denominador : int 9 r2 : Racionalnumerador : int 7 denominador : int 3

2003/2004 Introdução à Programação 21 Acesso a membros de instâncias de um TAD Operador de selecção de membro:. instância.membro

2003/2004 Introdução à Programação 22 Função somaDe() /** Devolve a soma de dois r1.denominador 0 r2.denominador 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.

2003/2004 Introdução à Programação 23 Procedimento reduz() /** Reduz a fracção que representa o racional recebido como r.denominador 0 r = 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.

2003/2004 Introdução à Programação 24 Procedimento lêPara() /** Lê do teclado um racional, na forma de dois inteiros r = 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) { … }

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

2003/2004 Introdução à Programação 26 Procedimento escreve() /** Escreve um racional no ecrã no formato de uma 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; }

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

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

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

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

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

2003/2004 Introdução à Programação 32 Construtores: declaração /** Representa números racionais. */ class Racional { public: /** Constrói racional com valor * this = n 0 < denominador mdc( numerador, denominador ) = 1. */ Racional(int const n = 0); /** Constrói racional correspondente a n / d * 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

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

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

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

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

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

2003/2004 Introdução à Programação 38 O que ainda podemos fazer... Racional r(6, 9); r.denominador = 0; O denominador tem de ser diferente de zero. Como impedir acesso indevidos?

2003/2004 Introdução à Programação 39 Categorias de acesso Os membros podem ser públicos ( public ) protegidos ( protected ) privados ( private )

2003/2004 Introdução à Programação 40 Categorias de acesso POO! Acessíveis por todos Acessíveis apenas pelos membros da classe

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

2003/2004 Introdução à Programação 42 Atributos privados /** Representa números racionais. */ class Racional { public: /** Constrói racional com valor * this = n 0 < denominador mdc( numerador, denominador ) = 1. */ Racional(int const n = 0); /** Constrói racional correspondente a n / d * this = n / d 0 < denominador mdc( numerador, denominador ) = 1. */ Racional(int const n, int const d); private: int numerador; int denominador; };

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

2003/2004 Introdução à Programação 44 Operação Racional::escreve() /** Representa números racionais. */ class Racional { public: … /** Escreve um racional no ecrã no formato de uma 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ê?

2003/2004 Introdução à Programação 45 Método Racional::escreve() void Racional::escreve() { cout << numerador; if(denominador != 1) cout << '/' << denominador; }

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

2003/2004 Introdução à Programação 47 Operação Racional::somaCom() /** Representa números racionais. */ class Racional { public: … /** Devolve a soma de dois denominador 0 r2.denominador somaDe = * this + r2 denominador 0 somaDe.denominador 0 mdc( somaDe.numerador, somaDe.denominador ) = 1. */ Racional somaCom(Racional const r2); private: int numerador; int denominador; };

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

2003/2004 Introdução à Programação 49 Operação Racional::lê() /** Representa números racionais. */ class Racional { public: … /** Lê do teclado um racional, na forma de dois inteiros * this = 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; };

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

2003/2004 Introdução à Programação 51 Operação Racional::reduz() /** Representa números racionais. */ class Racional { public: … private: /** Reduz a fracção que representa o racional recebido como denominador 0 r = denominador 0 mdc( numerador, denominador ) = 1 * this = r. */ void reduz(); int numerador; int denominador; }; Operação privada. Porquê?

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

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

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

2003/2004 Introdução à Programação 55 E mdc() ? Deveria passar a membro? Porquê?

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

2003/2004 Introdução à Programação 57 Desenho de TAD Começar sempre: pela interface e pelo contrato.

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

2003/2004 Introdução à Programação 59 Operação Racional::cumpreInvariante() /** Representa números 0 < denominador mdc( numerador, denominador ) = 1. */ class Racional { public: … private: /** Indica se a CIC se cumpreInvariante = 0 < denominador mdc( numerador, denominador ) = 1. */ bool cumpreInvariante(); int numerador; int denominador; };

2003/2004 Introdução à Programação 60 Método Racional::cumpreInvariante() bool Racional::cumpreInvariante() { return 0 < denominador and mdc(numerador, denominador) == 1; }

2003/2004 Introdução à Programação 61 Operação Racional::Racional() /** … */ class Racional { public: /** Constrói racional com valor * this = n. */ Racional(int const n = 0); … private: … };

2003/2004 Introdução à Programação 62 Método Racional::Racional() Racional::Racional(int const n) : numerador(n), denominador(1) { assert(cumpreInvariante()); }

2003/2004 Introdução à Programação 63 Operação Racional::Racional() /** … */ class Racional { public: … /** Constrói racional correspondente a n / d * this = n / d. */ Racional(int const n, int const d); … private: … };

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

2003/2004 Introdução à Programação 65 Operação Racional::escreve() /** … */ class Racional { public: … /** Escreve um racional no ecrã no formato de uma 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: … };

2003/2004 Introdução à Programação 66 Método Racional::escreve() void Racional::escreve() { assert(cumpreInvariante()); cout << numerador; if(denominador != 1) cout << '/' << denominador; assert(cumpreInvariante()); }

2003/2004 Introdução à Programação 67 Operação Racional::somaCom() /** … */ class Racional { public: … /** Devolve a soma de dois somaDe = * this + r2. */ Racional somaCom(Racional const r2); … private: … };

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

2003/2004 Introdução à Programação 69 Operação Racional::lê() /** … */ class Racional { public: … /** Lê do teclado um racional, na forma de dois inteiros * this = 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: … };

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

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