C++ - Herança
Herança é o processo pelo qual criamos novas classes, chamadas classes derivadas, baseadas em classes existentes ou classes-base.
A classe derivada herda todas as características da classe-base, além de incluir características próprias adicionais.
Vantagem : reutilização de código, permitindo uso de bibliotecas de classes criadas por outras pessoas.
Derivando classes : Através de exemplos #include <iostream.h>
#include <string.h> const TAM = 80;
class BasAg // classe base { protected :
char nome[TAM]; char numag[4]; public :
BasAg( ) { nome[0] = ‘\0’; numag[0] = ‘\0’;} // construtores BasAg( char n[ ], char ng[ ] )
{ if ( strlen(n) < TAM ) strcpy(nome, n);
if ( strlen(ng) < TAM ) strcpy(numag, ng); } void print( )
{ cout << “\nDados do Agente : “; cout << “\n ---“; cout << “\nNome : “ << nome;
cout << “\nNumero : “ << numag; } } ;
class Agente : public BasAg // classe derivada { protected:
float altura; int idade; public :
Agente() : BasAg() // chama construtor da classe base { altura = idade =0; }
Agente (char n[], char ng[], float a, int i) : BasAg (n, ng) { altura = a; idade = i; }
void print( ) // mesmo nome da função membro de BasAg {
BasAg::print(); // chama print() da classe base cout << "\nAltura : " << altura;
cout << "\nIdade : " << idade; }
} ;
void main( ) {
Agente agente("James Bond", "007", 90, 40); agente.print();
}
Observ. :
• Se duas funções de mesmo nome existem, uma na classe base e outra na classe derivada, a função da classe derivada será executada se for chamada por meio de um objeto da classe derivada.
• Se um objeto da classe-base é criado, usará sempre funções da própria classe-base pois não conhece nada da classe derivada.
• Membros protected são visíveis a todos os membros de uma classe derivada. Sempre que escrevermos uma classe que pode vir a ser uma classe-base de outras classes, devemos declarar como protected os membros privados necessários às classes derivadas.
Herança pública e privada : Acesso público, privado e protegido à classe-base através de membros e objetos da classe derivada, na derivação pública e privada.
class BASE {
protected : int secreto;
private : int ultra_secreto; public : int publico;
} ;
class DERIV1 : public BASE {
int a = secreto; // Ok
int b = ultra_secreto; // Erro : não acessível int c = publico; // Ok
} ;
class DERIV2 : private BASE {
int a = secreto; // Ok
int b = ultra_secreto; // Erro : não acessível int c = publico; // Ok
} ; main( ) {
int x;
DERIV1 obj1; // DERIV1 é public
x = obj1.a; // Erro : não acessível x = obj1.b; // Erro : não acessível x = obj1.c; // Ok
DERIV2 obj2; // DERIV2 é private x = obj2.a; // Erro : não acessível x = obj2.b; // Erro : não acessível x = obj2.c; // Erro : não acessível }
Conta
Simples Especial Poupança Prêmio #include <iostream.h> #include <stdio.h> #include <iomanip.h> const TAM = 80; class conta { private :
char nome[TAM]; // nome do cliente int nconta; // número da conta float saldo; // saldo bancário public :
void getdata( )
{ cout << “\nNome : “; gets(nome);
cout << “\nNum. Conta : “; cin >> nconta; cout << “\nSaldo : “; cin >> saldo;
}
void putdata( )
{ cout << “\nNome : “ << nome;
cout << “\nNum. Conta : “ << nconta; cout << “\nSaldo : “
<< setiosflags(ios::fixed) << setprecision(2) << saldo; }
float Saldo( ) {return saldo;} } ;
class contaSimples : public conta { } ; class contaEspecial : public conta { private :
float limite; public :
void getdata( )
{ conta :: getdata( ); // chama getdata() da classe-base cout << “\nLimite : “; cin >> limite;
}
void putdata( )
{ conta :: putdata( ) // chama putdata() da classe-base cout << “\nLimite : “ << limite;
cout << “\nSaldo Total : “ << setiosflags(ios::fixed)
<< setprecision(2) << (Saldo() + limite); }
} ;
class Poupanca : public conta { private :
float taxa; public :
void getdata( )
{ conta :: getdata( ); // chama getdata() da classe-base cout << “\nTaxa : “; cin >> taxa;
}
void putdata( )
{ conta :: putdata( ) // chama putdata() da classe-base cout << “\nTaxa : “ << limite;
cout << “\nSaldo Total : “ << setiosflags(ios::fixed)
<< setprecision(2) << (Saldo() + limite); }
} ;
class contaPremio : public Poupanca { private :
char prem[TAM]; public :
void getdata( )
{ Poupanca :: getdata( ); // chama getdata() da classe-base cout << “\nPremio : “; gets(prem);
}
void putdata( ) {
Poupanca :: putdata( ) // chama putdata() da classe-base cout << “\nPremio : “ << prem;
} } ; void main( ) { conta Simples c1; contaEspecial c2; Poupanca c3; contaPremio c4;
cout << “\nDigite os dados da conta simples : “; c1.getdata(); cout << “\nDigite os dados da conta especial : “; c2.getdata();
cout << “\nDigite os dados da conta poupança : “; c3.getdata(); cout << “\nDigite os dados da conta prêmio : “; c4.getdata(); cout << “\n\n* Conta Simples : “; c1.putdata();
cout << “\n\n* Conta Especial : “; c2.putdata(); cout << “\n\n* Conta Poupança : “; c3.putdata(); cout << “\n\n* Conta Prêmio : “; c4.putdata(); }
Observ. : Nenhum objeto da classe conta foi declarado. Ela foi usada como uma classe genérica, com o único propósito de agir como base para outras classes. Neste caso a classe é chamada abstrata.
Conversões de tipos entre classe-base e classe derivada : conta C;
contaEspecial CE; CE.getdata();
C = CE; // converte contaEspecial em conta CE = C; // Erro, não pode ser convertido
Herança múltipla : uma classe pode herdar as características de mais de uma classe-base. Este processo é chamado herança múltipla.
Ex. : Imóveis de uma imobiliária (para venda e para aluguel )
Tipo : comercial, residencial, etc. Já dispõe de um cadastro de clientes. Venda
Cadastro Imóvel Tipo Aluguel #include <iostream.h> #include <stdio.h> #include <iomanip.h> #include <string.h> class Cadastro { private :
char nome[30], fone [20]; public :
Cadastro () {nome[0]= fone[0]='\0';} // construtores Cadastro (char n[], char f[])
{ strcpy (nome, n);
strcpy (fone, f); } void getdata()
{ cout << "\n\tNome : ";gets(nome); cout << "\tFone : ";gets(fone); } void putdata()
{ cout << "\n\tNome : " << nome; cout << "\n\tFone : " << fone; } } ;
class Imovel {
private :
char end[30], bairro[20]; float AreaUtil, AreaTotal; int quartos;
public :
Imovel () // construtores { end[0] = bairro[0] = '\0';
AreaUtil = AreaTotal = 0.0;
quartos = 0; }
Imovel (char e[], char b[], float au, float at, int q) { strcpy (end, e);
strcpy (bairro, b);
AreaUtil = au; AreaTotal = at; quartos = q; } void getdata()
{
cout << "\n\tEnd.: "; gets(end); cout << "\tBairro : "; gets(bairro); cout << "\tArea util : ";cin >> AreaUtil; cout << "\tArea Total : ";cin >> AreaTotal; cout << "\tNo. quartos : ";cin >> quartos; } void putdata()
{
cout << "\n\tEnd.: " << end; cout << "\n\tBairro : " << bairro; cout << "\n\tArea util : "
<< setiosflags(ios::fixed)
<< setprecision(2) << AreaUtil; cout << "\n\tArea Total : "
<< setiosflags(ios::fixed)
<< setprecision(2) << AreaTotal; cout << "\n\tQuartos : " << quartos; } } ; class Tipo { private : char tipo[20]; public :
Tipo() {tipo[0]='\0';} // construtores Tipo (char t[]) {strcpy (tipo, t) ; }
void getdata()
{ cout << "\n\tTipo: ";gets(tipo); } void putdata()
{ cout << "\n\tTipo: " << tipo; } } ;
class Venda : private Cadastro, Imovel, Tipo {
private :
float valor; public :
Venda() : Cadastro(), Imovel(), Tipo() {valor = 0.0; } Venda (char n[],char f[], char e[], char b[], float au, float at, int q, char t[], float v) : Cadastro(n,f), Imovel(e, b, au, at, q), Tipo(t) {valor = v; }
void getdata() {
cout << "\n...Proprietario : "; Cadastro::getdata(); cout << "\n...Imovel : "; Imovel::getdata(); Tipo::getdata(); cout << "\tValor : "; cin >> valor;
} void putdata() {
cout << "\n...Proprietario : "; Cadastro::putdata();
cout << "\n...Imovel : "; Imovel::putdata(); Tipo::putdata();
cout << "\n\tValor : " << valor; } } ;
class Aluguel : private Cadastro, Imovel, Tipo { private : float aluguel; int prazo; Cadastro proprietario; public :
Aluguel() : Cadastro(), Imovel(), Tipo() { aluguel = 0.0; prazo = 0; }
Aluguel (char n[], char f[], char e[], char b[], float au, float at, int q, char t[], float a, int p) : Cadastro(n,f),
Imovel (e, b, au, at, q), Tipo(t) { aluguel = a; prazo = p; } void getdata()
{
cout << "\n...Proprietario : "; proprietario.getdata(); cout << "\n...Inquilino : "; Cadastro::getdata();
cout << "\n...Imovel : "; Imovel::getdata(); Tipo::getdata(); cout << "\tAluguel : "; cin >> aluguel;
cout << "\tPrazo do contrato : "; cin >> prazo; }
void putdata() {
cout << "\n...Proprietario : "; proprietario.putdata(); cout << "\n...Inquilino : "; Cadastro::putdata();
cout << "\n...Imovel : "; Imovel::putdata(); Tipo::putdata(); cout << "\n\tAluguel : " << aluguel;
cout << "\n\tPrazo de contrato : " << prazo; } } ; void main() { Venda v1; Aluguel a1;
cout << "\nDigite os dados do imovel : Venda "; v1.getdata(); cout << "\nDigite os dados do imovel : Aluguel "; a1.getdata(); cout << "\n\n* Imovel para venda * "; v1.putdata();
cout << "\n\n* Imovel para aluguel * "; a1.putdata(); }
Objetos de uma classe como membro de outra classe : Na classe Aluguel declaramos um objeto proprietario da classe Cadastro. Os membros deste objeto são acessados internamente por meio do operador ponto.
Ambigüidade em herança múltipla : Veja o exemplo a seguir: class X
{
public :
void print() { cout << “\nClasse X”; } } ;
class Y {
public :
void print() { cout << “\nClasse Y”; } // mesmo nome } ;
class Z : public X, Y // derivada de X e Y
{ } ; // não tem função com nome print() void main( )
{ Z obj;
obj.print(); // ambigüidade . Erro do compilador obj.X::print(); // Ok, usa o print() da classe X obj.Y::print(); // Ok, usa o print() da classe Y }
Assunto : Herança
Prática VIII
• Imagine que você deva escrever um programa para armazenar veículos. Primeiramente, crie a classe Motor que contém NumCilindro (int) e Potência (int), Inclua um construtor sem argumentos que inicialize os dados com zeros e um construtor que inicialize os dados com os valores
recebidos como argumento. Acrescente uma função para entrada de dados, getdata(), e outra que imprima os dados, putdata().
• Escreva a classe Veículo contendo Peso em quilos (int), VelocMac em Km/h (int) e Preço em R$ (float). Inclua um construtor sem argumentos que inicialize os dados com zeros e um construtor que inicialize os dados com os valores recebidos como argumento. Acrescente uma função para entrada de dados, getdata(), e outra que imprima os dados, putdata().
• Crie a classe CarroPasseio usando as classes Motor e Veículo como base. Inclua Cor (string) e Modelo (string). Inclua um construtor sem argumentos que inicialize os dados com zeros e um construtor que inicialize os dados com os valores recebidos como argumento. Acrescente uma função para entrada de dados, getdata(), e outra que imprima os dados, putdata().
• Crie a classe Caminhão derivada das classes Motor e Veículo. Inclua Toneladas (carga máxima), AlturaMax (int) e Comprimento (int). Inclua um construtor sem argumentos que inicialize os dados com zeros e um construtor que inicialize os dados com os valores recebidos como argumento. Acrescente uma função para entrada de dados, getdata(), e outra que imprima os dados, putdata().