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 cheian”;
else ptr_pilha[ + + top_ptr ] = elem;
}
void pop ( ) {
if (top_ptr = = -1)
cout << “Erro - pilha vazian”;
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 cheian”;
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

Cap10

  • 1.
    ABSTRAÇÃO • processo derepresentar 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")
  • 2.
  • 3.
    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), ...
  • 4.
    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
  • 5.
    ENCAPSULAMENTO • um agrupamentode 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)
  • 6.
    OBJETOS • um tipoabstrato 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
  • 7.
    EXEMPLO: O PONTO-FLUTUANTE COMOTIPO 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
  • 8.
    TIPOS DE DADOSABSTRATOS 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
  • 9.
    CLIENTES • unidades deprograma 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
  • 10.
    EXEMPLO: UMA PILHAE 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
  • 11.
    TIPOS DE DADOS ABSTRATOSEM 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
  • 12.
    FUNÇÕES-MEMBRO • as funçõesdefinidas 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
  • 13.
    TEMPO DE VIDADAS 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
  • 14.
    OCULTAÇÃO DA INFORMAÇÃO EMC++ • 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
  • 15.
    Construtores • Funções-membro usadaspara 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
  • 16.
    Destrutores • Implicitamente chamadosquando 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
  • 17.
    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; }
  • 18.
    Exemplo (continuação) ... ~pilha(){ //** um destrutor delete [ ] ptr_pilha; } void push ( int elem) { if (top_ptr = = tam_max) cout << “Erro - pilha cheian”; else ptr_pilha[ + + top_ptr ] = elem; } void pop ( ) { if (top_ptr = = -1) cout << “Erro - pilha vazian”; else top_ptr -- ; }
  • 19.
    Exemplo (continuação) ... inttop { 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( ); ... }
  • 20.
    Avaliação das classesC++ • 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?
  • 21.
    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.
  • 22.
    Java • Suporte paratipos 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
  • 23.
    Java • Suporte paratipos 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
  • 24.
    Pacotes Java • EmC++ 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
  • 25.
    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; }
  • 26.
    Exemplo (continuação) ... publicvoid 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
  • 27.
    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
  • 28.
    Classes parametrizadas emC++ 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;
  • 29.
    Classes genéricas emC++ #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; }
  • 30.
    Classes genéricas emC++ (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 cheian”; else ptr_pilha[ + + top_ptr ] = elem; } void pop ( ) {...}
  • 31.
    Classes genéricas emC++ (continuação) ... TIPO top { return ( ptr_pilha[top_ptr] ); } int empty { return ( top_ptr = = -1 ); } } ** fim da classe pilha