Linguagem de Programação II Carlos Oberdan Rolim Ciência da Computação Sistemas de Informação Classes Prog. Procedural x Orientação Objeto Linguagem procedural: dois conceitos – dados e algoritmo Dados + algoritmo = programa Orientação a objetos Enfatiza dados Preocupação centrada nos objetos a serem manipulados e não na lógica necessária para manipulá-los Prog. Procedural x Orientação Objeto Primeiro passo – identificar os objetos que se quer manipular e como eles se relacionam uns com os outros Generalizar como uma classe de objetos e define o tipo de dado que ela conterá e as sequencias lógicas para manipulálos (são os métodos) Objeto é o que será executado no computador Conceitos mais importantes: abstração, encapsulamento, polimorfirsmo, herança Abstração Exemplo do banco de dados de alunos que contém dados importantes dos alunos relacionados a sua vida escolar e não dados pessoais como cor do cabelo ou olhos Consiste em desprezar características de alguma coisa para reduzi-las a um conjunto de características essenciais Abstração Nesta fase tenta-se retirar elementos e requisitos que irão ajudar na resolução de um problema; É o processo de retirar do domínio do problema os detalhes relevantes e representá-los não mais em uma linguagem do domínio e sim na linguagem da solução. O sucesso de um Programa Orientado a Objeto está condicionado a uma boa abstração do problema Abstração No paradigma da Programação Estruturada identifica-se as funções como sendo "operações abstratas que resolvem um problema de programação", ou seja, ocorre a abstração de procedimentos. No paradigma da Orientação a Objetos, tem-se a Abstração de Dados, onde uma estrutura de dados deve incluir as operações que ocorrem com ela. Abstração Primeiramente procura-se dividir o problema por assuntos ou pequenas partes que compõem o todo; Dentro de cada assunto pode-se observar alguns elementos tais como : categorias; Ações; informações de estado; Operações; Categoria Por exemplo, se tentarmos resolver um problema ligado a esportes de modo geral, ao abstrair a categoria bola, que é utilizada em esportes tais como: futebol, basquete, golfe, etc. Esta instância concreta, representando todas as bolas, poderia ser descrita pelas propriedades : Peso; Cor; Diâmetro Outro exemplo: um automóvel descrito com as propriedades: Potência; Cilindradas; Número de passageiros; Ações Podemos observar uma bola vazia e queremos transforma-la em uma bola cheia. Para isto precisamos de aplicar uma ação de encher a bola, para transformar ‘dados de entrada’ em ‘dados de saída’. No caso do automóvel poderíamos ter a ação de abastecer, que teremos uma quantidade de combustível para achar o consumo em KM/L. Informações de estado A partir da observação de uma bola, pode-se encontrar os valores 30 e branca, este valores seriam valores encontrados para um atributo de uma determinada bola, que seriam as propriedades diâmetro (em cm) e cor. Para o automóvel teríamos valores como: Cilindradas = 1600 Potência = 95cv Número de passageiros = 5 Classe Classes e objetos são os elementos básicos da programação orientada a objetos Classes são os meios que traduzem a abstração de dados em um tipo Na orientação a objetos Cria-se estruturas Na orientação a objetos Cria-se classes Classe No mundo real freqüentemente percebemos vários objetos de um mesmo tipo. Por exemplo: seu carro é um dos muitos carros existentes no mundo. Usando a terminologia OO, dizemos que um carro em particular é uma instância da classe de objetos conhecida como carros. Os carros, em geral, possuem estado (cor, potência do motor, combutível) e comportamento (ligar, acelerar, brecar, mudar marcha) em comum. Classe O estado de cada carro é independente e pode ser diferente do estado dos outros carros. Cada carro pode ter uma cor diferentes, por exemplo. A partir dessas semelhanças, os fabricantes de veículos tiram vantagem disso para padronizar a construção de carros de um mesmo tipo, definindo um modelo único com características iguais para todos os carros a serem produzidos. Classe Na Orientação a Objetos também é possível ter vários objetos do mesmo tipo, que compartilham caracteríscas em comum. Tirando vantagem dessa semelhança entre alguns objetos, também é possível criar modelos para esses objetos. Esse modelo é chamado de CLASSE. As classes são tipos que podem ser criados. Por definição: Uma classe é um modelo (protótipo) que define as variáveis (estado) e os métodos (comportamento) comuns a todos os objetos do mesmo tipo. Classe Na classe são definidas as variáveis e implementados os métodos. Os objetos são criados a partir de suas classes. A cada objeto criado o sistema aloca memória para o novo objeto e suas variáveis. Comumente fazem confusão entre classes e objetos. Lembre-se que classe define as características comuns e os objetos são instâncias dessas classes, com estado próprio. Atributos e métodos Atributo representa alguma propriedade do que está sendo modelado - identifica as características próprias da classe Descreve os dados contidos nas instâncias de uma classe Um método é a implementação de uma operação para uma classe. Ver visibilidade na aula de UML +publico #protegido -privado Objeto Objeto é uma instância de uma classe Reflete a capacidade do sistema de guardar informações sobre o elemento abstraído, interagir com este, ou ambos. Um objeto de software mantém seu estado em uma ou mais de suas variáveis (atributos). Ele implementa seu comportamento através de seus métodos. Esses métodos e atributos são exclusivos do objeto Encapsulamento Método é o mesmo que função ou procedimento. Por definição: Um objeto é um pedaço de software que possui variáveis(estado) e métodos (comportamento) Objeto Objeto Um sistema pode conter um ou inúmeros objetos ativos. Cada objeto ativo no sistema em particular também é chamado de instância. As diferentes instâncias possuem seu próprio estado. O exemplo abaixo mostra várias intâncias de pessoas Objetos e classes Na classe são definidas as variáveis e implementados os métodos. Os objetos são criados a partir de suas classes. A cada objeto criado o sistema aloca memória para o novo objeto e suas variáveis. Comumente fazem confusão entre classes e objetos. Lembre-se que classe define as características comuns e os objetos são instâncias dessas classes, com estado próprio. Instância - Classe & Objeto Instância é um sinônimo para o termo Objeto, também encontrado na literatura, é Instância de Uma Classe, ou simplesmente Instância. Por exemplo : o objeto “Vectra" é uma instância da classe "Automóvel". Usa-se o termo Classe & Objeto para se referenciar uma Classe e os Objetos que a ela pertencem. Mensagem Um objeto por si só não significa muito em um sistema. Para ter algum sentido e valor esses objetos precisam interagir e comunicarse entre si. Os objetos se comunicam por meio de mensagens. Quando um objeto A quer se comunicar com um objeto B é enviada uma mensagem de A para B. Mensagem Enviar uma mensagem significa executar um método. Então, se A envia uma mensagem para B, podemos entender como o objeto A executando um método do objeto B. As mensagens são compostas por três partes: Objeto a quem a mensagem é endereçada Nome do método a ser chamado Parâmetros que o método recebe Mensagens É uma forma de relacionamento entre objetos; É através delas que os objetos interagem (se comunicam) em um programa. Tratam-se de pedidos enviados a um objeto, a fim de que este modifique seu estado ou retorne algum valor. Em um programa orientado a objeto, nenhuma outra parte do programa pode acessar diretamente os dados de um objeto. Toda a comunicação entre os objetos ocorre única e exclusivamente através de mensagens. Mensagens A interação entre os objetos é feita através da troca de mensagens; São representados na UML através dos diagramas de iteração e de colaboração. Encapsulamento / Ocultação de dados Usuários precisam conhecer apenas os detalhes essenciais de como acessar e utilizar tal componente Usuários não precisam conhecer os detalhes da implementação do componente Trata-se de uma das principais vantagens da Programação Orientada a Objetos sobre a Programação Estruturada, principalmente na reutilização de códigos. Encapsulamento / Ocultação de dados Pode-se entender intuitivamente o significado de encapsulamento quando se observa o mundo real. Nos objetos do mundo real, atributos e ações são inerentes ao próprio objeto. Exemplo : A um automóvel estão associados tanto atributos (modelo, kilometragem, cilindradas, capacidade do tanque de combustível, etc), quanto suas potencialidades (velocidade média, consumo de combustível, etc) porém para o usuário não importa em saber detalhes para poder dirigi-lo. Encapsulamento Na OO, encapsulamento é o mecanismo utilizado para disponibilizar métodos que operam sobre os dados e que protegem o acesso direto indevido aos atributos de uma instância fora da classe onde estes foram declarados. Esta proteção consiste em se usar modificadores de acesso mais restritivos sobre os atributos definidos na classe e fornecendo métodos que alteram os valores destes atributos de alguma forma. O encapsulamento ajuda a prevenir o problema de interferência externa indevida sobre os dados de um objeto, como objetos que possam alterar os dados de outros objetos indevidamente. Encapsulamento / Ocultação de dados Código ... ... Dado Código ... ... Dado Programação estruturada Código ... ... Dado Dado Código Código Código Dado Dado Dado ... ... Orientação a Objetos ... ... ... ... Polimorfismo O significado da palavra, originada do grego, é o de "possuir várias formas". Na POO é usado para indicar a propriedade de se utilizar o mesmo nome para métodos diferentes. Uma vantagem do polimorfismo é a relativa facilidade de manutenção e extensão dos programas. A idéia de polimorfismo está ligada com a indicação de que os atributos só devem ter seus valores alterados por métodos da classe. Polimorfismo Uma das estratégias adotadas na Programação Orientada a Objeto é a de implementar os métodos o mais alto possível na hierarquia de classes. As variações necessárias nos métodos são feitas a medida em que se desça a árvore hierárquica. O conceito de Polimorfismo é relevante pelo caráter sintético que dá aos programas. Polimorfismo O Polimorfismo não consiste simplesmente na existência de funções com o mesmo nome, que pode ser uma sobrecarga de função. A diferença entre sobrecarga de funções e polimorfismo vem de 2 fatos : O polimorfismo só existe em hierarquia de classes (herança) e deve ser feito em tempo de execução (Run time). A sobrecarga não exige herança e o processo de associação com um objeto se dá em tempo de compilação. Polimorfismo ClasseBase Mostrar() ClasseD1 Mostrar() ClasseD2 Mostrar() ClasseD3 Mostrar() objGeral.mostrar(); Polimorfismo ClasseBase Mostrar() ClasseD1 Mostrar() ClasseD2 Mostrar() ClasseD3 Mostrar() objGeral.mostrar(); Polimorfismo ClasseBase Mostrar() ClasseD1 Mostrar() ClasseD2 Mostrar() ClasseD3 Mostrar() objGeral.mostrar(); Polimorfismo ClasseBase Mostrar() ClasseD1 Mostrar() ClasseD2 Mostrar() ClasseD3 Mostrar() objGeral.mostrar(); Polimorfismo ClasseBase Mostrar() ClasseD1 Mostrar() ClasseD2 Mostrar() ClasseD3 Mostrar() objGeral.mostrar(); Herança É um mecanismo de hierarquia entre classes, onde uma classe mais especializada (filho) herda as propriedades da classe mais geral (pai). Este recurso não está disponível em sistemas procedurais, caracterizando-se em uma das principais diferenças entre a Análise Orientada a Objetos e a Análise Estruturada. A classe mais geral é denominada superclasse e a classe mais especializada é chamada subclasse. Herança Herança é uma relação entre uma superclasse e suas subclasses; A subclasse está subordinada a superclasse na hierarquia de classes. Há duas formas de se descobrir heranças: Generalização Especialização Herança sempre ocorrem de classe para classe; Herança representa um relacionamento "É um tipo de". Assim, a partir da estrutura de Especialização, diz-se que esta "é um tipo da" estrutura de Generalização. Herança Atributos comuns, operações, relações e/ou, são mostradas no nível aplicável mais alto da hierarquia Ao se definir a hierarquia, deve-se ter em mente a premissa básica de que as categorias inferiores sempre satisfazem todos os atributos e serviços das categorias às quais elas representam especializações. Uma classe filha deve ter, no mínimo, uma propriedade de distinção em relação à classe pai. Herança: Exemplo Funcionário Nome Endereço Salário Faltas CalcularSalario( Mostrar() Cliente Nome Endereço Compra TipoPagamento GerarRecibo() Mostrar() Nome Endereço Salário Faltas CalcularSalario() Mostrar() Compra TipoPagamento GerarRecibo() Mostrar() Herança: Exemplo Pessoa Nome Endereço Mostrar() Funcionário Salário Faltas CalcularSalario() Mostrar() Cliente Compra TipoPagamento GerarRecibo() Mostrar() Herança veiculo chapa:char[8] cor:integer chassis:char[30] carga peso_max:integer alt_max:integer comp_max:integer passageiros pass_max:integer Herança Múltipla Vimos o conceito de Herança como sendo quando uma classe especializada (filho) herda as propriedades de uma classe genérica (pai). E pelo exemplo percebemos que ‘um pai pode ter vários filhos’. E o filho ter vários pais ? O fato de uma classe especializada herdar propriedades de várias classes genéricas é o que chamamos de herança múltipla. Ex : Um telefone - secretária eletrônica, que herda as propriedades dos 2 aparelhos para formar um único Herança Múltipla - Exemplo O dono da loja dá um incentivo especial para alguns funcionários, isto é, um desconto para que eles comprem na própria loja. Além disto, as compras serão debitadas do salário. Os descontos serão diferenciados a critério do proprietário. Por causa disto surge a necessidade de se ter objetos para cadastrar os funcionários que possam ser clientes especiais, ou seja, uma classe Funcionário_Cliente que herde as características de Funcionário e também as de Cliente. Para que o salário destes, possam ser refeito com debito das compras (c/ desconto). Pessoa Herança múltipla Nome Endereço Mostrar() Funcionário Salário Faltas CalcularSalario() Mostrar() Cliente Compra TipoPagamento GerarRecibo() Mostrar() Funcionário_Cliente Desconto CalcularSalario() Mostrar() Declarando classes e criando objetos class nome_da_classe { public: // secao publica variavel; variavel; metodo; metodo; private: variavel; variavel; metodo; } // secao privada Declarando classes e criando objetos class carro { public: char marca [12]; char modelo [7]; int anofab; void exibe() { cout << “Marca” << marca << endl; cout << “Modelo” << modelo << endl; cout << "Ano " << anofab << endl; } private: char placa[9]; } Exemplo classe carro Declarando classes e criando objetos carro carro1; strcpy(carro1.marca, "Volks"); strcpy(carro1.modelo, "Gol"); carro1.anofab = 2003; Saída: Objeto carro1 Marca Volks cout << "Objeto carro1" << endl; carro1.exibe(); Modelo Gol Ano 2003 Declarando classes e criando objetos Por que deu o seguinte erro ? carro carro1; `char main()::carro::placa[9]' is private strcpy(carro1.marca, "Volks"); strcpy(carro1.modelo, "Gol"); strcpy(carro1.placa, "IDC-1234"); carro1.anofab = 2003; cout << "Objeto carro1" << endl; carro1.exibe(); #include <iostream> #include <cstring> #include <conio.h> carro carro1; using namespace std; strcpy(carro1.marca, "Volks"); strcpy(carro1.modelo, "Gol"); int main() { //strcpy(carro1.placa, "IDC-1234"); class carro { public: char marca [12]; char modelo [7]; int anofab; carro1.anofab = 2003; cout << "Objeto carro1" << endl; void exibe() { cout << "Marca " << marca << endl; cout << "Modelo " << modelo << endl; cout << "Ano " << anofab << endl; carro1.exibe(); getch(); } private: char placa[9]; }; return 0; } Seções de uma classe Seção publica Membros podem ser acessados por quaisquer objetos da classe Qualquer programa que utilize um objeto de uma determina classe pode acessar seus membros públicos diretamente Palavra chave public Seção privada Membros dessa seção podem ser acessados somente pelos métodos da classe ou pelas funções friends. Palavra chave private Quando não declaramos a que seção pertence um método ou atributo automaticamente são privados Definição dos métodos e métodos inline Os métodos de uma classe podem ser declarados e codificados dentro de uma classe ou fora dela Quando codificados fora dela usar o operador de resolução de escopo :: para dizer a que classe pertence Bastante comum e uma boa prática class carro { ….. void exibe(); // declaracao dentro da classe }; void carro :: exibe() { cout << "Marca " << marca << endl; cout << "Modelo " << modelo << endl; cout << "Ano " << anofab << endl; } Definição dos métodos e métodos inline Quando um método é codificado dentro da própria classe torna-se automaticamente um método inline É comum implementarmos métodos inline para métodos que possuem poucas linhas de código class carro { Codificado dentro da própria classe ….. void exibe() { cout << "Marca " << marca << endl; cout << "Modelo " << modelo << endl; cout << "Ano " << anofab << endl; } Se o programador quiser fazer um método externo a sua classe se tornar inline basta usar a palavra chave inline antes do tipo de valor de retorno inline void carro :: exibe() { …. } Setters e Getters Motivação: Respeitar o principio do encapsulamento Usar atributos privados Usar métodos para definir e obter o valor dessas variáveis Esses métodos são conhecidos como setters (para “setar” o valor a um atributo) getters (para “obter” o valor de um atributo) Setters e Getters Exemplo class pessoa { string nome; public: string getNome(){ // Retorna o valor do atributo return nome; } void setNome(string n){ // Define o valor do atributo nome = n; } }; Construtores São métodos que são executados no momento em que um objeto da classe é instânciado Possuem o mesmo nome da classe O protótipo do construtor deve estar declarado na seção public da classe Pode receber argumentos mas não pode retornar um valor #include <iostream> #include <cstring> #include <conio.h> int main() { // Instancia objeto chamando construtor using namespace std; carro carro1(“Volks”, “Gol”, 123); class carro { string marca; string modelo; int anofab; public: carro (string m1, string m2, int a); ….. }; carro :: carro(string m1, string m2, int a){ marca = m1; modelo = m2; anofab = a; } ….. getch(); return 0; } Formas de inicialização de um objeto O construtor pode ser invocado de duas formas Implicitamente carro carro1(“Volks”, “Gol”, 123); Explicitamente carro carro1 = carro(“Volks”, “Gol”, 123); Construtor default Uma vez definido um construtor o programador deverá obrigatoriamente utiliza-lo carro(char *, char *, int); ..... carro carro1(“Volks”, “Gol”,123); funciona carro carro2; Não funciona. Não foram passados os argumentos esperados Porém é possível instanciar objetos sem inicializá-los ou então inicializá-los com valores padrão Para isso se usa o construtor default Construtor default Por ser uma função deve ter o protótipo e definição, mas não recebe argumentos Pode ser definido de duas formas: Por meio de valores default passados a todos os argumentos do construtor existente Por meio de sobrecarga de funções utilizando um segundo construtor, mas sem argumentos (construtor vazio) Se não for declarado um construtor o C++ cria automaticamente um construtor vazio para o programador #include <iostream> #include <cstring> #include <conio.h> using namespace std; class carro { string marca; string modelo; int anofab; public: // Construtor default com valores default carro (string = “”, string = “”, int = 0); } .. int main() { // Instancia objeto chamando construtor carro carro1(“Volks”, “Gol”, 123); carro carro2; construtor default ….. getch(); return 0; }; carro :: carro(string m1, string m2, int a){ marca = m1; modelo = m2; anofab = a; } Exemplo de código com construtor default com valores default #include <iostream> #include <cstring> #include <conio.h> using namespace std; // Implementacao do const default vazio carro :: carro () { } class carro { string marca; string modelo; int anofab; int main() { // Instancia objeto chamando construtor carro carro1(“Volks”, “Gol”, 123); public: carro (string , string , int); carro carro2; construtor default ….. // Construtor default vazio carro (); .. getch(); return 0; }; carro :: carro(string m1, string m2, int a){ marca = m1; modelo = m2; anofab = a; } } Exemplo de código com construtor vazio Construtor de cópia Quando instanciamos um objeto e queremos inicializá-lo com valores guardados em outro objeto já existente class Ponto { float x, y; public : Ponto( Ponto & ); Ponto(float a, float b) {x = a; y= b; } }; void main(){ Ponto estePonto(2.2, 5.3); Ponto outroPonto = estePonto; } Ponto::Ponto(Ponto & _ponto){ x = _ponto.x; y = _ponto.y; } Destrutores É invocado quando um objeto sai do escopo ou quando é eliminado pelo operador delete (no caso de alocação dinâmica pelo operador new) não podem ter argumentos, retorno e não podem ser sobrecarregados. Mesmo nome da classe iniciando com ~ class NomeClasse { ... public : ~Nome_Classe (); } // Sintaxe na definição da Função Destrutora : NomeClasse :: ~ NomeClasse () { // código na função destrutora } Ponteiro this É um ponteiro que aponta para o objeto corrente É criado automaticamente pelo compilador void carro :: exibe (){ cout << “Nome :” << nome; cout << “Nome com ponteiro this:” << this -> nome; cout << “Nome com ponteiro this de-referenciado:” << (*this).nome; Como this é um ponteiro a necessidade do seletor indireto de membro -> ou o operador de de-referencia *