Programação Orientada por Objetos
Prof. Rogério Celestino dos Santos
http://sites.google.com/site/rogeriocsaulas/
Fonte: Material do Prof. Marco Túlio de Oliveira Valente
Programação Orientada por Objetos
Paradigma de programação dominante
Linguagens pioneiras: Simula 67 e Smalltalk
Outras linguagens: C++, Java, C#, Eiffel, Ada95 Principais conceitos:
Classes e objetos, herança e polimorfismo de inclusão Classes são tipos usados para instanciar objetos
Objetos (de uma classe) encapsulam tanto: Estado (dados)
Operações que manipulam estes dados Objetos são úteis para modelar entidades
do mundo real: pessoa, funcionário, professor, aluno,
conta bancária, pedido de compra etc
Classes
Classes permitem declarar:
Dados (definem o estado de um objeto)
Operações (acessar e alterar estado do objeto) Exemplo:
class Figura { ....
private int x, y; private int color; ...
public int getColor() { ... }
public void setColor(int color) { ... } ...
Encapsulamento
Classes devem prover ocultamento de informação (ou
encapsulamento) de seus membros
Deve ser permitido ao implementador informar:
O que é visível aos clientes da classe (interface)
O que é de uso privativo da classe (implementação) Membros podem ser:
privados: usados apenas no corpo da classe
públicos: usados em qualquer ponto do programa onde
o nome da classe é visível
Objetivos:
Definir um contrato entre clientes e implementadores Independência entre clientes e implementadores
Classes e TADs
Classes são instrumentos úteis para implementar Tipos
Abstratos de Dados (TAD)
Descrição de um tipo por meio de um conjunto de
operações públicas
Implementação do tipo é mantida oculta de seus
clientes
Exemplo: TAD Pilha (de elementos do tipo T) Operações:
void empilha (T item); T desempilha();
T topo();
Classes Genéricas
Classes que fazem uso de parâmetros Exemplo:
template <class T> class Pilha { int topo; T vetor [100]; public: void empilha (T x); T desempilha (); }; Instanciação: Pilha<int> p1; Pilha<float> p2;
Principal utilidade: reúso de código Viabiliza polimorfismo paramétrico
Herança
Permite definir uma nova classe que herde todos os
membros “classe pai”
Nova classe: subclasse Classe pai: superclasse
Subclasse herda todos os membros da classe pai
Inclusive membros privados (não podem ser usados na
subclasse, mas existem em seus objetos)
Subclasse pode:
Redefinir (sobrescrever) membros herdados Definir novos membros
Herança
Exemplo:
class Circulo extends Figura { ....
private double raio; ...
public int getDiametro() { ... } ...
}
Classe Circulo é uma subclasse de Figura; por sua vez,
Figura é a superclasse de Circulo
Circulo herda membros de Figura (x,y, color, getColor, etc) Circulo acrescenta seus próprios membros
Principal utilidade: reúso de código Viabiliza polimorfismo de inclusão
Herança Simples e Múltipla
Herança
Simples: classe pode ter no máximo uma superclasse Múltipla: classe pode ter mais de uma superclasse
Herança múltipla possui problemas de ordem conceitual e
de implementação:
Problemas conceituais:
Colisão de Nomes: g () definido em B2 e em B3 Herança Repetida: f () definido em A
A
C
B1 B2 B3
f ()
Chamada Dinâmica de Métodos
Tipo Estático x Tipo Dinâmico:
Tipo Estático: tipo com que uma variável foi declarada Tipo Dinâmico: tipo da variável em tempo de execução Atribuição Polimórfica:
x= y é válida se tipo de y for subclasse do tipo de x Altera tipo dinâmico de x
Chamada dinâmica (dynamic dispatching)
Tipo dinâmico de uma variável determina qual
implementação de método será executada
Exemplo:
Figura f; Circulo c= new Circulo(10); f= c;
Classes Abstratas
Classes que podem possuir um ou mais métodos sem
implementação (chamados de métodos abstratos)
Exemplo:
abstract class Figura { ....
public abstract void draw(); // não possui implementação ....
}
Métodos abstratos são implementados nas subclasses Não é permitido instanciar objetos de classes abstratas Utilidade:
Funcionar como raiz de uma hierarquia de classes Viabilizando chamadas dinâmicas em métodos de
Herança e Classes Abstratas
class Ponto {
private int x, y;
public int getX() { ... } public int getY() { ... }
public void setX(int x) { ... } public void setY(int y) { ... }
public void draw(Graphics g) { ... } public void refresh() {
draw(Canvas.getGraphics()); }
}
class Linha {
private Ponto p1, p2; public int getP1() { ... } public int getP2() { ... }
public void setP1(Ponto p) { ... } public void setP2(Ponto p) { ... } public void draw(Graphics g) { ... } public void refresh() {
draw(Canvas.getGraphics()); }
Herança e Classes Abstratas
class Ponto extends Figura { private int x, y;
public int getX() { ... } public int getY() { ... }
public void setX(int x) { ... } public void setY(int y) { ... }
public void draw(Graphics g) { ... }
}
class Linha extends Figura { private Ponto p1, p2; public int getP1() { ... } public int getP2() { ... }
public void setP1(Ponto p) { ... } public void setP2(Ponto p) { ... } public void draw(Graphics g) { ... }
} abstract class Figura {
public abstract void draw(Graphics g);
public void refresh() {
draw(Canvas.getGraphics()); }
Exercícios
1. O que é um classe? 2. O que é um objeto ?
3. De um exemplo de uma classe e de um objeto. 4. Qual objetivo do encapsulamento ?
5. Qual objetivo da herança ?
6. O que é herança simples e herança multipla ? 7. Qual utilidade de uma classe abstrata ?
8. É possível instanciar objetos de um classe abstrata ? 9. Exemplifique o uso de uma classe abstrata?
Java
Prof. Rogério Celestino dos Santos
Fonte: Material do Prof. Marco Túlio de Oliveira Valente
Introdução
Desenvolvida por James Gosling e equipe (Sun, 1995) Linguagem compilada e posteriormente interpretada bytecode: linguagem intermediária
Assembly de uma máquina hipotética
Máquina Virtual Java: interpretador de bytecodes Não é novidade: Pascal-P (Wirth, década de 70) Mesma estratégia em C#: CLR e CIL (ou MSIL) Vantagem: portabilidade COMPILADOR MÁQUINA VIRTUAL JAVA - JVM (INTERPRETADOR) prog1.class (bytecodes) prog1.java (fonte)
Primeiro Programa
// arquivo HelloWorld.java public class HelloWorld {
public static void main(String[ ] args){ System.out.println (“Hello, world”); }
}
Todo arquivo deve ter uma classe pública com o mesmo
nome do arquivo
Execução começa pelo método main desta classe Observações:
Programa em Java é um conjunto de classes
Classes
Exemplo:
class Data {
private int dia, mes, ano; ....
Data(int dia, int mes, int ano) { // metodo construtor this.dia= dia; this.mes= mes; this.ano= ano;
} ... }
Método construtor: usado para inicializar objeto Construtor tem o mesmo nome da classe
this: variável automaticamente declarada em um método Referencia o objeto alvo da chamada
Classes
Encapsulamento de membros:
public: em qualquer lugar onde a classe for acessível private: apenas dentro dos métodos da classe
protected: dentro dos métodos da classe, de suas
subclasses e de classes do mesmo pacote (package)
Objetos
Operador new: usado para instanciar um objeto Exemplo:
Data d1= new Data(1,2,2008); // instanciação
Data d2= new Data(25,12,2007);
d1.imprime(); // chamada de método
Programas em Java possuem duas áreas de memória: Heap: onde são alocados objetos criados via new
Stack: onde são alocadas variáveis locais de métodos
ativados
Dois tipos de valores podem ser armazenados no stack: Primitivos: byte,short,int,long,float,double,boolean,char Referências (ou “ponteiros”) para objetos
Coleta de Lixo
Objetivo: Evitar que programador tenha que se preocupar
com a liberação de memória alocada no heap
Programador aloca, mas não precisa liberar memória Tarefa normalmente sujeita a diversos erros
Funcionamento:
Existe na JVM um processo, chamado coletor de lixo,
que fica continuamente procurando por objetos que não estão sendo mais referenciados
Quando encontra um objeto inacessível, o coletor de
lixo libera a área de memória alocada para o mesmo
Não se tem controle sobre o momento em que o
coletor de lixo roda
Exemplo de Coleta de Lixo
class BigClasse { private int x;
private int bigvetor [ ]; // vetor de inteiros public BigClasse (int x1) { // construtora System.out.println ("Criando " + x1); x= x1;
bigvetor= new int [1024*1024]; }
protected void finalize () {
System.out.println("Eliminando " + x); }
Exemplo de Coleta de Lixo
public class Exemplo2 {
public static void main(String[] args) { BigClasse p;
for (int i= 0; i < 100; i++) p= new BigClasse (i); }
}
Método finalize(): chamado automaticamente pelo coletor
antes de liberar a área de memória de um objeto
Utilidade: liberar outros recursos (que não memória) Exemplo: fechar arquivos, fechar conexões etc
Chamado no máximo uma vez por objeto, mesmo que sua
execução “ressucite” o objeto
Atributos Estáticos
Pertencem à classe e não a cada objeto individualmente Exemplo:
class Conta { ... double saldo;
static double saldoMinimo= 500; ... }
Externamente, são acessados via nome da classe Exemplo: System.out.prinln(Conta.saldoMinimo);
Atributos estáticos e finais: são constantes
Não podem ser alterados, após terem sido inicializados Exemplo:
class Math { ...
public static final double PI = 3.1415; }
Métodos Estáticos
Pertencem à classe e, portanto, não são invocados sobre
um objeto alvo
Exemplo:
class Math { ...
public static double sin (double x) { ... } } ...
double x= Math.sin (90);
Podem acessar apenas atributos e métodos estáticos Não podem acessar a referência this
Passagem de Parâmetros e Sobrecarga
Passagem de parâmetros: Sempre por valor
Mesmo que o parâmetro seja uma referência para um
objeto (e essa referência seja usada no corpo do método para alterar o estado do objeto no heap)
Métodos (e construtores) sobrecarregados:
Mesmo nome
Número e tipos de parâmetros diferentes
Para fins de sobrecarga, não se considera o tipo de
retorno e as exceções levantadas pelo método
Herança
Java possui Herança Simples
class Figura { ....
}
class Quadrado extends Figura { ...
}
Classe Object: raiz da hierarquia de classes de Java
Toda classe (diretamente ou indiretamente) é subclasse
de Object
Utilidade: variável do tipo Object pode se referir a qualquer
objeto (de qualquer classe)
Redefinição de Métodos
Quando uma subclasse reimplementa um método herdado
da superclasse
Reimplementação deve manter assinatura da superclasse
(regra da invariância)
Exemplo:
public class Superclass {
public void printMethod() {
System.out.println("Printed in Superclass."); }
Redefinição de Métodos
public class Subclass extends Superclass { public void printMethod() { // redefinição
super.printMethod(); // acesso a método da
superclasse
System.out.println("Printed in Subclass"); }
public static void main(String[] args) { Subclass s = new Subclass();
s.printMethod(); }
Classes e Métodos final
Evitando herança:
final class Senha { ... }
class MinhaSenha extends Senha { ... } // Erro !
Evitando redefinição de métodos:
class Senha { ...
public final bool validarSenha () { ... } ....
}
class MinhaSenha extends Senha { ... bool validarSenha () { ... } // Erro ! ...
Chamada Dinâmica de Métodos
Métodos são chamados utilizando o tipo dinâmico de uma
referência.
Exemplo:
Figura p; if ( .... )
p= new Quadrado (4); // atribuição polimórfica
else p= new Circulo (3); // atribuição polimórfica
Classes Abstratas
Exemplo:
abstract class Figura {
public abstract double area ();
public abstract double perimetro (); }
Implementação de area() e perimetro() ficará a cargo das
Packages
Recurso para modularização de programas Java Package: conjunto de arquivos
Cada arquivo pode possuir, no máximo, uma classe
pública
O nome do arquivo é o mesmo de sua classe pública Todo pacote possui um nome
Exemplo: pacote figuras, com classes públicas Figura,
Circulo, Quadrado
Arquivo c:\temp\figuras\Figura.java:
package figuras;
public abstract class Figura { ... } // outras classes (não-públicas)
Packages
Exemplo (continuação):
Arquivo c:\temp\figuras\Circulo.java
package figuras;
public class Circulo { ... } // outras classes (não-públicas)
Arquivo c:\temp\figuras\Quadrado.java
package figuras;
public class Quadrado { ... } // outras classes (não-públicas)
Nome do pacote deve ser igual ao nome do diretório que
contém seus arquivos
Variável de ambiente CLASSPATH: deve conter o nome
do diretório onde se encontra o diretório do pacote
Packages
Classes públicas de um pacote podem ser usados fora do
pacote da seguinte forma:
Via qualificação com o nome do pacote:
figuras.Figura fig; figuras.Circulo c;
java.awt.Button btnOk;
Via comando import no início doarquivo:
import figuras.*; // importa todas classes do pacote figuras import java.awt.Button; // importa apenas classe Button
... Figura fig; Circulo c;
Interfaces
Uma interface é um tipo (assim como uma classe)
Uma interface define apenas a assinatura de um conjunto
de métodos (ou seja, são similares a classes abstratas)
Uma classe pode declarar que implementa (implements)
uma interface
Neste caso, ela assume o compromisso de implementar
todos os métodos desta interface
Exemplo:
interface Comparavel {
int compare(Comparavel obj); }
Interfaces
Exemplo:
class Aluno extends Pessoa implements Comparavel { int compare(Comparavel obj) {
Aluno obj2= (Aluno) obj;
“compara this.matr com obj2.matr; retorna –1, 0 ou 1” }
}
Exemplo: suponha um método de ordenação
void ordena(Comparavel [] lista)
Qual a vantagem em relação a uma classe abstrata? Se Comparavel fosse uma classe abstrata, Aluno não
poderia herdar de Pessoa
Classes Genéricas
Motivação:
List v = new ArrayList(); // List é uma lista de Object v.add("test");
String a = (String) v.get(0);
Integer b = (Integer) v.get(0); // erro em tempo de execução
Usando classes genéricas:
// List agora é uma lista de strings
List <String> v = new ArrayList <String> (); v.add("test");
String a = v.get(0);
Classes Genéricas
Declarando uma classe genérica:
class Pair <T, S> { private T first; private S second; public Pair(T f, S s) { first = f; second = s; }
public T getFirst() { return first; }
public S getSecond() { return second; } public String toString(){
return "("+first.toString()+", "+second.toString()+")"; }
Classes Genéricas
Usando uma classe genérica:
Pair<String, String> p1=new Pair<String, String>(“maria", "A"); Pair<String, Integer> p2=new Pair<String, Integer>(“maria", 100); System.out.println("P1:"+p1.toString());
C++
Prof. Marco Túlio de Oliveira Valente
Fonte: Material do Prof. Marco Túlio de Oliveira Valente
C++
Criada por Bjarne Stroustrup
AT&T Bell Labs, a partir de 1979
Objetivo: introduzir conceitos de OO em C Inicialmente, chamava-se “C com Classes” Principais conceitos de OO
Classes, inclusive genéricas e abstratas Herança (simples e múltipla)
Polimorfismo
Exemplo de Classe
class Cubo {
private: // membros privados
int altura, largura, prof; // atributos
public: // membros públicos
Cubo (int, int, int); // função construtora
int volume (); // métodos
};
Cubo::Cubo (int a, int l, int p) // Construtora
{ altura= a; largura:= l; prof:= p }
Exemplo de Classe
main () {
Cubo cb (7,8,9); // declara objeto e chama construtora cout << cb.volume();
}
Controle de visibilidade: membros de uma classe podem
ser
public: podem ser usados em qualquer ponto do
programa
private: podem ser usados apenas em métodos da
própria classe (visibilidade default)
protected: podem ser usados apenas em métodos da
Funções Construtora e Destruidora
Função construtora:
Mesmo nome da classe
Chamada automaticamente na declaração de objetos
da classe
Utilizada para inicializar atributos da classe Função destruidora:
Nome da classe, prefixado por ~
Chamada implicitamente quando termina o escopo de
um objeto da classe
Usada para liberar memória alocada no heap, fechar
Herança
Mecanismo para construir novas classes (chamadas de classes derivadas ou subclasses) a partir de classes já existentes
(chamadas de classes base ou superclasses)
Objetivo: reutilização de código (subclasse herda atributos e métodos da superclasse)
class Hora {
int hora, min, seg; public:
Hora (int h, int m, int s) // construtora
{ hora= h; min= m; seg= s; } void imprime ()
{ cout << hora << “:” << min << “:” << seg; } };
Exemplo de Herança
class HoraCompleta: public Hora { protected:
char *fuso; // Fuso horário: “FNO”, “BRA”, “AMZ” ou “ACR” public:
HoraCompleta (int h, int m, int s, char *fs): Hora (h, m, s) { fuso= fs;
}
void imprime () {
Hora::imprime (); // chama imprime da superclasse cout << “ “ << fs;
} };
Herança Múltipla
Exemplo:
class aviao { ... } class barco { .... }
class hidroaviao: public aviao, public barco { .... }
A subclasse hidroaviao herda todos os atributos e métodos
Colisão de Nomes
class A { class B {
public: void f () { .... } public: void f () { .... }
}; };
class C: public A, public B { public:
void g () {
f(); // Erro ! Ambíguo, qual f ?
A::f (); // OK, qualificação (operador ::) com o nome B::f (); // da classe remove ambigüidade
Herança Repetida
class A { public: int x; ...}; class B1: public A {.... }; class B2: public A {.... };
class C: public B1, public B2 { public:
void g () {
x= 2; // Erro
B1::x= 3; // OK, cópias diferentes de x B2::x= 4; // OK, cópias diferentes de x }
Classe Base Virtual
Classe base virtual: usada para evitar que uma superclasse
seja herdada mais de uma vez
class A { public: int x; ...};
class B1: public virtual A {.... }; // classe base virtual class B2: public virtual A {.... }; // classe base virtual class C: public B1, public B2 {
public:
void g () {
x= 2; // OK
B1::x= 3; B2::x= 4; // OK, mesma cópia de x }
Polimorfismo
Um apontador para uma classe base pode apontar para um
objeto de uma classe dela derivada
Exemplo:
HoraCompleta hc (15,25,18, “BRA”); Hora *ph;
ph= &hc; // atribuição polimórfica
Somente apontadores possuem tipo estático e dinâmico. Tipo Estático: tipo com que o apontador foi declarado.
Exemplo: Hora
Tipo Dinâmico: tipo para o qual o apontador se refere em
tempo de execução. Exemplo: HoraCompleta
Atribuições polimórficas alteram o tipo dinâmico de um
Funções Virtuais
Chamadas utilizando o tipo dinâmico de um apontador
class Hora { ....
virtual void imprime () { .... } }
class HoraCompleta: public Hora { .... virtual void imprime () { .... }
}
main () {
HoraCompleta hc (21, 42, 12, “BRA”);
Hora *ph= &hc; // atribuição polimórfica ph->imprime (); // imprime: 21:42:12 BRA }
Classes Abstratas
Classes que possuem uma ou mais funções virtuais puras,
isto é, funções que não possuem implementação
Não se pode criar objetos de classes abstratas Exemplo:
class Poligono { ....
virtual float perimetro() = 0; // função virtual pura }
...
Poligono t; // Erro !
Utilização:
Projeto OO
Ponteiro this
Toda classe possui um ponteiro de nome this, que, dentro
de um método da classe, aponta para o objeto que está sendo manipulado por este método (objeto receptor).
Útil quando se precisa passar o objeto receptor como
Exemplo de Uso do this
Pilha undo;
class Circulo: public Poligono { int raio; ...
void aumenta_tam (int dr); ....
}
void Circulo::aumenta_tam (int dr) {
undo.empilha (this); // salva circulo corrente na pilha de undo raio= raio+dr;
... // redesenha circulo com novo tamanho }
... Circulo c (10);
Membros Estáticos
Atributo estático: atributo que pertence à classe, sendo
compartilhado por todos os objetos da mesma.
Exemplo: atributo para armazenar o número de objetos já
criados de uma classe class Circulo {
int raio;
static int total_circulos; // atributo estático
public:
Circulo (int r); void imprime(); };
Membros Estáticos
int Circulo::total_circulos= 0; // inicializa atributo estático Circulo::Circulo (int r) { raio= r; total_circulos++; }
void Circulo::imprime ()
{ cout << "\nTotal circulos: " << total_circulos; } ...
Circulo c1 (10) Circulo c2 (27); c1.imprime(); c2.imprime();
Métodos Estáticos
Métodos Estáticos: podem ser chamados sobre a classe e
não sobre um objeto da mesma
Somente podem acessar atributos estáticos da classe Não possuem o ponteiro this
class Circulo { int raio;
static int total_circulos; // atributo estático public:
Circulo (int r);
static void imprime(); // método estático
Métodos Estáticos
int Circulo::total_circulos= 0; // inicializa atributo estático Circulo::Circulo (int r) { raio= r; total_circulos++; }
void Circulo::imprime () // somente acessa atributos estáticos { cout << "\nTotal circulos: " << total_circulos; }
...
Circulo c1 (10) Circulo c2 (27); ...
Classes Genéricas
Classes Genéricas: permitem parametrizar a
implementação de classes
Exemplo: pilha de inteiros
class pilha {
int topo; int vetor [100]; public:
pilha ();
void empilha (int x); int desempilha ();
Classes Genéricas
pilha::pilha () { topo= 0; }
void pilha::empilha (int x) { vetor [topo++]= x; } int pilha::desempilha () { return vetor [--topo]; }
Mas e se pilha de float ? Ou de char ?
Solução “braçal”: “copiar e colar” + “trocar”
Classes Genéricas: parametrizar uma classe com um
parâmetro de tipo
“copiar e colar” + “trocar” a cargo do compilador Chamadas em C++ de templates.
Templates: Definição
template <class T> class pilha_gen { int topo; T vetor [100]; public: pilha_gen (); void empilha (T x); T desempilha (); };
template <class T> pilha_gen<T>:: pilha_gen () { topo= 0; }
template <class T> void pilha_gen<T>:: empilha (T x) { vetor [topo++]= x; } template <class T> T pilha_gen<T>:: desempilha () { return vetor [--topo]; }
Templates: Instanciação
void main () { int i; float x;
pilha_gen<char> pchar; // pchar: pilha de char pilha_gen<float> pfloat; // pfloat: pilha de float for (i=0; i < 10; i++)
pfloat.empilha (3.14 * i); for (i=0; i < 10; i++) {
x= pfloat.desempilha (); cout << x << “\n”;
} ... }
Templates: Comentários Finais
Em C++, pode-se também parametrizar uma classe com
parâmetros que não sejam tipos
template <class T, int tam> class pilha_gen { int topo; T vetor [tam]; ...
}
C++ implementa apenas generalidade irrestrita
Não é possível restringir os tipos a serem instanciados C++ implementa templates com uma semântica de
macro-expansão
Tratamento de Exceções
Prof. Marco Túlio de Oliveira Valente
Fonte: Material do Prof. Marco Túlio de Oliveira Valente
Seqüenciadores
Definição: construção que altera o fluxo de execução
normal de um programa
Principais tipos de seqüenciadores: Saltos, Escapes e Exceções
Saltos (jumps):
Sintaxe: goto L, onde L é um label
Permite que um bloco de comandos possua várias
entradas e várias saídas
Desvantagem: legibilidade Escapes:
Exemplos (em C) : break, return, halt
Permite que um bloco de comandos tenha múltiplas
Exceções: Introdução
Programas devem tratar erros ou situações não previstas: Exemplos: divisão por zero, Indexação de um vetor
além de seus limites, overflow em uma operação aritmética, memória insuficiente, disco cheio etc
Ausência de tratamento: graves conseqüências
Exemplo: explosão do foguete Ariane 5 em 1996
devido a um overflow em uma operação de ponto flutuante em um programa desenvolvido em ADA
Problema: formas convencionais “poluem” o programa
com código para tratamento de erros
Chegando a 2/3 do código em alguns programas Solução: exceções
Exceções: Introdução
Exceção: erro ou um estado imprevisto, que não ocorre com freqüência
Idéia: remover o tratamento de erros do fluxo normal de execução, de forma a não “poluir” o código.
Tratador (ou Manipulador) de Exceção: bloco de código para onde a execução é desviada quando ocorre uma exceção Primeira linguagem: PL/I (1964)
Atualmente: ADA, C++, Java etc
Exceções em linguagens de programação: Como ativar uma exceção ?
Como especificar um tratador de exceções ?
Como exceções são propagadas?
Tratamento de Exceções em C++
Como ativar uma exceção em C++ ?
Através do comando throw <expressão> Exemplo:
class DivisaoPorZero { } ;
double divisao (double x, double y) { if (y = = 0)
throw DivisaoPorZero (); // ativa (ou levanta) exceção return x / y;
}
throw: abandona execução do bloco corrente e passa a
Tratamento de Exceções em C++
Como especificar um tratador de exceções em C++ ? Através dos comandos:
try { ... } // comandos que podem ativar exceções catch (parâmetro formal) { ... } // tratador
catch (parâmetro formal) { ... }
Exceções ocorridas no interior de um try são transferidas
para o catch correspondente
Exemplo:
try { ...
divisao (5.0, 0.0); // ativa uma exceção ...
}
catch (DivisaoPorZero) { // “captura” exceção ...; cout << “divisão por zero”; ...
Exemplo 2
Sem Tratamento de Exceções:
ok= AbraArquivo (nome); if (ok) {
tam= TamanhoArquivo (nome); if (tam != 0) { p= AloqueMemoria (tam); if (p != NULL) { ... } else { ... } } else { ... } } else { ... }
Com Tratamento de Exceções :
try {
abraArquivo (nome);
tam= TamanhoArquivo (nome); p= AloqueMemoria (tam); ... } catch (ExcecaoAberturaArquivo) { ... } catch (ExcecaoTamanhoArquivo) { ... } catch (ExcecaoAlocacaoMemoria) { ... }
Como exceções são propagadas ?
Exceções são propagadas automaticamente, terminando
cada um dos blocos e funções do programa, até se
encontrar um tratador com parâmetro formal do mesmo tipo do objeto especificado na ativação da exceção.
Em outras palavras, procura-se na pilha de ativação de
blocos e funções, o primeiro catch que trate a exceção ativada
Como um tratador é escolhido ?
catch (A) { ... } // captura exceções da classe A e das subclasses de A catch (B) { .... } // captura exceções da classe B e das subclasses de B catch (...) { ... } // captura exceções de qualquer classe (catch-all)
Exemplo 3
void f (int a) { cout << "f-inicio "; try { divisao (5.0, a); } catch (Overflow) { cout << "f-over"; } cout << "f-fim "; } void g () { int a; cout << "g-inicio "; try { cin >> a; f (a); } catch (DivisaoPorZero) { cout << "g-div0 "; } cout << "g-fim "; }void main () { // Resultado:
g (); // a= 1: g-inicio f-inicio f-fim g-fim
Retorno ao Fluxo Normal Execução
Como retornar ao fluxo normal de execução após tratar
uma exceção ?
Basta que encontre-se um bloco catch que trate o tipo da
exceção levantada
Este bloco é então executado; A exceção é desativada;
E a execução prossegue na linha seguinte ao bloco Como reativar uma exceção dentro de um bloco catch ?
Através do comando throw Exemplo:
catch (A) { ...
throw; // reativa exceção do tipo A ...
Sobrecarga de Operadores em C++
Objetivo: permitir que operadores (+, -, * etc) sejam usados
para operar com outros tipos que não os tipos primitivos
Exemplo:
class Complexo {
double re, im; public:
Complexo (double r, double i); Complexo ();
Complexo operator+ (Complexo b); };
Complexo::Complexo (double r, double i) { re= r; im= i;} Complexo::Complexo () { re= im= 0;}
Sobrecarga de Operadores em C++
Complexo Complexo::operator+ (Complexo b) { Complexo res (0,0); res.re= re + b.re; res.im= im + b.im; return res; } void main() { Complexo a (2.4, 3.2); Complexo b (0.6, 1.8); Complexo c; c= a + b; // a + b ⇔ a.operator+ (b) }
Exemplo 4: Classe Vetor
Implementar uma classe vetor que ative uma exceção no
caso de se tentar acessar um índice fora dos limites permitidos
class IndiceForaDeFaixa { public:
int indice;
IndiceForaDeFaixa (int i) { indice= i; } };
Exemplo 4: Classe Vetor
class Vetor {
int tam; // numero de elementos do vetor int *elem; // elementos do vetor
public:
Vetor (int n) { // construtora elem= new int [n]; tam= n; }
int& operator[ ] (int i) { // Sobrecarga de operador: v[i] ⇔ v.operator[ ](i)
if ((i < 0) || (i >= tam))
throw IndiceForaDeFaixa (i); return elem[i];
} };
Exemplo 4: Classe Vetor
void main () { Vetor v(10);
for (int i= 0; i < 10; i++) v[i]= 10*i;
try {
cout << v[11]; }
catch (IndiceForaDeFaixa i) {
cout << "indice " << i.indice << " fora de faixa"; }
Tratamento de Exceções em Java
Como ativar uma exceção: throw <expressão>
Expressão deve ser um objeto de uma classe derivada
da classe pré-definida Exception
Similar a C++, porém incluir um new para criar objeto Métodos devem relacionar na clásula throws todas as
exceções que podem encerrar a execução do mesmo
Exemplo:
class DivisaoPorZero extends Exception { } ; ...
double divisao (double x, double y) throws DivisaoPorZero{ if (y = = 0)
throw new DivisaoPorZero (); // ativa (ou levanta) exceção return x / y;
Tratamento de Exceções em Java
Como especificar um tratador de exceções ?
try { ... } // comandos que podem ativar
exceções
catch (ExceptionType ident ) { ... } // tratador de exceções catch (ExceptionType ident) { ... }
finally { .... } // opcional
Código do finally é executado ocorrendo ou não uma exceção no try
Exemplo:
try { ... }
catch (A e) { .... } finally { ... }
Neste exemplo, o bloco finally será executado quando: try terminar corretamente, sem ativação de nenhuma
exceção
Tratamento de Exceções em Java
Bloco finally é usado para liberar algum recurso que foi
alocado
Exemplo: processar um arquivo, sendo que em caso de
erro deve-se fechar o arquivo e propagar a exceção.
Sem finally:
file.open();
try { ... } // processamento do arquivo catch (IOException e) { file.close(); throw e; } file.close();
Com finally:
file.open(); try { ... }