PDA

View Full Version : Funções Virtuais



jssuser
07-01-2019, 01:55 AM
A palavra-chave virtual é o especificador de função que fornece um mecanismo para selecionar dinamicamente em tempo de execução uma função-membro apropriada entre as funções de classes base e derivadas. Estrutura não podem ter funções virtuais. Pode ser usado para alterar as declarações de funções-membro somente.

A função virtual, assim como uma função comum, deve ter um corpo executável. Ao ser chamada, sua semântica é a mesma que das outras funções.

Uma função virtual pode ser sobreposta (overridden) em um classe derivada. A escolha de qual definição de função deve ser chamada para uma função virtual é feita dinamicamente (em tempo de execução). Um caso típico é quando uma classe base contém uma função virtual, e as classes derivadas têm sua própria versão desta função.

O ponteiro para a classe base pode indicar tanto um objeto da classe base quanto um objeto de uma classe derivada. A escolha da função-membro a ser chamada será executada em tempo de execução e dependerá do tipo do objeto, não do tipo do ponteiro. Se não houver nenhum membro de um tipo derivado, a função virtual da classe base é usada por default.

Destrutores são sempre virtuais, independentemente se elas estão declaradas com a palavra-chave virtual ou não.

Vamos considerar o uso de funções virtuais no exemplo do MT5_Tetris.mq5. A classe base CTetrisShape com a função virtual de desenhar é definjida na inclusão do arquivo MT5_TetisShape.mqh.

//+------------------------------------------------------------------+
class CTetrisShape
{
protected:
int m_type;
int m_xpos;
int m_ypos;
int m_xsize;
int m_ysize;
int m_prev_turn;
int m_turn;
int m_right_border;
public:
void CTetrisShape();
void SetRightBorder(int border) { m_right_border=border; }
void SetYPos(int ypos) { m_ypos=ypos; }
void SetXPos(int xpos) { m_xpos=xpos; }
int GetYPos() { return(m_ypos); }
int GetXPos() { return(m_xpos); }
int GetYSize() { return(m_ysize); }
int GetXSize() { return(m_xsize); }
int GetType() { return(m_type); }
void Left() { m_xpos-=SHAPE_SIZE; }
void Right() { m_xpos+=SHAPE_SIZE; }
void Rotate() { m_prev_turn=m_turn; if(++m_turn>3) m_turn=0; }
virtual void Draw() { return; }
virtual bool CheckDown(int& pad_array[]);
virtual bool CheckLeft(int& side_row[]);
virtual bool CheckRight(int& side_row[]);
};

Mais adiante, para cada classe derivada, esta função é implementada de acordo com as características da classe descendente. Por exemplo, a primeira forma CTetrisShape1 tem sua implementação própria da função Draw():

class CTetrisShape1 : public CTetrisShape
{
public:
//--- desenhando formato
virtual void Draw()
{
int i;
string name;
//---
if(m_turn==0 || m_turn==2)
{
//--- horizontal
for(i=0; i<4; i++)
{
name=SHAPE_NAME+(string)i;
ObjectSetInteger(0,name,OBJPROP_XDISTANCE,m_xpos+i *SHAPE_SIZE);
ObjectSetInteger(0,name,OBJPROP_YDISTANCE,m_ypos);
}
}
else
{
//--- vertical
for(i=0; i<4; i++)
{
name=SHAPE_NAME+(string)i;
ObjectSetInteger(0,name,OBJPROP_XDISTANCE,m_xpos);
ObjectSetInteger(0,name,OBJPROP_YDISTANCE,m_ypos+i *SHAPE_SIZE);
}
}
}
}

A forma Quadrado é descrita por meio da classe CTetrisShape6 e tem sua implementação própria do método Draw():

class CTetrisShape6 : public CTetrisShape
{
public:
//--- desenhando formato
virtual void Draw()
{
int i;
string name;
//---
for(i=0; i<2; i++)
{
name=SHAPE_NAME+(string)i;
ObjectSetInteger(0,name,OBJPROP_XDISTANCE,m_xpos+i *SHAPE_SIZE);
ObjectSetInteger(0,name,OBJPROP_YDISTANCE,m_ypos);
}
for(i=2; i<4; i++)
{
name=SHAPE_NAME+(string)i;
ObjectSetInteger(0,name,OBJPROP_XDISTANCE,m_xpos+( i-2)*SHAPE_SIZE);
ObjectSetInteger(0,name,OBJPROP_YDISTANCE,m_ypos+S HAPE_SIZE);
}
}
};

Dependendo da classe da qual o objeto criado pertence, é chamada a função virtual desta ou daquela classe derivada.

void CTetrisField::NewShape()
{
//--- criando uma dos 7 possíveis formas aleatoriamente
int nshape=rand()%7;
switch(nshape)
{
case 0: m_shape=new CTetrisShape1; break;
case 1: m_shape=new CTetrisShape2; break;
case 2: m_shape=new CTetrisShape3; break;
case 3: m_shape=new CTetrisShape4; break;
case 4: m_shape=new CTetrisShape5; break;
case 5: m_shape=new CTetrisShape6; break;
case 6: m_shape=new CTetrisShape7; break;
}
//--- desenhar
m_shape.Draw();
//---
}