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

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

Programação Baseada em Objectos Desenho de TAD

Apresentações semelhantes


Apresentação em tema: "Programação Baseada em Objectos Desenho de TAD"— Transcrição da apresentação:

1 Programação Baseada em Objectos Desenho de TAD
Aula 14 Programação Baseada em Objectos Desenho de TAD

2 Desenvolver uma calculadora
Operações: + – adição - – subtracção / – divisão * – multiplicação ^ – potenciação Suporte para double (incluindo negativos) Parênteses proibidos Expressões de cin Resultados em cout Expressões terminam em ; ou . Símbolo . termina execução da calculadora Introdução à Programação 2003/2004

3 Introdução à Programação
Exemplo Entrada: 2 + 2 ; 2 * 2.5 . Saída: 4 5 Introdução à Programação 2003/2004

4 Introdução à Programação
Exercício Qual o resultado de 2 * * 5 ^ 2 ; ? E se os símbolos forem lidos um de cada vez? (Símbolos são valores ou operadores, incluindo terminadores) Introdução à Programação 2003/2004

5 Introdução à Programação
Cálculo de expressão 1 Símbolo lido: Introdução à Programação 2003/2004

6 Introdução à Programação
Cálculo de expressão + Que fazer aos símbolos lidos? Ao 1 e ao +? É necessário guardá-los algures! Símbolo lido: Introdução à Programação 2003/2004

7 Introdução à Programação
Cálculo de expressão 4 Podemos calcular já 1 + 4? Não! Depende do que se segue! Símbolo lido: Introdução à Programação 2003/2004

8 Introdução à Programação
Cálculo de expressão * Calcular já 1 + 4 teria sido asneira! A não ser que se tivesse lido 1 * 4, ou se o símbolo lido fosse + Nesse caso podíamos fazer já o cálculo, e escusávamos de memorizar tantos símbolos Símbolo lido: Memorizar… No nosso programa teremos de guardar os símbolos algures! Introdução à Programação 2003/2004

9 Introdução à Programação
Cálculo de expressão 3 E a saga continua Símbolo lido: Introdução à Programação 2003/2004

10 Introdução à Programação
Cálculo de expressão / Podemos calcular o produto anterior, ou seja, 4 * 3! O resultado do produto tem de ser guardado O produto é o dos dois últimos valores lidos Regra: Ao ler um operador, podemos calcular os operadores em espera enquanto forem de precedência maior ou igual Símbolo lido: Por ordem inversa à da leitura! Podem-se empilhar os operadores! Introdução à Programação 2003/2004

11 Introdução à Programação
Cálculo de expressão 2 Mais uma vez é necessário guardar o valor Se a próxima operação for, por exemplo, +, a divisão é calculada entre 12 e 2, que foram os últimos valores considerados Símbolo lido: Também se podem empilhar os valores! Introdução à Programação 2003/2004

12 Introdução à Programação
Regressemos ao início Vamos recomeçar o cálculo, mas equipando-nos com duas pilhas: Pilha dos operadores Pilha dos valores Introdução à Programação 2003/2004

13 Introdução à Programação
Cálculo de expressão Lido um valor, há que colocá-lo na respectiva pilha Símbolo lido: 1 operadores valores Introdução à Programação 2003/2004

14 Introdução à Programação
Cálculo de expressão Lido um operador, há que verificar se há algum outro de maior ou igual precedência na pilha Como não há, há que o colocar na pilha apropriada Símbolo lido: + 1 operadores valores Introdução à Programação 2003/2004

15 Introdução à Programação
Cálculo de expressão Valores vão sempre para a pilha Símbolo lido: 4 + 1 operadores valores Introdução à Programação 2003/2004

16 Introdução à Programação
Cálculo de expressão Como a multiplicação tem maior precedência que a soma, que está no topo da pilha, não se pode ainda realizar a soma É necessário, de qualquer forma, colocar a multiplicação no topo da pilha Símbolo lido: * 4 + 1 operadores valores Introdução à Programação 2003/2004

17 Introdução à Programação
Cálculo de expressão É um valor… Símbolo lido: 3 * 4 + 1 operadores valores Introdução à Programação 2003/2004

18 Introdução à Programação
Cálculo de expressão No topo da pilha há um operador com igual precedência Antes de guardar a nova operação na pilha, efectua-se a do topo e guarda-se o resultado Símbolo lido: / 3 12 * 4 = + 1 operadores valores Introdução à Programação 2003/2004

19 Introdução à Programação
Cálculo de expressão Valores vão directos para a pilha, como sempre Símbolo lido: 2 / 12 + 1 operadores valores Introdução à Programação 2003/2004

20 Introdução à Programação
Cálculo de expressão Como a potenciação tem maior precedência que a divisão, que está no topo da pilha, não se pode ainda realizar a divisão É necessário, de qualquer forma, colocar a potenciação no topo da pilha Símbolo lido: ^ 2 / 12 + 1 operadores valores Introdução à Programação 2003/2004

21 Introdução à Programação
Cálculo de expressão Pilha com ele! Símbolo lido: 3 ^ 2 / 12 + 1 operadores valores Introdução à Programação 2003/2004

22 Introdução à Programação
Cálculo de expressão Têm de se realizar todas as operações com precedência maior ou igual! Símbolo lido: - 3 ^ 2 8 / 12 = + 1 operadores valores Introdução à Programação 2003/2004

23 Introdução à Programação
Cálculo de expressão Têm de se realizar todas as operações com precedência maior ou igual! Símbolo lido: - 8 1,5 / 12 = + 1 operadores valores Introdução à Programação 2003/2004

24 Introdução à Programação
Cálculo de expressão Têm de se realizar todas as operações com precedência maior ou igual! Depois, guarda-se a operação na pilha Símbolo lido: - 2,5 1,5 = + 1 operadores valores Introdução à Programação 2003/2004

25 Introdução à Programação
Cálculo de expressão Mais um… Símbolo lido: 2 - 2,5 operadores valores Introdução à Programação 2003/2004

26 Introdução à Programação
Cálculo de expressão Ao atingir o símbolo . (ponto), efectuam-se todas as operações que restam na pilha Símbolo lido: . 0,5 2 = - 2,5 operadores valores Introdução à Programação 2003/2004

27 Introdução à Programação
Cálculo de expressão Ao atingir o símbolo . (ponto), efectuam-se todas as operações que restam na pilha O resultado retira-se da pilha dos valores: Símbolo lido: 0,5 operadores valores Introdução à Programação 2003/2004

28 Introdução à Programação
E agora? É necessário escrever o programa… Mas já se sabe que ferramentas estão em falta: Um TAD para representar operadores Um TAD para representar uma calculadora E… Introdução à Programação 2003/2004

29 Introdução à Programação
TAD Operador Representa operadores (binários) que podem ser +, -, *, / ou ^ Construtor deve receber símbolo indicando operação a realizar Deve possuir operação para calcular resultado da sua aplicação a dois operandos double Introdução à Programação 2003/2004

30 Introdução à Programação
TAD Operador /** Representa um operador aritmético, com o qual se podem realizar operações. @invariant ?. */ class Operador { public: }; Introdução à Programação 2003/2004

31 Construtor Operador::Operador()
A utilização de explicit impede a conversão implícita de char em Operador. /** … */ class Operador { public: /** Constrói um novo operador correspondente ao símbolo dado. @pre símbolo pertence a {'+', '-', '*', '/', '^'}. @post Operador é o operador representado por símbolo. */ explicit Operador(char const símbolo); }; Código possível: Operador multiplicação(‘*’); Introdução à Programação 2003/2004

32 Operação Operador::operator()()
/** … */ class Operador { public: /** Devolve o resultado do operador quando aplicado aos operandos dados. @pre *this ≠ Operador(‘/’)  operando_direito ≠ 0. @post operator() = operando_esquerdo *this operando_direito. */ double operator()(double const operando_esquerdo, double const operando_direito) const; }; Chiça! O operador parênteses é usado na invocação de rotinas. É um operador n-ário, que pode ser sobrecarregado! Código possível: Operador multiplicação(‘*’); cout << multiplicação(2.0, 3.0) << endl; Introdução à Programação 2003/2004

33 Operação Operador::operator<()
/** … */ class Operador { public: /** Verifica se o operador tem menor precedência que o operador dado. @pre V. @post operador< = (precedência de *this é menor que a de outro_operador). */ bool operator<(Operador const& outro_operador) const; }; Código possível: Operador multiplicação(‘*’); Operador adição(‘+’); if(adição < multiplicação) Introdução à Programação 2003/2004

34 Operação Operador::operator==()
/** … */ class Operador { public: /** Verifica se o operador é igual ao operador dado. Note-se que a >= b e b >= a não implica que a == b, mas sim que a e b têm a mesma precedência. @pre V. @post operador== = (*this representa o mesmo operador que outro_operador). */ bool operator==(Operador const& outro_operador) const; }; Código possível: Operador multiplicação(‘*’); Operador adição(‘+’); if(adição == multiplicação) Introdução à Programação 2003/2004

35 Operação Operador::símboloÉVálido()
Um membro qualificado com static diz-se de classe. Se for uma operação, não tem instância implícita. As únicas diferenças para uma rotina não-membro são os privilégios de acesso a membros privados e o nome qualificado com o nome da classe. /** … */ class Operador { public: /** Verifica se um símbolo é representação de algum dos operadores suportados. @pre V. @post símbolo pertence a {'+', '-', '*', '/', '^'}. */ static bool símboloÉVálido(char const símbolo); }; Código possível: char símbolo; cin >> símbolo; if(not Operador::símboloÉVálido(símbolo)) cout << “…” << endl; else { Operador operador(símbolo); } Introdução à Programação 2003/2004

36 TAD Operador: Implementação
/** Representa um operador aritmético, com o qual se podem realizar operações. @invariant símbolo pertence a {'+', '-', '*', '/', '^'}. */ class Operador { private: /** Indica se o invariante da classe é cumprido. @pre V. @post símbolo pertence a {'+', '-', '*', '/', '^'}. */ bool cumpreInvariante() const; char símbolo; }; Introdução à Programação 2003/2004

37 Construtor Operador::Operador()
inline Operador::Operador(char const símbolo) : símbolo(símbolo) { assert(símboloÉVálido(símbolo)); assert(cumpreInvariante()); } Introdução à Programação 2003/2004

38 Método Operador::operator()()
double Operador::operator()(double const operando_esquerdo, double const operando_direito) const { assert(cumpreInvariante()); assert(símbolo != '/' or operando_direito != 0); switch(símbolo) { case '+': return operando_esquerdo + operando_direito; case '-': return operando_esquerdo - operando_direito; case '*': return operando_esquerdo * operando_direito; case '/': return operando_esquerdo / operando_direito; case '^': return pow(operando_esquerdo, operando_direito); } Introdução à Programação 2003/2004

39 Método Operador::operator<()
inline bool Operador::operator<(Operador const& outro_operador) const { assert(cumpreInvariante()); switch(símbolo) { case '+': case '-': return outro_operador.símbolo == '*' or outro_operador.símbolo == '/' or outro_operador.símbolo == '^'; case '*': case '/': return outro_operador.símbolo == '^'; case '^': return false; } Introdução à Programação 2003/2004

40 Método Operador::operator==()
inline bool Operador::operator==(Operador const& outro_operador) const { assert(cumpreInvariante()); return símbolo == outro_operador.símbolo; } Introdução à Programação 2003/2004

41 Método Operador::símboloÉVálido()
inline bool Operador::símboloÉVálido(char const símbolo) { return símbolo == '+' or símbolo == '-' or símbolo == '*' or símbolo == '/' or símbolo == '^'; } Introdução à Programação 2003/2004

42 Método Operador::cumpreInvariante()
inline bool Operador::cumpreInvariante() const { return símboloÉVálido(símbolo); } Introdução à Programação 2003/2004

43 Introdução à Programação
TAD Calculadora Representa uma calculadora Para ser mais curto e legível, o código não verifica nenhum possível erro do utilizador! Introdução à Programação 2003/2004

44 Introdução à Programação
TAD Calculadora /** Representa uma calculadora que opera sobre expressões lidas do canal cin, escrevendo o resultado em cout. As expressões podem envolver os operadores binários +, -, *, / e ^ (potenciação). Não podem incluir parênteses. As expressões são separadas por ; (ponto-e-vírgula) e terminadas por . (ponto). @invariant ?. */ class Calculadora { public: }; Introdução à Programação 2003/2004

45 Operação Calculadora::executa()
/** … */ class Calculadora { public: /** Executa a calculadora sobre expressões presentes no canal cin. @pre As expressões no canal cin têm de estar sintacticamente correctas, estar separadas por ; (ponto-e-vírgula) e a sua sequência deve ser terminada por . (ponto). @post O canal cout contém os resultados de todas as expressões, um em cada linha. */ void executa(); }; Introdução à Programação 2003/2004

46 TAD Calculadora: Implementação
/** Representa uma calculadora que opera sobre expressões lidas do canal cin, escrevendo o resultado em cout. As expressões podem envolver os operadores binários +, -, *, / e ^ (potenciação). Não podem incluir parênteses. As expressões são separadas por ; (ponto-e-vírgula) e terminadas por . (ponto). @invariant pilha_de_valores.empty()  pilha_de_operadores.empty(). */ class Calculadora { private: /** Indica se o invariante da classe é cumprido. @pre V. @post pilha_de_valores.estáVazia()  pilha_de_operadores. estáVazia(). */ bool cumpreInvariante() const; PilhaDeDouble pilha_de_valores; PilhaDeOperador pilha_de_operadores; }; Introdução à Programação 2003/2004

47 Operação Calculadora:: efectuaOperaçãoNoTopo()
/** … */ class Calculadora { private: /** Efectua operação correspondente ao operador que se encontra no topo da pilha de operadores usando como operandos os dois valores no topo da pilha de valores. O valor que se encontra no topo da pilha de valores é o operando direito, sendo o valor imediatamente abaixo o operando esquerdo. @pre 1 ≤ pilha_de_operadores.altura()  2 ≤ pilha_de_valores.altura(). @post Pilha de valores deixou de conter os dois valores do topo, tendo sido colocado no lugar deles o resultado do operador do topo da pilha de operadores (que entretanto foi retirado) quando aplicado aos dois valores retirados (o primeiro valor retirado da pilha de valores é o operando direito). */ void efectuaOperaçãoNoTopo(); }; Introdução à Programação 2003/2004

48 Operação Calculadora:: efectuaOperacoesDePrecedenciaMaiorOuIgualA()
/** … */ class Calculadora { private: /** Efectua os cálculos de todos os operadores de precedência superior ou igual ao operador passado como argumento. @pre n = pilha_de_operadores.altura()  k = número de operadores na pilha de operadores com precedência superior ou igual a operador  m = pilha_de_valores.altura()  k + 1 ≤ m. @post pilha_de_operadores.altura() = n – k  pilha_de_valores.altura() = m – k – 1. */ void efectuaOperaçõesDePrecedênciaMaiorOuIgualA( Operador const& operador); }; Introdução à Programação 2003/2004

49 Operação Calculadora:: efectuaTodasAsOperações()
/** … */ class Calculadora { private: /** Efectua os cálculos de todos os operadores que estão na pilha. @pre n = pilha_de_operadores.altura()  m = pilha_de_valores.altura()  n + 1 <= m. @post pilha_de_operadores.estáVazia()  pilha_de_valores.altura() = m – n – 1. */ void efectuaTodasAsOperações(); }; Introdução à Programação 2003/2004

50 Método Calculadora::executa()
void Calculadora::executa() { assert(cumpreInvariante()); char caractere; do { cin >> caractere; if(not cin.fail()) if(Operador::simboloÉVálido(caractere)) { // Processamento de operador. } else if(caractere == ';' or caractere == '.') { // Processamento de terminador. } else if(isdigit(caractere)) { // Processamento de valor. } } while(not cin.fail() and caractere != '.'); Introdução à Programação 2003/2004

51 Método Calculadora::executa()
if(Operador::simboloÉVálido(caractere)) { efectuaOperaçõesDePrecedênciaMaiorOuIgualA(Operador(caractere)); pilha_de_operadores.põe(Operador(caractere)); } else if(caractere == ';' or caractere == '.') { efectuaTodasAsOperações(); cout << pilha_de_valores.itemNoTopo() << endl; pilha_de_valores.tiraItem(); } else if(isdigit(caractere)) { cin.putback(caractere); double valor; cin >> valor; pilha_de_valores.põe(valor); } Introdução à Programação 2003/2004

52 Método Calculadora:: efectuaOperaçãoNoTopo()
void Calculadora::efectuaOperaçãoNoTopo() { assert(1 <= pilha_de_operadores.altura()); assert(2 <= pilha_de_valores.altura()); double operando_direito = pilha_de_valores.itemNoTopo(); pilha_de_valores.tiraItem(); double operando_esquerdo = pilha_de_valores.itemNoTopo(); Operador operador = pilha_de_operadores.itemNoTopo(); pilha_de_operadores.tiraItem(); pilha_de_valores.põe(operador(operando_esquerdo, operando_direito)); } Introdução à Programação 2003/2004

53 Método Calculadora:: efectuaOperacoesDeMaiorPrecedenciaQue()
void Calculadora::efectuaOperaçõesDePrecedênciaMaiorOuIgualA( Operador const& operador) { while(not pilha_de_operadores.estáVazia() and pilha_de_operadores.itemNoTopo() >= operador) efectuaOperaçãoNoTopo(); } Introdução à Programação 2003/2004

54 Método Calculadora:: efectuaTodasAsOperações()
void Calculadora::efectuaTodasAsOperações() { while(not pilha_de_operadores.estáVazia()) efectuaOperaçãoNoTopo(); assert(pilha_de_operadores.estáVazia()); } Introdução à Programação 2003/2004

55 Método Calculadora:: cumpreInvariante()
bool Calculadora::cumpreInvariante() const { return pilha_de_valores.estáVazia() and pilha_de_operadores.estáVazia(); } Introdução à Programação 2003/2004

56 Introdução à Programação
E as pilhas? Programa escrito usa-as Necessário desenvolvê-las Desenho de TAD será demonstrado com as pilhas Introdução à Programação 2003/2004

57 Introdução à Programação
Desenho de TAD Recomendável começar por escrever restante código assumindo que existem Recomendável também escrever programa de teste Ambos clarificam operações e comportamentos desejáveis, bem como a interface desejável Introdução à Programação 2003/2004

58 Introdução à Programação
Operações das pilhas Começaremos por PilhaDeDouble Construir pilha vazia Verificar se está vazia Obter o item do topo Saber altura da pilha Pôr item na pilha Tirar o item do topo construtores predicados (inspectores) inspectores modificadores Introdução à Programação 2003/2004

59 TAD PilhaDeDouble: Teste de unidade
int main() { PilhaDeDouble pilha; assert(pilha.estáVazia()); assert(pilha.altura() == 0); for(int i = 0; i != 10; ++i) { assert(pilha.altura() == i); pilha.poe(i); assert(pilha.itemNoTopo() == i); assert(not pilha.estáVazia()); assert(pilha.altura() == i + 1); } (continua) Introdução à Programação 2003/2004

60 TAD PilhaDeDouble: Teste de unidade
(continuação) assert(pilha.itemNoTopo() == 9); assert(not pilha.estáVazia()); assert(pilha.altura() == 10); for(int i = 9; i != -1; --i) { assert(pilha.itemNoTopo() == i); assert(pilha.altura() == i + 1); pilha.tiraItem(); assert(pilha.altura() == i); } assert(pilha.estáVazia()); assert(pilha.altura() == 0); Introdução à Programação 2003/2004

61 Introdução à Programação
TAD PilhaDeDouble /** Representa pilhas de double. @invariant [o invariante é um problema de implementação]. */ class PilhaDeDouble { public: typedef double Item; }; Permite alterar o tipo dos itens com muita facilidade. Definir PilhaDeOperador torna-se trivial: Copiar classe PilhaDeDouble completa. Substituir PilhaDeDouble por PilhaDeOperador. Alterar definição de Item de double para Operador. Introdução à Programação 2003/2004

62 TAD PilhaDeDouble: Construtores
/** … */ class PilhaDeDouble { public: /** Constrói pilha vazia. @pre V. @post estáVazia(). */ PilhaDeDouble(); }; Introdução à Programação 2003/2004

63 TAD PilhaDeDouble: Predicados
/** … */ class PilhaDeDouble { public: /** Indica se a pilha está vazia. @pre V. @post estáVazia = *this está vazia. */ bool estáVazia() const; }; Introdução à Programação 2003/2004

64 TAD PilhaDeDouble: Inspectores
/** … */ class PilhaDeDouble { public: /** Devolve o item que está no topo da pilha. @pre ¬estáVazia(). @post itemNoTopo idêntico ao item no topo de *this. */ Item const& itemNoTopo() const; /** Devolve altura da pilha. @pre V. @post altura = altura de *this (número de itens). */ int altura() const; }; Introdução à Programação 2003/2004

65 TAD PilhaDeDouble: Modificadores
/** … */ class PilhaDeDouble { public: /** Põe um novo item na pilha (no topo). @pre V. @post *this contém um item adicional no topo igual a novo_item. */ void põe(Item const& novo_item); /** Tira o item que está no topo da pilha. @pre ¬estáVazia(). @post *this contém os itens originais menos o do topo. */ void tiraItem(); private: }; Introdução à Programação 2003/2004

66 TAD PilhaDeDouble: Implementação
Fica como exercício Introdução à Programação 2003/2004

67 Estrutura global do programa
#include <iostream> #include <utility> // define <=, >, >= e != à custa de < e de ==. #include <cassert> #include <cctype> // para isdigit(). #include <cmath> // para pow(). #include … // outras inclusões necessárias para as pilhas. using namespace std; using namespace std::rel_ops; // para definições de <= etc. terem efeito. class Operador {…} // e respectivos métodos. class PilhaDeDouble {…} // e respectivos métodos. class PilhaDeOperador {…} // e respectivos métodos. class Calculadora {…} // e respectivos métodos. (continua) Introdução à Programação 2003/2004

68 Estrutura global do programa
(continuação) #ifdef TESTE int main() { // Testes das várias classes! } #else // TESTE Calculadora calculadora; calculadora.executa(); #endif // TESTE Para compilar os testes usa-se um comando de compilação semelhante a: c++ -DTESTE … Introdução à Programação 2003/2004

69 Programação procedimental
Primeiro pensa-se nos algoritmos Depois pensa-se nos dados Introdução à Programação 2003/2004

70 Programação baseada em objectos
Primeiro pensa-se nos dados (TAD) Depois pensa-se nos algoritmos Frequentemente são os substantivos mais importantes que surgem na descrição do problema. Introdução à Programação 2003/2004

71 Introdução à Programação
Desenho de TAD TAD são módulos Designers e departamento marketing definem interface Engenharia desenvolve o mecanismo Introdução à Programação 2003/2004

72 Introdução à Programação
Desenho de TAD Surgem para auxiliar resolução de problema Resolução usada para sugerir operações necessárias no TAD Começa-se pelo teste de unidade Teste de unidade testa todas as operações do TAD Depois desenha-se a interface do TAD Finalmente implementa-se: Passo a passo, testando a cada passo Se necessário fazer implementação embrionária de métodos e rotinas (apenas instruções asserção e nas funções uma instrução de retorno). Introdução à Programação 2003/2004

73 Introdução à Programação
Alerta! Há pilhas na biblioteca do C++: #include <stack> #include <iostream> using namespace std; int main() { stack<int> pilha; pilha.push(1); pilha.push(2); while(not pilha.empty()) { cout << pilha.top() << endl; pilha.pop(); } Introdução à Programação 2003/2004

74 Introdução à Programação
Aula 14: Sumário Desenho de TAD: programação baseada em objectos Fases: Escrita de testes Declaração das operações suportadas, suas consequências, e forma de utilização: interface Definição dos atributos (representação) e dos métodos (mecanismo): implementação. Exemplo com pilhas. Definição de sinónimos de tipos com typedef Classe genérica stack Noções elementares de eXtreme Programming: Testes primeiro Desenvolvimento incremental Introdução à Programação 2003/2004


Carregar ppt "Programação Baseada em Objectos Desenho de TAD"

Apresentações semelhantes


Anúncios Google