AULA 10 - Programação II - Graduação

De IFSC
Revisão de 13h09min de 18 de abril de 2018 por imported>Fargoud (→‎HERANÇA)
Ir para navegação Ir para pesquisar

HERANÇA

Herança é um dos pontos chave de programação orientada a objetos (POO).

Ela fornece meios de promover a extensibilidade do código, a reutilização e uma maior coerência lógica no modelo de implementação.

Estas características nos possibilitam diversas vantagens, principalmente quando o mantemos bibliotecas para uso futuro de determinados recursos que usamos com muita frequência.

Uma classe de objetos "veiculo", por exemplo, contém todas as características inerentes aos veículos, como:

  • combustível,
  • autonomia,
  • velocidade máxima,
  • etc.

Agora podemos dizer que "carro" é uma classe que têm as características básicas da classe "veículo" mais as suas características particulares.

Analisando esse fato, podemos concluir que poderíamos apenas definir em "carro" suas características e usar "veículo" de alguma forma que pudéssemos lidar com as características básicas. Este meio chama-se herança.

Agora podemos definir outros tipos de veículos como:

  • moto,
  • caminhão,
  • trator,
  • helicóptero,
  • etc,

sem ter que reescrever a parte que está na classe "veículo". Para isso define-se a classe "veículo" com suas características e depois cria-se classes específicas para cada veículo em particular, declarando-se o parentesco neste instante.

Exemplo:

Imagine que já exista uma classe que defina o comportamento de um dado objeto da vida real, por exemplo, animal. Uma vez que eu sei que o leão é um animal, o que se deve fazer é aproveitar a classe animal e fazer com que a classe leão derive (herde) da classe animal as características e comportamentos que a mesma deve apresentar, que são próprios dos indivíduos classificados como animais.


PRGheranca1.png

Ou seja, herança acontece quando duas classes são próximas, têm características mútuas mas não são iguais e existe uma especificação de uma delas.

Portanto, em vez de escrever todo o código novamente é possível poupar algum tempo e dizer que uma classe herda da outra e depois basta escrever o código para a especificação dos pontos necessários da classe derivada (classe que herdou).


Através da herança, cria-se novas classes, chamadas de SUB-CLASSES ou CLASSES DERIVADAS, baseadas em uma classe já existente, chamada de SUPER-CLASSE ou CLASSE-BASE.

A classe derivada “herda” todas as características da classe-base, além de poder incluir suas características próprias.

Em resumo, o maior objetivo do uso do mecanismo de herança é a REUTILIZAÇÃO DE CÓDIGO, para facilitar o desenvolvimento e também para criação de BIBLIOTECAS.

É preciso ter o arquivo de código-objeto da super-classe (não o arquivo-fonte).


Sintaxe:

Para declarar uma classe derivada de outra já existente, procedemos de forma a declarar o parentesco e o grau de visibilidade (acesso) que a classe derivada terá dos membros de sua classe base.

Para isso seguimos o seguinte código sintático:


class NomeSubclasse: [Modificador de acesso] NomeSuperclasse
{  ...  
   //Características próprias da subclasse  
   ...
};

Repare que temos o operador ":" ( dois pontos ) como elo entre as duas classes. Este operador promove o "parentesco" entre as duas classes quando é usado na declaração de uma classe derivada.

O termo [Modificador de acesso] é opcional, mas se estiver presente deve ser public, private ou protected. Por "defaut" (padrão) temos o private, ou seja, se o modificador não estiver presente, o compilador usará "private" durante a interpretação do código.

Ele define o grau de visibilidade dos membros da classe base quando a classe derivada precisar acessá-los.

Exemplo:

PRGex1heranca.png

Na implementação acima temos a classe base veiculo_rodoviario e duas classes derivadas “:” caminhao e automovel.

Podemos notar que as características comuns a todos os tipos de veículos, rodas e passageiros, estão na classe base, enquanto as características exclusivas de cada tipo de veículo estão nas classes derivadas.

Desta forma podemos definir procedimentos especializados para cada classe, fazendo com que todas as eventuais modificações feitas ao longo da implementação na classe base sejam estendidas a todos os objetos criados a partir das classes derivadas no programa.


Repare ainda um pormenor: tanto a classe "caminhao" quanto a automovel têm como função membro o método mostrar(), mas uma não interfere com a outra. Isto ilustra um outro aspecto da orientação a objeto, o polimorfismo. Este será exposto em mais detalhe nos capítulos subsequentes.

Também no Visual C++ utilizamos herança. Na verdade, o próprio aplicativo utiliza herança para gerar os controles dos projetos visuais. Por exemplo, quando criamos um novo projeto no VC++, um formulário da classe Form1 é criado.

Esta classe é, na verdade, uma herança da classe mais geral Form:

class Form1 : public Form
{       
  ...
};

Implementação da classe derivada:

Existem algumas particularidades na implementação de uma subclasse:

Construtor da classe derivada

Pode utilizar o construtor da classe base. Exs:

class Quadrado : public Retangulo
{    public:
     Quadrado() :  Retangulo() { ...}
     Quadrado(int x1, int y1, int x2, int y2) : Retangulo(x1, y1, x2, y2) {...}
     ...   
};
class Quadrado : public Retangulo
{    public:
     Quadrado(int x1, int x2, int y1, int y2) 
    { 
            if(abs(x2 – x1) == abs(y2 – y1))
                Retangulo::Retangulo(x1, y1, x2, y2);
            else  
                 ShowMessage(“Coordenadas inválidas para quadrado”);
     ...  
};

Métodos da classe derivada também podem chamar métodos (públicos ou protegidos) da classe base usando a sintaxe

Classe_base::Método_classe_base( ); 

Se a classe derivada não possuir construtor – construtor da classe base é chamado.

Se este construtor da classe base não for default, ou não possuir valores default e não forem passados argumentos ⇒ ERRO!

Além de herança simples, uma classe pode ser derivada de mais de uma classe base ⇒ Herança múltipla!


Um método na classe derivada pode sobrecarregar um método da classe base : redefinir usando mesmo nome! Ex:

class Quadrado : public Retangulo
{    public:  // Métodos da classe base sobrecarregados na derivada:
        long int Calcula_Area( );
        long int Calcula_Perimetro( );
   ...
};
long int Quadrado::Calcula_Area( )
{   return(base*base);  }
long int Quadrado::Calcula_Perimetro()
{   return(4*base);       }

ESPECIFICADOR DE ACESSO PROTECTED:

As classes derivadas não têm acesso aos membros privados da classe base.

Para que as subclasses possam alterar atributos da superclasse, sem torná-los públicos: definí-los como protected.


Exemplo:

class Base { 	
       public: int publico; 
       private: int privado;
       protected: int protegido; 
};
class Derivada : public Base
{ public: int a, b, c;
  Derivada( ) {
           a = publico;   // Ok!
           b = protegido;   //Ok!
           c = privado; }   // ERRO! 
};  
PRGheranca.png
PRGherancaex2.png

EXERCÍCIO:

A partir da classe Pessoa derive as classes:

  • Cliente - com o atributo particular CPF e o método privado ValidaCPF()*, e com os métodos de inicialização e atualização destes atributos;
  • Empregado - com os atributos particulares IdEmpresa, TotalVendas e Salario, os métodos de inicialização e atualização destes atributos, além de um método privado CalculaComissao( ).


* Número de inscrição no CPF

O número de inscrição no CPF é composto de onze dígitos decimais, sendo os oito primeiros aleatoriamente designados no momento da inscrição.

Já o nono (antepenúltimo) dígito indica a região fiscal responsável pela inscrição.

Por fim, o décimo e o décimo-primeiro são dígitos verificadores calculados de acordo com um algoritmo definido pela Receita Federal e publicamente conhecido.

Seja o código do CPF formado por

cpf[8] cpf[7] cpf[6] . cpf[5] cpf[4] cpf[3] . cpf[2] cpf[1] cpf[0] - v1 v2

A computação da expressão acima para o cálculo dos dígitos verificadores podem ser escritas de forma algorítmica tendo como base o seguinte pseudocódigo:

variáveis
 cpf[0..8]  vetor de Inteiros; 
 v1, v2: Inteiro;
início
 # popula a variável 'cpf' de forma inversa (o menor índice deve conter o dígito mais à direita do CPF)
 # ...
 para i := 0 até tamanho(cpf)-1 faça
   v1 := v1 + cpf[i] * (9 - (i mod 10));
   v2 := v2 + cpf[i] * (9 - ((i + 1) mod 10));
 fim-para
 v1 := (v1 mod 11) mod 10;
 v2 := v2 + v1 * 9;
 v2 := (v2 mod 11) mod 10;
 escreva(v1);
 escreva(v2);
fim.

Regiões fiscais brasileiras, indicadas pelo cpf[0]:

O terceiro dígito da direita para a esquerda identifica a unidade federativa na qual a pessoa foi registrada:

No exemplo CPF nº 000.000.00X-00

  • 0 - Rio Grande do Sul
  • 1 - Distrito Federal, Goiás, Mato Grosso do Sul e Tocantins
  • 2 - Pará, Amazonas, Acre, Amapá, Rondônia e Roraima
  • 3 - Ceará, Maranhão e Piauí
  • 4 - Pernambuco, Rio Grande do Norte, Paraíba e Alagoas
  • 5 - Bahia e Sergipe
  • 6 - Minas Gerais
  • 7 - Rio de Janeiro e Espírito Santo
  • 8 - São Paulo
  • 9 - Paraná e Santa Catarina

Mais informações:

  O código CPF - Wikipedia
e Valida Códigos