•
Polimorfismo
Classes Bases Abstratas
Quando estamos programando, sempre falamos para o compilador
quais são
os tipos e quais os objetos
que estamos utilizando.
Mais as vezes, é preciso para os quais nós nunca precisaremos instanciar
um objeto, ou seja, uma classe abstrata.
Nenhuma classe abstrata pode ser instanciada, e ela é usada
pela herança
para prover classes bases.
Assim ela tbm é conhecida como classes básicas Abstratas.
Elas oferencem interfaces para implementação
Uma classe é tornada abstrata quando declaramos nela uma ou mais funções
virtuais PURAS.
Funções virtuais puras tem um inicializador
= 0
Exemplo:
virtual int somatorias() const = 0; // virtual pura
OBS:
Se na classe que deriva a classe abstrata não tiver nenhuma definição
para a função vitual pura, então
ela continua virtual pura, logo a classe derivada também é uma
classe abstrata.
Tentar instanciar um objeto que possue
função virtual pura é um
erro de sintaxe.
Polimorfismo
CARAS, C++ possibilita polimorfismo - A habilidade de objeto de classes diferentes
relacionados
por herança responderem diferentemente a MESMA mensagem!
O polimorfismo é implementado atraves de funções virtuais.
Quando esta função é chamada através
de um ponteiro ( ou referencia ) de uma classe básica, C++ escolhe a função
sobrecarregada correta da classe
derivada dinamicamente.
O Polimorfismo promove a extensibilidade> o software escrito
para invocar o comportamento polimórfico é escrito
independentemente dos tipos dos objetos para os quais as mensagens são
enviadas. Deste modo, novos tipos de
objetos que podem responder a mensagens existentes podem ser acrescentados a
um sistema como esse, sem modificar
o sistema básico.
Exemplo do livro Deitel para Aprendizado: pg 612 C++ como Programar
/*
employ.h
Deitel - C++ Como Programar
*/
#ifndef EMPLOY_H
#define EMPLOY_H
class Employee {
public:
Employee( const char *, const char * );
~Employee();
const char *getFirstName() const;
const char *getLastName() const;
// Função
virtual pura torna Employee uma classe base abstrata
virtual double earnings() const = 0; // virtual pura
// virtual
virtual void print() const;
private:
char *firstName;
char *lastName;
};
#endif
#include <iostream>
using std::cout;
/*
employ.cpp
Deitel - C++ Como Programar
*/
#include <cstring>
#include <cassert>
#include "employ.h"
Employee::Employee( const char *first, const char *last )
{
this->firstName = new char[ strlen(first) + 1 ];
assert( this->firstName != 0 );
strcpy( this->firstName, first );
this->lastName = new char[ strlen(last) + 1 ];
assert( this->lastName != 0 );
strcpy( this->lastName, last );
}
Employee::~Employee()
{
delete [] this->firstName;
delete [] this->lastName;
}
// chamador deve copiar a string
const char *Employee::getFirstName() const
{
return this->firstName;
}
const char *Employee::getLastName() const
{
return this->lastName;
}
// imprime o nome
void Employee::print() const
{
cout << this->firstName << " " << this->lastName;
}
/*
boss.h
Deitel - C++ Como Programar
*/
#ifndef BOSS_H
#define BOSS_H
#include "employ.h"
class Boss : public Employee {
public:
Boss( const char *, const char *, double = 0.0 );
void setWeeklySalary( double );
virtual double earnings() const;
virtual void print() const;
private:
double weeklySalary;
};
#endif
/*
boss.cpp
Deitel - C++ Como Programar
*/
#include <iostream>
using std::cout;
#include "boss.h"
Boss::Boss( const char *first, const char *last, double s )
: Employee( first, last )
{
this->setWeeklySalary( s );
}
void Boss::setWeeklySalary( double s )
{
this->weeklySalary = ( s > 0 ? s : 0 );
}
double Boss::earnings() const
{
return this->weeklySalary;
}
// chama função de employee, não
polimorfica, mais tenho que criar
void Boss::print() const
{
cout << "\n Chefe: ";
Employee::print();
}
/*
commis.h
Deitel - C++ Como Programar
*/
#ifndef COMMIS_H
#define COMMIS_H
#include "employ.h"
class CommissionWorker : public Employee {
public:
CommissionWorker( const char *, const char *, double = 0.0, double = 0.0, int
= 0 );
void setSalary( double );
void setCommission( double );
void setQuantity( int );
virtual double earnings() const;
virtual void print() const;
private:
double salary;
double commission;
int quantity;
};
#endif
/*
commis.cpp
Deitel - C++ Como Programar
*/
#include <iostream>
using std::cout;
#include "commis.h"
CommissionWorker::CommissionWorker( const char *first, const char *last,
double s, double c, int q )
: Employee( first, last )
{
this->setSalary( s );
this->setCommission( c );
this->setQuantity( q );
}
void CommissionWorker::setSalary( double s )
{
this->salary = ( s > 0 ? s : 0 );
}
void CommissionWorker::setCommission( double c )
{
this->commission = ( c > 0 ? c : 0 );
}
void CommissionWorker::setQuantity( int q )
{
this->quantity = ( q > 0 ? q : 0 );
}
double CommissionWorker::earnings() const
{
return this->salary + this->commission * this->quantity;
}
// chama função de employee, não
polimorfica, mais tenho que criar
void CommissionWorker::print() const
{
cout << "\n Comissionado: ";
Employee::print();
}
/*
hourly.h
Deitel - C++ Como Programar
*/
#ifndef HOURLY_H
#define HOURLY_H
#include "employ.h"
class HourlyWorker : public Employee {
public:
HourlyWorker( const char *, const char *, double = 0.0, double = 0.0 );
void setWage( double );
void setHours( double );
virtual double earnings() const;
virtual void print() const;
private:
double wage;
double hours;
};
#endif
/*
hourly.cpp
Deitel - C++ Como Programar
*/
#include <iostream>
using std::cout;
#include "hourly.h"
HourlyWorker::HourlyWorker( const char *first, const char *last,
double w, double h )
: Employee( first, last )
{
this->setWage( w );
this->setHours( h );
}
void HourlyWorker::setWage( double w )
{
this->wage = ( w > 0 ? w : 0 );
}
void HourlyWorker::setHours( double h )
{
this->hours = ( h >= 0 && h < 168 ? h : 0 );
}
double HourlyWorker::earnings() const
{
if ( this->hours <= 40 )
return this->wage * this->hours;
else
return 40 * this->wage + ( this->hours - 40 ) * this->wage * 1.5;
}
// chama função de employee, não
polimorfica, mais tenho que criar
void HourlyWorker::print() const
{
cout << "\n HourlyWorker: ";
Employee::print();
}
/*
piece.h
Deitel - C++ Como Programar
*/
#ifndef PIECE_H
#define PIECE_H
#include "employ.h"
class PieceWorker : public Employee {
public:
PieceWorker( const char *, const char *, double = 0.0, int = 0 );
void setWage( double );
void setQuantity( int );
virtual double earnings() const;
virtual void print() const;
private:
double wagePerPiece;
int quantity;
};
#endif
/*
piece.cpp
Deitel - C++ Como Programar
*/
#include <iostream>
using std::cout;
#include "piece.h"
PieceWorker::PieceWorker( const char *first, const char *last,
double w, int q )
: Employee( first, last )
{
this->setWage( w );
this->setQuantity( q );
}
void PieceWorker::setWage( double w )
{
this->wagePerPiece = ( w > 0 ? w : 0 );
}
void PieceWorker::setQuantity( int q )
{
this->quantity = ( q > 0 ? q : 0 );
}
double PieceWorker::earnings() const
{
return this->quantity * this->wagePerPiece;
}
// chama função de employee, não
polimorfica, mais tenho que criar
void PieceWorker::print() const
{
cout << "\n Piece Worker: ";
Employee::print();
}
/*
main.cpp // principal
Deitel - C++ Como Programar
*/
#include <iostream>
using std::cout;
using std::endl;
#include <iomanip>
using std::ios;
using std::setiosflags;
using std::setprecision;
#include "employ.h"
#include "boss.h"
#include "commis.h"
#include "piece.h"
#include "hourly.h"
void virtualViaPointer( const Employee * );
void virtualViaReference( const Employee & );
int main()
{
cout << setiosflags( ios::fixed | ios::showpoint )
<< setprecision( 2 );
Boss b( "José", "Silva",
800.00 );
b.print();
cout << " recebeu & " << b.earnings();
virtualViaPointer( &b );
virtualViaReference( b );
CommissionWorker c( "Simone", "Bianchi",
200.0, 3.0, 150 );
c.print();
cout << " recebeu & " << c.earnings();
virtualViaPointer( &c );
virtualViaReference( c );
PieceWorker p( "Roberto", "Santos",
2.5, 200 );
p.print();
cout << " recebeu & " << p.earnings();
virtualViaPointer( &p );
virtualViaReference( p );
HourlyWorker h( "Carmem", "Diego",
13.75, 40 );
h.print();
cout << " recebeu & " << h.earnings();
virtualViaPointer( &h );
virtualViaReference( h );
cout << endl;
system("pause");
return 0;
}
// usando vinculação dinamica
( polimorfismo )
void virtualViaPointer( const Employee *baseClassPtr )
{
baseClassPtr->print();
cout << " recebeu $ " << baseClassPtr->earnings();
}
// usando vinculação dinamica
( polimorfismo )
void virtualViaReference( const Employee &baseClassref )
{
baseClassref.print();
cout << " recebeu $ " << baseClassref.earnings();
}
!!!!!!!!! FIM !!!!!!!!!!!
Eu sei que fica um pouco complicado de ler este codigo todo aqui.
Por isso cole em um compilador.. Tente compilar.
Analisando o código, vc vai perceber que, as funções
earnings e print
são virtuais e são sempre sobresescrito.
Sendo que earnings é polimorfico, quando chamamos a função
virtualViaPointer
ele recebe um objeto qualquer e ele sabe qual earnings vai executar, mesmo ele
não sabendo o tipo
do objeto passado
- Destruidores Virtual
O Polimorfismo e funções virtuais funcionam bem quando todas
as classes possíveis não são conhecidas com antecedência.
Mas eles também funcionam quando novos tipos de classes são acrescentados
aos sistemas. Novas classes são
acomodadas pela vinculação dinâmica ( ou vinculação
tardia ). O tipo de um objeto não precisa ser conhecido durante
a compilação para a chamada de uma função virtual;
Pode acontecer um problema quando usamos polimorfismo para
processar objetos alocados dinamicamente de
uma hierarquia de classes. Se um objeto é explicitamente destruído
com o operador delete a um ponteiro da
classe base para o objeto, a função destruidor da classe base é chamada
para o objeto. Isto acontece não
importando o tipo do objeto para o qual o ponteiro da classe base aponta e independente
do fato que cada
destruidor de classe ter um nome diferente.
Para que este problema não aconteça, você deve
declarar um destruidor virtual para a classe base.
Isso faz com o que os destruidores das classes derivadas sejem virtual e C++
conseguirá destrui-los corretamente.
OU seja, se a classe qualquer possui
funções virtual, faça
também um destruidor virtual para evitar problemas.
Não se esqueça, construtores não pode ser virtual.
|