Baixe o app para aproveitar ainda mais
Prévia do material em texto
Escola Politécnica da Universidade de São Paulo Escola Politécnica da Universidade de São Paulo Laboratório de Programação Orientada a Objetos para Engenharia Elétrica Aula 8: Classe Abstrata e Herança Múltipla PCS3111 Agenda 1. Classe abstrata 2. Herança múltipla 3. Atributos e métodos estáticos 2 Agenda 1. Classe abstrata 2. Herança múltipla 3. Atributos e métodos estáticos 3 Abstração ! Em uma hierarquia, às vezes é útil representar conceitos abstratos • Representa uma abstração de um ou mais conceitos • Não existe uma instância deste conceito ! Exemplo: ordem Carnivora da biologia • Não existe um mamífero que seja dessa ordem mas que não pertença a uma de suas espécies 4 Classe abstrata ! Não pode ser instanciada • Serve de base para a criação de outras classes ! Pode não estar completamente implementada • Define o comportamento, mas não como ele é implementado ! Métodos abstratos ! Exemplo 5 retirar(valor) depositar(valor) transferirPara(destino, valor) getSaldo numero saldo ContaCorrente retirar(valor) getLimite() limite ContaEspecial retirar(valor) getSaldo() numeroDeTransacoes ContaSalário Como funciona o retirar? Saldo negativo até um limite Saldo não negativo Classe abstrata ! Permite aproveitar os benefícios da herança • Reaproveitar código • Substituição ! Princípio da substituição 6 Alguns usos 1. Para ser uma base para herança • Comportamento comum • Conceitualmente, uma classe abstrata pode não ter métodos abstratos 7 ContaCorrente getNome() setNome() getEndereco() setEndereco() getTelefone() setTelefone() nome endereço telefone Cliente getCPF() getDataDeNascimento() cpf dataDeNascimento Pessoa getCNPJ() cnpj Empresa * 1 Cliente é a classe abstrata – identificador em itálico Associação entre classes – notação UML – Um Cliente pode ter várias ContaCorrente (*) - Uma ContaCorrente pertence a um só Cliente (1) Alguns usos 2. Para simplificar o relacionamento com classes que sejam comuns a todas as subclasses • ...e podem ser representadas por um conceito geral 8 class Cliente { public: ... protected: ContaCorrente* contas[MAX]; Seguro* seguros[MAX]; Previdencia* previdencias[MAX]; }; Cliente ContaCorrente Seguro Previdência * * * class Cliente { public: ... protected: Produto* produtos[MAX]; }; Cliente ContaCorrente Seguro Previdência * Produto Alguns usos 3. Para permitir a escolha do método em tempo de execução • Uma classe é abstrata se tiver, pelo menos um, método abstrato. • Uma classe abstrata pode ter todos os métodos abstratos 9 Classes filhas redefinem o método retirar retirar(valor) depositar(valor) transferirPara(destino, valor) getSaldo numero saldo ContaCorrente retirar(valor) getLimite() limite ContaEspecial retirar(valor) getSaldo() numeroDeTransacoes ContaSalário Classe abstrata em C++ ! Não há uma declaração direta de classe abstrata • Uma classe é abstrata quando pelo menos um de seus métodos é abstrato ! Terminologia C++: método puramente virtual (virtual e = 0) 10 … 4 class ContaCorrente { 5 public: 6 ContaCorrente (int numero); 7 virtual ~ContaCorrente(); 8 virtual bool retirar (double valor) = 0; 9 virtual void depositar (double valor); … 14 protected: 15 double saldo; 16 private: 17 int numero; 18 }; EX01 Método abstrato Método concreto com ligação dinâmica Classe abstrata em C++ ! Classe abstrata é uma classe normal • Pode ter uma classe pai • Pode ter atributos e métodos concretos • Pode ter um construtor ! C++ não permite criar uma classe abstrata em que todos os métodos são concretos • Mas é possível que ela tenha apenas métodos abstratos 11 O método abstrato não deve ser colocado na implementação da classe abstrata Classe abstrata em C++ ! Uma classe filha precisa implementar todos os métodos abstratos • Ou ela também deve ser abstrata • O método abstrato deve ser colocado na declaração da classe 12 … 6 class ContaEspecial : public ContaCorrente { 7 public: 8 ContaEspecial (int numero, double limite); 9 virtual ~ContaEspecial(); 10 bool retirar (double valor); 11 virtual double getLimite(); 12 private: 13 double limite; 14 }; Método era abstrato na superclasse. Aqui é concreto! EX01 ! Equipamento é uma classe abstrata ! As classes Carga e Fonte fazem sentido “no contexto” de Smart Grids. Uma Carga pode ser uma Lâmpada e uma Fonte pode ser uma Bateria. Exemplo no contexto de Smart Grids 13 Ela tem duas filhas: - Carga - Fonte Quem é essa classe? O que ela faz? Apenas se sabe que: - pode ser programada; - tem um estado; - possui uma hora de ligar e de desligar. EX02 Agenda 1. Classe abstrata 2. Herança múltipla 3. Atributos e métodos estáticos 14 Herança múltipla ! Uma classe tem 2 ou mais classes-mãe • Exemplo ! Qual é o problema disso? 15 retirar(valor) depositar(valor) retirar(valor, investimento) investir(valor, investimento) saldo ContaInvestimento retirar(valor) depositar(valor) transferirPara(destino, valor) getSaldo saldo ContaCorrente retirar(valor) getLimite() limite ContaEspecial superclasses ContaEspecial, nesse caso, além de ser herdeira de ContaCorrente, herda também de ContaInvestimento. Problema: ambiguidade ! Se um nome estiver definido em mais de uma classe pai qual nome usar? • Exemplo 16 retirar(valor) depositar(valor) retirar(valor, investimento) investir(valor, investimento) saldo ContaInvestimento retirar(valor) depositar(valor) transferirPara(destino, valor) getSaldo saldo ContaCorrente retirar(valor) getLimite() limite ContaEspecial Qual saldo usar? Qual método depositar é usado? Problema: ancestral comum ! Quantos atributos a classe deve ter? • Problema do diamante 17 retirar(valor) retirar(valor, investimento) investir(valor, investimento) ContaInvestimento transferirPara(destino, valor) getSaldo ContaCorrente retirar(valor) getLimite() limite ContaEspecial retirar(valor) depositar(valor) saldo ContaBancaria Tem 1 saldo ou 2 saldos? Herança múltipla ! Algumas linguagens não permitem a herança múltipla • Exemplo: Java e C# • O C++ permite! ! Ainda assim é bom evitar a herança múltipla ! (Capítulo 13 do livro do Budd) ! Discute-se a seguir um exemplo. 18 Herança múltipla 19 ! Considere-se o seguinte caso de herança múltipla, onde não ocorrem problemas de ambiguidade. Não há atributos nem operações com nomes duplicados A subclasse tem acesso a todas as operações das superclasses EX03 Herança múltipla ! A apresentação desse exemplo leva em conta alguns cuidados especiais para evitar os problemas descritos: • Não haverá ambiguidade de nomes; os nomes dos atributos e operações das classes foram escolhidos como diferentes em cada classe; • Não há um ancestral comum. ! As classes ContaCorrente e ContaInvestimento foram construídas de forma muito parecidas apenas por simplificação, mas poderiam ser adequadas para uma aplicação bancária, podendo ser expandidas com novas funcionalidades. 20 Como declarar a herança múltipla 21 8 class ContaCorrente { 9 public:10 ContaCorrente (int numero); 11 virtual ~ContaCorrente(); 12 13 bool retirarCC (double valor); 14 void depositarCC (double valor); 15 bool transferirPara (ContaCorrente* destino, 16 double valor); 17 double getSaldoCC(); 18 int getNumeroCC(); 19 protected: 20 double saldoCC; 21 int numeroCC; 22 }; A classe ContaCorrente pode ser entendida como uma conta corrente normal, com operações simples e sem nenhum limite extra de crédito. Somente se pode sacar dessa conta, quantias menores que o saldo disponível, saldoCC. EX03 Como declarar a herança múltipla 22 5 #include "ContaCorrente.h" … 9 class ContaInvestimento 10 { 11 public: 12 ContaInvestimento (int numero); 13 virtual ~ContaInvestimento(); 14 15 bool retirarCI (double valor); 16 void depositarCI (double valor); 17 bool transferirCIParaCC (ContaCorrente* destino, 18 double valor); 19 double getSaldoCI(); 20 int getNumeroCI(); 21 protected: 22 double saldoCI; 23 int numeroCI; 24 }; A classe ContaInvestimento possui uma operação, transferirCIParaCC que necessita conhecer características da classe ContaCorrente. Essa classe tem um saldo, saldoCI, que pode render juros, porém a operação de cálculo de juros não foi incluída, porque nada acrescenta ao problema que está sendo tratado. EX03 4 #include "ContaCorrente.h" 5 #include "ContaInvestimento.h" … 9 class ContaGerente : public ContaCorrente, public ContaInvestimento 10 { 11 public: 12 ContaGerente (int IDgerente, string data); 13 virtual ~ContaGerente(); 14 double getSaldoTotal(); 15 int getIDGerente(); 16 17 private: 18 double saldoTotal; 19 int IDGerente; 20 string data; 21 }; Como declarar a herança múltipla 23 Incluir a definição das superclasses A vírgula marca a separação entre os nomes das superclasses-mãe As demais definições - public e private – se referem às definições normais de uma classe e são feitas como em qualquer outra classe. EX03 Como declarar os construtores das superclasses ! Declaração normal dos construtores das superclasses ! As duas superclasses-mãe foram construídas de forma similar. Elas irão diferir em alguns pontos; por exemplo, ContaInvestimento tem rendimento, mas nesse contexto essas operações não serão consideradas. 24 7 ContaCorrente::ContaCorrente (int numero) { 8 this->numeroCC = numero; 9 this->saldo = 0; 10 } 7 ContaInvestimento::ContaInvestimento (int numero) { 8 this->numeroCI = numero; 9 this->saldo = 0; 10 } EX03 Como declarar o construtor da classe- filha 25 7 ContaGerente::ContaGerente(int IdGerente, string data): ContaCorrente (9990), ContaInvestimento(9991) 8 { 9 this->IDGerente = IdGerente; 10 this->data = data; 11 } A virgula separa as chamadas dos construtores das superclasses Observação: optou-se por construir, a título de exemplo, um construtor bem simples, que define ele próprio os números que são atribuídos às superclasses, respectivamente: 9990 para a Conta Corrente e 9991 para a Conta Investimento. EX03 Utilização das superclasses 26 12 cout << "Teste da Conta Corrente" << endl; 13 ContaCorrente *cc = new ContaCorrente (9990); 14 cc->depositarCC (1000); 15 cout << (cc->retirarCC (150) ? "Ok" : "NOK") << endl; 16 cout << "Saldo da Conta Corrente numero " << 17 cc->getNumeroCC() << " = " << cc->getSaldoCC() << endl; 18 19 cout << "Teste da Conta Investimento" << endl; 20 ContaInvestimento *ci = new ContaInvestimento (9991); 21 ci->depositarCI (4000); 22 ci->transferirCIParaCC (cc, 300); 23 cout << "Saldo da Conta Corrente numero " << 24 cc->getNumeroCC() << " = " << cc->getSaldoCC() << endl; 25 cout << (ci->retirarCI (150) ? "Ok" : "NOK") << endl; 26 cout << "Saldo da Conta Investimento numero " << 27 ci->getNumeroCI() << " = " << ci->getSaldoCI() << endl; Main.exe EX03 Utilização das superclasses ! Na linha 13 é feita a instanciação de um objeto da classe Conta Corrente. O ponteiro “cc” aponta o novo objeto criado. Na linha 20 é instanciado um objeto da classe ContaInvestimento. O ponteiro “ci” identifica esse objeto. ! É feito, então, um depósito na Conta Corrente (linha 14) e em seguida uma retirada (linha 15). A seguir é exibido o número da conta e o saldo (linha 16). ! Para a Conta Investimento é feito um depósito na linha 21 e em seguida uma transferência para a conta corrente associada (linha 22). O número da conta e o saldo são exibidos (linhas 23 e 24). 27 Utilização das superclasses ! A saída abaixo mostra os resultados dessas operações. ! Observe-se que nesse exemplo foram criados dois objetos distintos (ponteiros “cc” e “ci”). 28 EX03 Utilização da subclasse 29 28 … 29 cout << "Teste da Conta Gerencial" << endl; 30 31 ContaGerente *cg = new ContaGerente ( 21, "04/06/2016"); 32 cg->depositarCC (1000); 33 cout << (cg->retirarCC (150) ? "Ok" : "NOK") << endl; 34 cout << "Saldo da Conta Corrente numero " << 35 cg->getNumeroCC() << " = " << cg->getSaldoCC() << endl; 36 37 cg->depositarCI (4000); 38 cg->transferirCIParaCC (cg, 300); 39 cout << (cg->retirarCI (150) ? "Ok" : "NOK") << endl; 40 cout << "Saldo da Conta Corrente numero " << 41 cg->getNumeroCC() << " = " << cg->getSaldoCC() << endl; 42 cout << "Saldo da Conta Investimento numero " << 43 cg->getNumeroCI() << " = " << cg->getSaldoCI() << endl; 44 cout << "Saldo Total = " << cg->getSaldoTotal() << endl; 45 … EX03 Utilização da subclasse ! A instância da Classe Gerente foi criada na linha 31. O ponteiro “cg” indica esse objeto. Note-se que esse objeto é composto por três partes: • uma parte relativa a Classe Gerente (transparência 23) e tem acesso a todas as suas operações; • uma parte relativa à Conta Corrente (transparência 21) e acessa todas essas operações ; • uma parte relativa à Conta Investimento (transparência 22), com acesso as suas operações. ! As operações descritas para os objetos apontados por “cc” e “ci” são repetidas nas linhas 32 a 44 e a saída é apresentada a seguir. 30 Utilização da subclasse ! O saldo total apresentado na última linha corresponde à soma dos saldos individuais de cada conta. ! A Conta Gerente se comporta como uma “macro conta”, formada por uma conta corrente e por uma conta de investimentos, por exemplo, uma caderneta de poupança. 31 EX03 Agenda 1. Classe abstrata 2. Herança múltipla 3. Atributos e métodos estáticos 32 Como instâncias ocupam a memória ! Cada instância de uma classe tem um valor específico para cada atributo • São diferentes entre as instâncias ! O código dos métodos é compartilhado • É o mesmo para todas as instâncias • Usam os valores dos atributos de cada instância Atributo 1 Atributo 2 Atributo 1 Atributo 2 Atributo 1 Atributo 2 Método 1 Método 2 33 Atributo estático ! Um atributo pode ser declarado como estático • (Ou atributo com escopo de classe) • Apenas um valor é criado para a classe ! Não é definido em cada instância • O atributo existe mesmo que não haja instâncias • Ele existe por toda a execução do programa 34 static double limiteDeSaque; número: 124 saldo: 700 conta1:ContaUniversitária número: 125 saldo: 500 conta2:ContaUniversitárianúmero: 126 saldo: 10000 conta3:ContaUniversitária Uso ! Permite compartilhar informações entre todas as instâncias de uma classe ! Exemplos de uso • Identificador sequencial • Contador de quantas instâncias a classe tem • Declaração de constantes (static const) • Informações comuns a todos os objetos 35 Atributo estático em C++ ! Declaração: static ! Na implementação deve-se atribuir o valor inicial 36 1 #include "ContaUniversitaria.h" 2 3 double ContaUniversitaria::limiteDeSaque = 0; … … 6 class ContaUniversitaria : public ContaCorrente { 7 public: 8 ContaUniversitaria (int numero); 9 virtual ~ContaUniversitaria(); 10 bool retirar (double valor); … 13 private: 14 static double limiteDeSaque; 15 }; Atributo estático EX01 EX01 Atributo estático em C++ ! Uso • <nome da classe>::<nome do atributo> ! Dentro da classe é possível omitir o <nome da classe> • (Mas pode ser confuso) • Exemplo 37 … 12 bool ContaUniversitaria::retirar (double valor) { 13 if (valor <= ContaUniversitaria::limiteDeSaque 14 && saldo >= valor) { 15 saldo -= valor; 16 return true; 17 } 18 19 return false; 20 } Acessando o limite EX01 Método estático ! Método que não é executado no contexto de um objeto específico • Não é preciso ter uma instância para chamar o método ! Exemplos de uso • Manipular atributos estáticos • Métodos de apoio ! Exemplo: arredondar um valor, embaralhar um vetor e imprimir um texto em um certo formato na saída 38 Método estático em C++ ! Declaração: static ! Implementação 39 … 6 class ContaUniversitaria : public ContaCorrente { 7 public: … 11 static double getLimiteDeSaque(); 12 static void setLimiteDeSaque (double limite); 13 private: 14 static double limiteDeSaque; 15 }; … 22 double ContaUniversitaria::getLimiteDeSaque() { 23 return ContaUniversitaria::limiteDeSaque; 24 } Não deve-se colocar o static na implementação EX01 EX01 Método estático em C++ ! Chamada de método estático • Usando a instância ! (Se confunde com método com escopo de objeto) • Usando o nome da classe (recomendado) 40 … 17 ContaUniversitaria* c = new ContaUniversitaria (1); 18 c->depositar (100); 19 ContaUniversitaria::setLimiteDeSaque (50); 20 c->setLimiteDeSaque (55); Formas possíveis EX01 Bibliografia Budd, T. An Introduction to Object-Oriented Programming. Addison-Wesley, 3rd ed. 2002. • Classe abstrata: Seção 8.5 • Herança múltipla: Capítulo 13 Savitch, W. C++ Absoluto. Pearson, 1st ed. 2003. • Atributos e métodos estáticos: Seção 7.2. 41
Compartilhar