PDA

View Full Version : Polimorfismo



usuarioforum
03-01-2019, 05:28 PM
Polimorfismo é uma oportunidade para diferentes classes de objetos, relacionadas através de herança, de responder de várias formas quando o mesmo elemento de função for chamado. Isso ajuda a criar um mecanismo universal descrevendo o comportamento não apenas da classe base, mas também das classes descendentes.

Vamos continuar a desenvolver uma classe base CShape, e definir uma função membro GetArea(), destinado a calcular a área de uma forma. Em todas as classes descendentes, produzidas por herança a partir da classe base, nós redefinimos esta função de acordo com as regras de cálculo de área de uma forma (shape) particular.

Para um quadrado (classe CSquare), a área é calculada através de seu lado, para um círculo (classe CCircle), a área é expressa através de seu raio, etc. Nós podemos criar um array para armazenas objetos do tipo CShape, no qual tanto objetos da classe base como todos os objetos de classes descendentes podem ser armazenados. Mais adiante, podemos chamar a mesma função para cada elemento do array.

Exemplo:

//--- Classe Base
class CShape
{
protected:
int m_type; // tipo da forma
int m_xpos; // X - coordenada do ponto base
int m_ypos; // Y - coordenada do ponto de base
public:
void CShape(){m_type=0;}; // construtor, tipo=0
int GetType(){return(m_type);};// retorna o tipo da forma
virtual
double GetArea(){return (0); }// retorna a área da forma
};

Agora, todas as classes derivadas têm uma função membro getArea(), que retorna o valor zero. A implementação desta função em cada descendente não será a mesma.

//--- A classe derivada Circle
class CCircle : public CShape // Depois do dois pontos definimos a classe base
{ // a partir do qual a herança é feita
private:
double m_radius; // raio do círculo

public:
void CCircle(){m_type=1;}; // construtor, tipo=1
void SetRadius(double r){m_radius=r;};
virtual double GetArea(){return (3.14*m_radius*m_radius);}// área do círculo
};

Para a classe Square, a declaração é a mesma:

//--- A classe derivada Square
class CSquare : public CShape // Depois do dois pontos definimos a classe base
{ // a partir do qual a herança é feita
private:
double m_square_side; // lado do quadrado

public:
void CSquare(){m_type=2;}; // construtor, tipo=2
void SetSide(double s){m_square_side=s;};
virtual double GetArea(){return (m_square_side*m_square_side);}// área quadrada
};

Para calcular a área do quadrado e círculo, precisamos dos correspondentes valores de m_radius e m_square_side, por isso nós adicionamos as funções SetRadius() e SetSide() na declaração da correspondente classe.

Assumimos que objetos de diferentes tipos (CCircle e CSquare) derivados do tipo base CShape são usados em nosso programa. Polimorfismo permite criar um array de objetos da classe base CShape, mas ao declarar este array, estes objetos são desconhecidos e o tipo deles é indefinido.

A decisão sobre que tipo de objeto estará contido em cada elemento do array será tomada diretamente durante a execução do programa. Isso envolve a criação dinâmica de objetos das classes apropriadas, e portanto a necessidade do uso de ponteiros de objeto ao invés de objetos.

O operador new é usado para criação dinâmica de objetos. Cada um destes objetos devem ser individualmente e explicitamente excluídos usando o operador delete. Portanto declararemos um array de ponteiros do tipo CShape, e criaremos um objeto de um tipo apropriado para cada elemento (new Class_Name), como mostrado no exemplo de script seguinte:

//+------------------------------------------------------------------+
//| Programa Script da função start (iniciar) |
//+------------------------------------------------------------------+
void OnStart()
{
//--- Declararmos um array de ponteiros de objeto do tipo base
CShape *shapes[5]; // Um array de ponteiros para objetos CShape

//--- Aqui preenchemos o array com objetos derivados
//--- Declaramos um ponteiro para o objeto de tipo CCircle
CCircle *circle=new CCircle();
//--- Definimos propriedades do objeto usando o ponteiro do círculo
circle.SetRadius(2.5);
//--- Colocamos o valor do ponteiro em shapes[0]
shapes[0]=circle;

//--- Criamos um outro objeto CCircle e escrevemos seu ponteiro em shapes[1]
circle=new CCircle();
shapes[1]=circle;
circle.SetRadius(5);

//--- Aqui nós intencionalmente "esquecemos" de definir um valor para shapes[2]
//circle=new CCircle();
//circle.SetRadius(10);
//shapes[2]=circle;

//--- Definimos NULL para o elemento que não é usado
shapes[2]=NULL;

//--- Criamos um objeto CSquare e escrevemos seu ponteiro em shapes[3]
CSquare *square=new CSquare();
square.SetSide(5);
shapes[3]=square;

//--- Criamos um objeto CSquare e escrevemos seu ponteiro em shapes[4]
square=new CSquare();
square.SetSide(10);
shapes[4]=square;

//--- Temos um array de ponteiros, obtemos seu tamanho
int total=ArraySize(shapes);
//--- Passamos em um loop através de todos os ponteiros no array
for(int i=0; i<5;i++)
{
//--- Se o ponteiro no índice especificado é válido
if(CheckPointer(shapes[i])!=POINTER_INVALID)
{
//--- Imprimi o tipo e área da forma
PrintFormat("O objeto do tipo %d tem a área %G",
shapes[i].GetType(),
shapes[i].GetArea());
}
//--- Se o ponteiro tem o tipo POINTER_INVALID
else
{
//--- Notificamos um erro
PrintFormat("Objeto shapes[%d] não foi inicializado! Seu ponteiro pe %s",
i,EnumToString(CheckPointer(shapes[i])));
}
}

//--- Devemos excluir todos os objetos criados dinamicamente
for(int i=0;i<total;i++)
{
//--- Nós podemos excluir somente objetos com ponteiros do tipo POINTER_DYNAMIC
if(CheckPointer(shapes[i])==POINTER_DYNAMIC)
{
//--- Notificação de exclusão
PrintFormat("Excluindo shapes[%d]",i);
//--- Excluímos um objeto por meio de seu ponteiro
delete shapes[i];
}
}
}

Favor notar que ao excluir um objeto usando o operador delete, o tipo de seu ponteiro deve ser verificado. Somente objetos com ponteiro do tipo POINTER_DYNAMIC podem ser excluídos usando delete. Para ponteiros de outros tipos, um erro será retornado.

Além da redefinição de funções durante herança, o polimorfismo também inclui a implementação de uma mesma função com diferentes conjuntos de parâmetros dentro de uma classe. Isso significa que a classe pode ter várias funções com o mesmo nome, mas com um tipo e/ou conjunto de parâmetros diferentes. Neste caso, o polimorfismo é implementado através de sobrecarga de função.