CES-11 Teoria Cap 9

Propaganda
CES-11 ALGORITMOS E
ESTRUTURAS DE DADOS
Capítulo IX
Programação Orientada a Objetos
Capítulo IX – Programação
Orientada a Objetos
9.1 – Classes, objetos e métodos
9.2 – Herança
9.3 – Polimorfismo
9.1 – Classes, Objetos e Métodos
9.1.1 – Revendo tipos abstratos de dados

Programação Orientada a Objetos (POO) é um paradigma
de programação originado do conceito de tipos abstratos de
dados (TAD’s)

Tal paradigma é usado em linguagens como C++, Java,
Delphy, C#, Python, Visual Basic (a partir da versão 4), etc.

O MATLAB, a partir da versão 7.6, lançada em 03/2008,
tem utilizado princípios de orientação a objetos

Este capítulo será ilustrado com a Linguagem C++

TAD é um modelo de armazenamento de informações para o
qual é definida uma estrutura e uma relação de operadores

Por questões de disciplina, operadores fora da relação não
podem ser aplicados a esses tipos

Tais operadores são implementados em C por funções

Numa região do programa, declara-se a estrutura de dados e
define-se as funções para os operadores do TAD

No resto do programa podem ser declaradas variáveis desse
TAD

Essas variáveis só podem figurar em chamadas dessas
funções-operadoras
Exemplo: programa com o TAD lista linear
struct lista {
int ultimo,
elementos[51];
};
Funções com os
operadores de listas
lineares
lista L, L1, L2;
Região de
definição do
TAD lista
Operadores previstos para o TAD lista:
Inserir (x, p, L): insere elemento x na
posição p da lista L
Deletar (p, L): deleta elemento da
posição p da lista L
Conteudo (p, L): retorna elemento da
posição p da lista L
Alterar (x, p, L): altera para x o
conteúdo da posição p da lista L
Exemplo: programa com o TAD lista linear
Operadores:
struct lista {
int ultimo,
elementos[51];
};
Inserir (x, p, L)
Deletar (p, L)
Conteúdo (p, L)
Alterar (x, p, L)
Funções com os
operadores de listas
lineares
lista L, L1, L2;
Nesta região, a estrutura
interna de uma lista deve ser
considerada desconhecida
Exemplo: programa com o TAD lista linear
Operadores:
struct lista {
int ultimo,
elementos[51];
};
Inserir (x, p, L)
Deletar (p, L)
Conteúdo (p, L)
Alterar (x, p, L)
Funções com os
operadores de listas
lineares
Já que (L.elementos[i]
(L.ultimo
(x
= L.elementos[i];)
= --=
- - x;)
- - ;)
Proibido:
é proibido, usar
lista L, L1, L2;
L.ultimo
= muda
-que
- - -atribui
-o- ; a
x = Conteúdo
Inserir
Alterar
(x,
i, L)(i,
–que
que
L)
provoca
acréscimo
xconteúdo
o conteúdo
de
unitário
L.elementos[i]
de L.elementos[i]
em L.ultimo, ou
L.elementos[i] = x;
Deletar (p, L) – que provoca
x = unitário
L.elementos[i];
decréscimo
9.1.2 – Correspondência entre TAD’s e POO

Em Programação Orientada a Objetos:

Um TAD corresponde a uma classe

Uma variável de tal TAD corresponde a um objeto de tal
classe

Os campos da estrutura de dados de tal TAD
correspondem aos atributos dos objetos de tal classe

Uma função-operadora de tal TAD corresponde a um
método de tal classe

Em vários programas escritos e elaborados em CES-11, foi
usado o conceito de TAD’s

O professor exigiu dos alunos a disciplina de impedir que
variáveis de certos TAD’s figurassem em operações não
definidas para os mesmos


Em POO essa disciplina pode ser exigida pelo compilador


O acesso à estrutura de dados de um TAD ficou restrito
às funções-operadoras do mesmo
O programador fica impedido de desobedecê-la
Esconder a estrutura de um TAD ou classe é chamado de
encapsular
9.1.3 – Definições

Em POO, combina-se numa única entidade sua estrutura de
dados e as funções que operam sobre essa estrutura

Tal entidade é denominada objeto

Classe é uma categoria de objetos

É na declaração de uma classe que se especifica a estrutura
de dados e as funções que operam sobre os objetos da
mesma

Classes correspondem a tipos e objetos correspondem a
variáveis

Os elementos que compõem a estrutura de dados de uma
classe são denominados atributos dos objetos da mesma

As funções que operam nos objetos de uma classe são
denominadas métodos dessa classe

Exemplo: uma classe com

Apenas um atributo

Um método (função) para atribuir valor ao atributo

Um método (função) para mostrar o atributo no vídeo
#include <iostream>
Contém os objetos cout e cin
#include <conio.h>
using namespace std;
Indica que o atributo x é visível
class cl {
apenas dentro da class cl
private:
int x;
Indica que os métodos
AtribValor e MostraValor são
public:
void AtribValor (int d) {x = d;} visíveis em todo o programa
void MostraValor () {
Comando de
cout << "Valor = " << x << "\n";
saída de C++
}
};
Mensagem para o objeto obj1
executar o método AtribValor
int main () {
cl obj1, obj2;
obj1.AtribValor (11); obj2.AtribValor (22);
obj1.MostraValor (); obj2.MostraValor ();
cout << "\n\n"; system("pause"); return 0;
}
#include <iostream>
Resultado
#include <conio.h>
Valor = 11
using namespace std;
Valor = 22
class cl {
Pressione ...
private:
int x;
public:
void AtribValor (int d) {x = d;}
void MostraValor () {
cout << "Valor = " << x << "\n";
}
Tal como para struct’s, usa-se o
};
ponto ‘.’ para acessar os atributos e
os métodos de um objeto, de fora
de sua classe
int main () {
cl obj1, obj2;
obj1.AtribValor (11); obj2.AtribValor (22); Dentro da
classe não se
obj1.MostraValor (); obj2.MostraValor ();
cout << "\n\n"; system("pause"); return 0; usa o ponto ‘.’
}
#include <iostream>
Por default, atributos e métodos numa classe
#include <conio.h>
são private
using namespace std;
class cl {
Para encapsular objetos, os atributos de sua
classe devem estar em private e os métodos
private:
devem estar em public
int x;
public:
void AtribValor (int d) {x = d;}
void MostraValor () {
cout << "Valor = " << x << "\n";
Aqui o comando obj1.x = 40;
}
};
seria rejeitado pelo compilador
Mas não mais seria, se private fosse
int main () {
trocado por public
cl obj1, obj2;
obj1.AtribValor (11); obj2.AtribValor (22);
obj1.MostraValor (); obj2.MostraValor ();
cout << "\n\n"; system("pause"); return 0;
}
#include <iostream>
Alternativa para declarar uma classe:
#include <conio.h>
Dentro da classe ficam os atributos e os
using namespace std;
protótipos dos métodos
class cl {
As definições dos métodos podem ficar fora
private:
dos limitantes da classe
int x;
public:
void AtribValor (int);
void MostraValor (void);
};
:: é um operador de
void cl :: AtribValor (int d) {
escopo
x = d;
}
AtribValor e MostraValor
void cl :: MostraValor () {
são métodos da classe cl
cout << "Valor = " << x << "\n";
}
void main () {- - - - -}
9.1.4 – Programação estruturada versus POO

Programação estruturada: um programa é dividido em
funções que se comunicam e trocam dados entre si
Dados Globais
Dados
Controle
Função
main
Função
f1
Função
f2

Programação orientada a objetos: um programa é dividido
em objetos que se comunicam entre si através de chamadas
de métodos
atributos
Método 1
Método 2
atributos
Objeto 2
Objeto 1
Chamar um método de
um objeto pode ser
entendido como enviar
uma mensagem para
esse objeto
atributos
Método 1
Método 1
Método 2
Método 2
Objeto 3

Na programação estruturada, é difícil estabelecer um elo de
ligação entre funções e estruturas de dados com os objetos
do mundo real

Isso se torna crítico quando os programas são muito
grandes

Como o mundo real é composto de objetos e não de
funções, a POO tem se mostrado melhor modeladora da
realidade do que a programação estruturada
9.1.5 – Entrada e saída em C++

Além das funções de entrada e saída da linguagem C, a
linguagem C++ tem ainda os objetos cin e cout, da biblioteca
iostream

cin faz entrada pelo teclado e cout faz saída pelo vídeo

O operador endl (end line) substitui o caractere ‘\n’

O operador setw faz formatação de saída (espaço de
caracteres em que um item será escrito)
Exemplo: seja o seguinte programa
Contém o operador setw
#include <iostream>
Vai duas vezes para o início
#include <iomanip>
da linha seguinte
Escreve
a
cadeia
#include <conio.h>
using namespace std; “x^2” num espaço de
10 caracteres,
int main () {
justaposta à direita
int x, m, n;
cout << endl << "TABELA DE POTENCIAS" << endl << endl ;
cout << "\tDigite o intervalo da tabela: ";
cin >> m >> n;
cout << endl << endl;
cout << setw(5) << "x" << setw(10) << "x^2" << setw(15) <<
"x^3" << endl;
cout << "------------------------------" << endl;
for (x = m; x <= n; x++)
cout << setw(5) << x << setw(10) << x*x << setw(15) <<
x*x*x << endl;
cout << endl << endl; system("pause"); return 0;
}
Resultado:
TABELA DE POTENCIAS
#include <iostream>
Digite o intervalo da tabela: 7 12
#include <iomanip>
x
x^2
x^3
#include <conio.h>
-----------------------------using namespace std;
7
49
343
8
64
512
int main () {
9
81
729
int x, m, n;
10
100
1000
11 POTENCIAS"
121
1331 << endl
cout << endl << "TABELA DE
<< endl
;
12
144
1728
cout << "\tDigite o intervalo da tabela: ";
cin >> m >> n;
Pressione ...
cout << endl << endl;
cout << setw(5) << "x" << setw(10) << "x^2" << setw(15) <<
"x^3" << endl;
cout << "------------------------------" << endl;
for (x = m; x <= n; x++)
cout << setw(5) << x << setw(10) << x*x << setw(15) <<
x*x*x << endl;
cout << endl << endl; system("pause"); return 0;
}
Exemplo: soma de dois números complexos lidos
#include <iostream>
using namespace std;
class complexo {
private:
double real, imag;
public:
void Ler (void);
void Escrever (void);
void Soma (complexo, complexo);
};
void complexo :: Ler () {
cin >> real >> imag;
}
void complexo :: Escrever () {
cout << "[(" << real << ")+j(" << imag << ")]";
}
void complexo :: Soma (complexo a, complexo b) {
real = a.real + b.real;
imag = a.imag + b.imag;
}
int main () {
complexo a, b, r; char c;
cout << "Adicao de complexos? (s/n): "; cin >> c;
while (c == 's' || c == 'S') {
cout << endl << "\tDigite os dois operandos: ";
a.Ler(); b.Ler();
Adicao de complexos? (s/n): s
r.Soma(a, b);
cout << endl << "\t";
Digite os dois operandos: 2.3 -7.1 -1.2 4.3
a.Escrever();
[(2.3)+j(-7.1)] + [(-1.2)+j(4.3)] = [(1.1)+j(-2.8)]
cout << " +Adicao
"; de complexos? (s/n): n
b.Escrever();
Process returned 0 (0x0)
execution time : 48.740 s
cout << " =Press
"; any key to continue.
r.Escrever();
cout << endl << endl;
cout << "Adicao de complexos? (s/n): "; cin >> c;
}
Exercício: estender este programa para fazer
return 0;
subtração, multiplicação e divisão de complexos
}
Exemplo: leitura das coordenadas de um ponto
#include <iostream>
#include <conio.h>
using namespace std;
typedef char logic;
const logic TRUE = 1, FALSE = 0;
class ponto {
private:
int abscissa, ordenada;
public:
void Setar (int, int);
int PegarAbscissa (void);
int PegarOrdenada (void);
};
void ponto :: Setar (int abs, int ord) {
logic ok;
ok = abs >= 0 && abs <= 100 && ord >= 0 && ord <= 100;
abscissa = ok ? abs : 0;
ordenada = ok ? ord : 0;
}
int ponto :: PegarAbscissa () {
return abscissa;
}
int ponto :: PegarOrdenada () {
return ordenada;
}
int main () {
ponto a; int abs, ord;
cout << "Digite as coordenadas de um ponto: ";
cin >> abs >> ord;
a.Setar(abs, ord);
cout << endl << "\tPonto digitado: ";
cout << "[" << a.PegarAbscissa() << ", "
<< a.PegarOrdenada() << "]";
cout << endl << endl; system("pause"); return 0;
}
Digite as coordenadas de um ponto: 3 8
Resultado:
Ponto digitado: [3, 8]
Pressione ...
9.1.6 – Construtores e destrutores

A declaração de um objeto de uma determinada classe aloca
tal objeto na memória

Isso é feito por um método invisível de tal classe:

Tem o mesmo nome da classe, não tem tipo nem
parâmetros

O método que aloca um objeto é chamado de construtor de
sua classe

Construtores podem ser programados
Exemplo: contas bancárias
#include <iostream>
#include <conio.h>
using namespace std;
conta :: conta () {
saldo = 0;
}
class conta {
conta :: conta (int inic) {
saldo = inic;
}
private:
int saldo;
public:
conta (void);
conta (int);
void Creditar (int);
int PegaSaldo (void);
};
void conta :: Creditar (int quant) {
saldo += quant;
}
int conta :: PegaSaldo () {
return saldo;
}
Quando um construtor alternativo é programado,
o construtor padrão também deve ser
c1 é inicializada pelo construtor
int main () {
padrão
conta c1, c2 = conta(200);
c2 é pelo outro construtor
cout << "Saldos iniciais:";
cout << endl << endl << "\tSaldo da conta c1: " <<
c1.PegaSaldo();
cout << endl << endl << "\tSaldo da conta c2: " <<
c2.PegaSaldo();
c1.Creditar (500);
c2.Creditar (800);
Saldos iniciais:
cout << endl << endl << "Saldos finais:";
Saldo dada
conta
c1:c1:
0 " <<
cout << endl << endl << "\tSaldo
conta
c1.PegaSaldo();
Saldo da conta c2: 200
cout << endl << endl << "\tSaldo da conta c2: " <<
c2.PegaSaldo();
Saldos finais:
cout << endl << endl; system("pause"); return 0;
Saldo da conta c1: 500
}
Saldo da conta c2: 1000
Resultado: Pressione ...

A desalocação de um objeto é feita por outro método
invisível de sua classe

Tem o mesmo nome da classe, precedido do caractere ‘~’,
não tem tipo nem parâmetros

O método que desaloca um objeto é chamado de destrutor de
sua classe

Destrutores podem ser programados e são usados quando se
deseja desalocar alocações dinâmicas
class Exemplo {
private: int dado;
Exemplo:
public: Exemplo () {dado = 0;}
~Exemplo () {}
};
9.1.7 – Atributos estáticos

Até agora, os atributos vistos pertencem ao conjunto
particular de cada objeto de uma classe

No entanto pode haver atributos pertencentes à classe como
um todo

Esses atributos devem ser declarados com a palavra reservada
static

Eles existem independentemente de haver objetos
declarados de tal classe
Exemplo: atributos estáticos
#include <iostream>
#include <conio.h>
using namespace std;
class ccc {
private:
static int atr;
public:
ccc (void);
void SomarAtr (void);
int PegaAtr (void);
ccc :: ccc () {
atr = 0;
}
void ccc :: SomarAtr () {
atr++;
}
int ccc :: PegaAtr () {
return atr;
}
int ccc :: atr;
};
O atributo atr deve ser
definido globalmente
int main () {
ccc c1, c2, c3;
cout << endl <<
cout << endl <<
cout << endl <<
c1.SomarAtr ();
cout << endl <<
c2.SomarAtr ();
cout << endl <<
c3.SomarAtr ();
cout << endl <<
cout << endl <<
}
"atr = " << c1.PegaAtr();
"atr = " << c2.PegaAtr();
"atr = " << c3.PegaAtr();
"atr = " << c1.PegaAtr();
"atr = " << c1.PegaAtr();
"atr = " << c1.PegaAtr();
endl; system("pause"); return 0;
atr
atr
atr
atr
Resultado: atr
atr
=
=
=
=
=
=
0
0
0
1
2
3
Pressione ...
9.1.8 – Classe pilha para cadeias espelhadas

Seja o seguinte conjunto infinito de cadeias:
“k”, “aka”, “bkb”, “abkba”, “bakab”, “abbkbba”,
“abakaba”, “aabkbaa”, ......

Especificação de cadeia típica: wkwr, onde w contém uma
sequência qualquer de ‘a’s e ‘b’s, que pode até ser vazia, e wr é
a sequência inversa a w

Exemplo: se w = “abb”, wr = “bba”

Fazer um algoritmo que leia uma cadeia qualquer x e, usando
uma pilha, determine se x é do tipo wkwr
Método:

Percorrer a cadeia empilhando os ‘a’s e ‘b’s iniciais

Se o primeiro caractere diferente de ‘a’ e ‘b’ for um ‘k’,
avançar; se não for, a cadeia não é wkwr

Comparar cada caractere da cadeia com o topo da pilha:
 Se forem iguais, desempilhar
 Senão, a cadeia não é wkwr
A seguir, o
programa
/* Diretivas de pre-processamento
*/
#include <iostream>
#include <stdlib.h>
#include <conio.h>
using namespace std;
/* Definicao do tipo logic e suas constantes
typedef char logic;
const logic TRUE = 1, FALSE = 0;
/* Definicao do tipo noh
typedef struct noh noh;
struct noh {
char elem;
noh *prox;
};
*/
*/
/* Classe Pilha
*/
class pilha {
private:
noh *topo;
public:
void Inicializar (void);
void Empilhar (char);
void Desempilhar (void);
char Topo (void);
logic Vazia (void);
};
void pilha :: Inicializar () {topo = NULL;}
void pilha :: Empilhar (char x) {
noh *temp;
temp = topo;
topo = (noh *) malloc (sizeof (noh));
topo->elem = x; topo->prox = temp;
}
void pilha :: Desempilhar () {
noh *temp;
if (! Vazia()) {
temp = topo; topo = topo->prox; free (temp); }
}
char pilha :: Topo () {
if (! Vazia()) return topo->elem; else return '\0';}
logic pilha :: Vazia () {
if (topo == NULL) return TRUE; else return FALSE;
}
/* Classe cadeia
*/
class cadeia {
private:
char str[200];
int cursor;
public:
void Ler (void);
void Inicializar (void);
char GetNext (void);
void Escrever (void);
};
void cadeia :: Inicializar () {
cursor = -1;
}
char cadeia :: GetNext () {
cursor++;
return str[cursor];
}
void cadeia :: Ler () {
cin >> str;
}
void cadeia :: Escrever () {
cout << str;
}
/* Funcao main: Verifica se uma cadeia eh espelhada */
int main ( ) {
pilha P; cadeia cad; char wkwr, c;
cout << "Digite a cadeia: ";
cad.Ler(); P.Inicializar(); wkwr = TRUE;
/* Percorre a primeira parte da cadeia
cad.Inicializar();
c = cad.GetNext();
while (c == 'a' || c == 'b') {
P.Empilhar(c); c = cad.GetNext();
}
*/
/* Verifica se a segunda parte eh espelho da primeira
if (c != 'k') wkwr = FALSE;
else {
while (P.Vazia() == FALSE && wkwr == TRUE) {
c = cad.GetNext ();
if (c != P.Topo()) wkwr = FALSE;
else P.Desempilhar();
}
if (wkwr == TRUE) {
c = cad.GetNext();
if (c != '\0') wkwr = FALSE;
}
}
*/
/* Emite o resultado da verificacao
*/
cout << endl << "\t";
cad.Escrever();
cout << ": cadeia ";
if (wkwr) cout << "aceita";
else cout << "rejeitada";
cout << endl << endl; system("pause"); return 0;
}
9.1.9 – Sobrecarga de métodos

Sobrecarga é a possibilidade de vários métodos de uma
mesma classe terem o mesmo nome, porém com protótipos
ligeiramente diferentes

Variações na quantidade ou no tipo dos argumentos e no
tipo de retorno
Exemplo:
#include <math>
class Logaritmo {
public:
double logaritmo(double x);
double logaritmo(double x, double b);
};
double Logaritmo::logaritmo(double x) {
return log(x);
}
double Logaritmo::logaritmo(double x, double b) {
return (log(x)/log(b));
}
Capítulo IX – Programação
Orientada a Objetos
9.1 – Classes, objetos e métodos
9.2 – Herança
9.3 – Polimorfismo
9.2 – Herança

Herança permite criar novas classes a partir de classes
existentes

A classe existente se chama classe base

A nova classe se chama classe derivada
Classe base
(pai)
Classe derivada
(filha)
Classe derivada
(filha)

Um exemplo:
class Pessoa {
private:
char nome[50];
int idade;
class Funcionario: public Pessoa {
int depto;
public:
public:
Funcionario(char *nome, int
idade, int depto);
bool ehResponsavel();
Pessoa(char *nome, int idade);
};
bool Pessoa::ehResponsavel() {
if(idade >= 18 )return true;
};
Funcionario::Funcionario(char
*nome, int idade, int depto)
:Pessoa(nome,idade) {
this->depto = depto;
else return false;
}
}
Pessoa::Pessoa(char *nome, int
idade){
strcpy(this->nome,nome);
this->idade=idade;
}
9.3 – Polimorfismo

Na herança, os objetos da classe derivada herdam os
atributos e os métodos da classe base

Além disso, uma classe derivada pode sobrescrever os
métodos da sua classe base, isto é, ter uma versão particular
dessas operações

Consequentemente, a execução de um mesmo método, se
realizada por objetos de classes distintas (base e derivada,
por exemplo), pode gerar diferentes ações
Exemplo:
class Pessoa {
private:
char nome[50];
int idade;
public:
virtual bool ehResponsavel();
Pessoa(char *nome, int idade);
char *getNome();
};
char *Pessoa::getNome() {
return nome;
}
bool Pessoa::ehResponsavel() {
if (idade >= 18) return true;
else return false;
}
Pessoa::Pessoa(char *nome, int idade)
{
strcpy(this->nome,nome);
this->idade=idade;
}
Possibilita
sobrescrita
Uma classe derivada:
class Casado: public Pessoa {
public:
bool ehResponsavel();
Casado(char *nome,int idade): Pessoa(nome,idade) { }
};
bool Casado::ehResponsavel() {
return true;
}
Download