ABSTRAÇÃO processo de representar um grupo de entidades através de seus atributos comuns feita a...
Transcript of ABSTRAÇÃO processo de representar um grupo de entidades através de seus atributos comuns feita a...
ABSTRAÇÃO • processo de representar um grupo de
entidades através de seus atributos comuns
• feita a abstração, cada entidade particular (instância) do grupo é considerada somente pelos seus atributos particulares
• os atributos comuns às entidades do grupo são desconsiderados (ficam "ocultos" ou "abstraídos")
ABSTRAÇÃO
• de processos
• de dados
ABSTRAÇÃO DE PROCESSOS • o conceito de abstração de processos é um
dos mais antigos no projeto de linguagens
• absolutamente crucial para a programação
• historicamente anterior à abstração de dados
• todos os subprogramas são abstrações de processo
• exemplo: chamadas sort(array1, len1), sort(array2, len2), ...
MÓDULOS• módulos são "containers" sintáticos contendo
subprogramas e grupos de dados relacionados logicamente
• modularização: processo de projetar os módulos de um programa
• a compreensão do programa pelos mantenedores seria impossível sem organização modularizada
• além disso, há um ponto crítico: quando o projeto de um programa estende-se por milhares de linhas, recompilá-lo totalmente a cada atualização do código é absolutamente inviável - daí a necessidade de modularizá-lo
ENCAPSULAMENTO• um agrupamento de subprogramas+dados que é
compilado separada/independentemente chama-se uma unidade de compilação ou um encapsulamento
• um encapsulamento é portanto um sistema abstraído • muitas vezes os encapsulamentos são colocados em
bibliotecas • exemplo: encapsulamentos C (não são seguros porque
não há verificação de tipos de dados em diferentes arquivos de encapsulamento)
OBJETOS• um tipo abstrato de dados é um encapsulamento que
inclui somente um tipo específico de dado e os subprogramas que fornecem as operações para este tipo
• detalhes de implementação do tipo ficam ocultos das unidades fora do encapsulamento que o contém
• um objeto é uma variável (instância) de um tipo abstrato de dados, declarada por alguma unidade
• programação orientada a objetos consiste no uso de objetos no desenvolvimento do software
EXEMPLO: O PONTO-FLUTUANTE COMO TIPO ABSTRATO DE DADOS
• embora o tipo ponto-flutuante esteja presente desde o início da programação, raramente nos referimos a ele como tipo abstrato de dados
• praticamente todas as linguagens permitem que se criem "objetos" do tipo ponto-flutuante
• observe que existe um conjunto de operações que são válidas para o tipo ponto-flutuante, exatamente como os “métodos” definidos para uma “classe”
• além disso, a ocultação da informação está presente: o formato real dos dados é inacessível ao programador - isto é exatamente o que se espera de uma abstração
• isto é o que permite a portabilidade de um programa entre as implementações da linguagem para plataformas particulares
TIPOS DE DADOS ABSTRATOS DEFINIDOS PELO USUÁRIO
• a definição do tipo e as operações sobre objetos do tipo estão contidas numa única unidade sintática
• outras unidades de programa podem ter permissão para criar variáveis do tipo definido
• a implementação do tipo não é visível pelas unidades de programa que usam o tipo
• as únicas operações possíveis sobre objetos do tipo são aquelas oferecidas na definição do tipo
CLIENTES• unidades de programa que utilizam um tipo
abstrato chamam-se clientes daquele tipo • a ocultação da representação do tipo abstrato é
vantajoso para seus clientes: o código no cliente não depende desta representação, e mudanças na representação não exigem mudanças nos clientes (mas se o protocolo de alguma operação for modificado, então é claro que os clientes precisam ser alterados)
• a ocultação aumenta a confiabilidade: nenhum cliente pode interferir intencional ou acidentalmente na representação
EXEMPLO: UMA PILHA E SUAS OPERAÇÕES ABSTRATAS
• create(stack)• destroy(stack)• empty(stack)• push(stack, elem)• pop(stack)• top(stack) • create(STK1); % STK1 é um objeto ou uma
instância do tipo stack• create(STK2); % outra instância do tipo stack
TIPOS DE DADOS ABSTRATOS EM C++
• os tipos abstratos de dados em C++ são as chamadas classes
• as variáveis são declaradas como instâncias de classes
• classes do C++ são baseadas nas da SIMULA67 e no struct do C
• os dados definidos numa classe são os membros de dados
FUNÇÕES-MEMBRO• as funções definidas em uma classe são as
funções-membro
• as funções-membro são compartilhadas por todas as instâncias de classe
• mas: cada instância tem seu próprio conjunto de membros de dados
• uma função membro pode ter sua definição completa dentro da classe ("inlined") ou apenas seu cabeçalho
TEMPO DE VIDA DAS CLASSES
• as instâncias de classe podem ser estáticas, stack-dinâmicas ou heap-dinâmicas, exatamente como variáveis do C
• as classes podem incluir membros de dados heap-dinâmicos, não obstante elas próprias não serem heap-dinâmicas
OCULTAÇÃO DA INFORMAÇÃO EM C++
• cláusula private: para entidades ocultas na classe
• cláusula public: para as entidades visíveis aos clientes. Descreve a interface com objetos da classe
• cláusula protected: relacionada com herança
Construtores
• Funções-membro usadas para inicializar os membros de dados de um objeto recém-criado
• Também alocam membros de dados heap-dinâmicos
• Têm o mesmo nome da classe
• Pode-se sobrecarregar construtores
• Não têm tipo de retorno, não usam return
Destrutores• Implicitamente chamados quando se
encerra o tempo de vida de um objeto
• Se um objeto é heap-dinâmico, será explicitamente desalocado com delete
• O destrutor pode conter chamadas delete para desalocar membros de dados heap-dinâmicos
• Nome do destrutor: ~ <nome_da_classe>
• Não têm tipo de retorno, não usam return
Exemplo#include <iostream.h>
class pilha {
private:
int *ptr_pilha;
int tam_max;
int top_ptr ;
public:
pilha( ){ //** um construtor
ptr_pilha = new int [100];
tam_max = 99;
top_ptr = -1;
}
Exemplo (continuação)... ~pilha( ){ //** um destrutor
delete [ ] ptr_pilha;
}
void push ( int elem) {
if (top_ptr = = tam_max)
cout << “Erro - pilha cheia\n”;
else ptr_pilha[ + + top_ptr ] = elem;
}
void pop ( ) {
if (top_ptr = = -1)
cout << “Erro - pilha vazia\n”;
else top_ptr -- ;
}
Exemplo (continuação)... int top { return ( ptr_pilha[top_ptr] ); }
int empty { return ( top_ptr = = -1 ); }
} \\** fim da classe pilha
Código no cliente:
void main ( ) {
int top_one;
pilha stk;
stk.push(42);
stk.push(17);
top_one = stk.top( );
stk.pop( );
... }
Avaliação das classes C++
• As classes são tipos
• Não há construções de encapsulamento generalizadas
• Exemplo: temos uma classe “matriz” e uma classe “vetor”, e precisamos multiplicar um objeto “matriz” por um objeto “vetor”.
• Em qual classe essa operação deve ser definida?
Solução para “matriz vetor” class Matriz {
friend Vetor mult(const Matriz&, const Vetor&);
...}
class Vetor {
friend Vetor mult(const Matriz&, const Vetor&);
...}
Vetor mult(const Matriz& m1, const Vetor& v1){
..}
Se Matriz e Vetor pudessem ser definidas num único pacote, evitaríamos esta construção pouco natural.
Java• Suporte para tipos abstratos similar a C++
• Todos os tipos de dados definidos pelo usuário são classes
• Todos os objetos são heap-dinâmicos e acessados por variáveis de referência
• Todos os subprogramas (métodos) em Java somente podem ser definidos em classes
• public e private são modificadores anexados às definições de métodos/variáveis
Java• Suporte para tipos abstratos similar a C++
• Todos os tipos de dados definidos pelo usuário são classes
• Todos os objetos são heap-dinâmicos e acessados por variáveis de referência
• Todos os subprogramas (métodos) em Java somente podem ser definidos em classes
• public e private são modificadores anexados às definições de métodos/variáveis
Pacotes Java• Em C++ as classes são a única construção de
encapsulamento
• Java inclui uma construção adicional: os pacotes
• Pacotes podem conter mais de uma classe
• public e private são os chamados modificadores
• Os membros sem modificador (e os membros public) de uma classe são visíveis a todas as classes do mesmo pacote (escopo de pacote)
• Não há, portanto, necessidade de declarações friend explícitas em Java
Exemplo
import java.io.*
class Pilha {
private int [ ] ref_pilha;
private int tam_max, top_index ;
public Pilha( ){ // um construtor
ref_pilha = new int [100];
tam_max = 99;
top_index = -1;
}
Exemplo (continuação)... public void push ( int elem) {
if (top_index = = tam_max)
System.out.println(“Erro”);
else ref_pilha[ + + top_index ] = elem;
}
public void pop ( ) {
if (top_index = = -1)
System.out.println(“Erro”);
else --top_index ;
}
public int top { return ( ref_pilha[top_index] ); }
public boolean empty { return ( top_index = = -1 ); }
} \\** fim da classe Pilha
Exemplo (continuação) - uso da classe Pilha public class Testa_Pilha {
public static void main (String [ ] args) {
Pilha p1 = new Pilha( );
p1.push(42);
p1.push(29);
p1.pop( );
p1.pop( );
p1.pop( ); // Produz msg de erro
... }
• Não há destrutor (eliminado pela coleta de lixo implícita em Java)
• Observe o uso de variável de referência em vez de ponteiro
Classes parametrizadas em C++Exemplo: suponha que o método construtor para a
classe pilha fosse:
pilha (int size ){
ptr_pilha = new int [size];
tam_max = size-1;
top_ptr = -1;
}
No cliente:
... pilha(150) p1;
Classes genéricas em C++ #include <iostream.h>
template < class TIPO >
class pilha {
private:
TIPO *ptr_pilha;
int tam_max;
int top_ptr ;
public:
pilha( ){ //** um construtor
ptr_pilha = new TIPO [100];
tam_max = 99;
top_ptr = -1;
}
Classes genéricas em C++ (continuação)
pilha (int size ){ // outro construtor sobrecarregado
ptr_pilha = new TIPO [size];
tam_max = size-1;
top_ptr = -1;
}
~pilha( ){ delete ptr_pilha; }
void push ( TIPO elem) {
if (top_ptr = = tam_max)
cout << “Erro - pilha cheia\n”;
else ptr_pilha[ + + top_ptr ] = elem;
}
void pop ( ) {...}
Classes genéricas em C++ (continuação)... TIPO top { return ( ptr_pilha[top_ptr] ); }
int empty { return ( top_ptr = = -1 ); }
} \\** fim da classe pilha