Algoritmos e Estruturas de
Dados
Aula 01 – Introdução a Programação Orientada a Objetos, e Tipos Abstratos de Dados
Professor Renato Vimieiro Centro de Informática – UFPE
Introdução
• Até esse momento, nossos programas envolviam dados bastante simples (de um mesmo tipo) que eram armazenados também
estruturas simples
• Vetores de inteiros, reais ou textuais, por exemplo
• Sistemas maiores exigem abstrações mais próximas da realidade
• O modelo ou paradigma de programação estudado até agora focava em instruções imperativas organizadas em funções para manipulação de dados
Introdução
• No paradigma imperativo, existe uma clara divisão entre dados e instruções
• Tal separação não é tão explícita no mundo real
• Os objetos do mundo real concentram tanto características/dados quanto ações que podem executar
• Exemplo: O painel de um forno elétrico armazena a informação da
temperatura atual e possui as funções ligar/desligar e aumentar/diminuir temperatura
Introdução
• Essas funções e dados do forno seriam implementadas separadamente segundo o paradigma imperativo
• Entre outros problemas, podemos perceber uma certa falta de unidade
• Não está explícito que todas aquelas funções e dados são referentes a uma única entidade, forno.
• O paradigma de programação orientada por objetos, como o próprio nome sugere, baseia-se em trocas de mensagens entre objetos
Programação Orientada a Objetos (POO)
• O conceito central em POO é o de objetos.
• Como na realidade, objetos são dotados de características (dados/variáveis) e ações que podem executar (funções) • As características de um objeto são chamadas de atributos
• As ações (funções) que o objeto pode executar são chamadas de
métodos
• Os objetos são organizados em classes que definem os atributos e métodos comuns a todos eles
Programação Orientada a Objetos (POO)
• Uma classe em C++ é definida da seguinte maneira class ID{
<atributos>
<métodos>
};
• Para exemplificar, considere um programa em que devemos
Classes em C++
class Pessoa { public: string nome; string sobrenome; Pessoa( ); Pessoa(string nome, string sobrenome);string getNome( ){ return nome;} }; Pessoa::Pessoa( ){ this->nome = “”; this->sobrenome = “”; } Pessoa::Pessoa(string nome, string sobrenome ){ this->nome = nome; this->sobrenome = sobrenome; }
Classes em C++
• A classe Pessoa define um ‘molde’ para seus objetos
• Após definir essa classe no programa, estamos aptos a criar objetos que concentrarão todas as informações pessoais de um indivíduo • Para ‘criarmos’ uma variável do tipo Pessoa, usamos a seguinte
sintaxe:
• Pessoa eu(”Renato”,”Vimieiro”) • Pessoa ele(“Alan”,”Turing”)
• Pessoa ela(“Ada”,”Lovelace”) • Pessoa ninguem;
Classes em C++
• No exemplo anterior, criamos quatro objetos da classe Pessoa (eu, ele, ela e ninguém)
• Os objetos de uma classe são chamados de instâncias da classe; e a criação de um novo objeto instanciação
• Cada objeto/instância possui/armazena suas próprias características • A instanciação de um novo objeto requer a alocação de um espaço na
memória para armazenamento de todos os membros
• Os membros de um objeto são acessados usando o ponto (eu.nome ou ele.sobrenome)
• O exemplo anterior mostrou a criação de objetos estáticos, ou seja, objetos criados daquela forma possuem escopo/tempo de vida associado ao local onde foram criados
Classes em C++
• Na definição da classe Pessoa, observamos um método especial
Pessoa
• Esse método é chamado de construtor e tem como objetivo inicializar os valores dos atributos do objeto
• Podemos definir vários construtores desde que possuam assinaturas diferentes
• O construtor sem parâmetros é chamado de construtor padrão e os demais alternativos
• Os métodos podem ser definidos fora da classe, bastando qualificá-los (Pessoa::)
Classes em C++
• Todos os objetos em C++ possuem um atributo especial chamado this. Este atributo é uma referência para o próprio objeto.
• Como dito anteriormente, o construtor serve para “construir” o objeto da forma que desejamos
• Similarmente, podemos definir quais são as ações a serem executadas quando um objeto deixar de existir
• Tal método especial é chamado de destrutor da classe
• Destrutores em C++ são definidos pelo método com o mesmo nome da classe (como os construtores) precedidos por ~
• ~Pessoa()
• Os destrutores são chamados imediatamente antes de um objeto deixar de existir
Classes em C++
• Exemplo: class Pessoa{ ... ~Pessoa( ){ this->nome = this->sobrenome = “”; std::cout << “Apagado” << std::endl; } ... };Classes e alocação dinâmica
• Como foi dito, objetos criados como nos exemplos anteriores são
estáticos e estão associados ao escopo do bloco onde foram criados. • C++ permite o controle total da alocação e desalocação de recursos
de memória.
• Em outras palavras, podemos dissociar o tempo de vida de um objeto do escopo do bloco onde ele foi criado. Esse processo é chamado de alocação dinâmica.
• A alocação e liberação de recursos é feita em C++ com os comandos
Classes e alocação dinâmica
• Para alocar um objeto dinamicamente, usamos a seguinte sintaxe
• Pessoa * eu = new Pessoa(“Renato”,”Vimieiro”);
• Pessoa * ele = new Pessoa(“Alan”,”Turing”);
• Pessoa * ela = new Pessoa(“Ada”,”Lovelace”);
• Pessoa * ninguem = new Pessoa( );
• O comando new aloca um espaço na memória para o objeto e retorna uma referência/ponteiro para seu endereço de memória.
• Objetos alocados dinamicamente ‘vivem’ até o momento em que são liberados através do comando delete
• delete eu;
• CUIDADO!!! Se você liberar um endereço, todas as outras referências para aquela área
apontarão para um endereço inválido (dangling pointers)
• ninguem = eu;
• delete eu;
Tipos Abstratos de Dados
• Note que a definição de classes ‘introduz’ novos tipos à linguagem • Ao definir a classe Pessoa, passamos a ter um novo tipo de dados em
C++
• Esse novo tipo pode conter dados de diversos tipos (heterogêneo), criando uma abstração sobre eles
• Um tipo abstrato de dados é um conjunto de objetos e as operações definidas sobre eles
Tipos Abstratos de Dados
• A definição de uma classe cria uma nova abstração. Os métodos e atributos abstraem para o usuário as ações e características de seus objetos.
• O usuário sabe que as informações estão armazenadas no objeto e que certas ações podem ser executadas, mas não sabe como elas são.
• Essa é uma das grandes vantagens desse paradigma de programação. • A abstração sobre tipos de dados oculta os detalhes desnecessários em
algumas partes e permite restabelecer o foco naquilo que realmente importa
• Se armazenarmos pessoas em uma lista e quisermos apresentá-las em ordem alfabética, não nos interessa saber que uma pessoa é representada por nome,
sobrenome, etc; somente em como compará-las, cujos detalhes também podem ser omitidos
Encapsulamento
• Apesar de programação orientada por objetos ser centrada em
objetos, ela está baseada em três pilares: encapsulamento, herança e polimorfismo.
• O encapsulamento é, como o nome sugere, a concentração e ocultação de detalhes na classe
• C++ permite ao programador da classe controlar a visibilidade das informações para os usuários
• Em geral, o acesso direto aos atributos é restrito, sendo feito através da interface oferecida pelos métodos
Encapsulamento
• A visibilidade de métodos e atributos é feita através das palavras-chave:
• public – Acesso livre
• private – Acesso interno
• protected – Acesso interno à classe e suas derivadas
• A maior virtude do controle de acesso é garantir a integridade dos objetos. Como o usuário não tem acesso aos membros privados, diminui-se o risco dos dados serem corrompidos por alguma alteração não-intencional
• Além disso, como dito, ela permite ocultar detalhes desnecessários para o usuário final
• Poderíamos ter um atributo privado data de nascimento para a pessoa, e um método público idade que calcularia quantos anos a pessoa teria no momento da chamada