- Encapsulamento e Extensibilidade de Tipo
- Herança
- Polimorfismo
- Sobrecarga (Overload)
- Funções Virtuais
- Membros Estáticos de uma Classe
- Templates de Função
- Modelos de classes
- Classes abstratas
Funções Virtuais
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.
//+------------------------------------------------------------------+
|
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
|
A forma Quadrado é descrita por meio da classe CTetrisShape6 e tem sua implementação própria do método Draw():
class CTetrisShape6 : public CTetrisShape
|
Dependendo da classe da qual o objeto criado pertence, é chamada a função virtual desta ou daquela classe derivada.
void CTetrisField::NewShape()
|
Modificador override #
O modificador override indica que a função declarada deve substituir o método da classe pai. O uso deste modificador permite evitar erros durante as substituições, por exemplo, durante uma alteração aleatória na assinatura do método. Ou, por exemplo, na classe base, está definido o método func, ele é usado como argumento da variável do tipo int:
class CFoo |
A seguir, o método é substituído na classe que está sendo herdada:
class CBar : public CFoo |
No entanto, no caso de haver um erro, o tipo de argumento é alterado de int para short. De fato, aqui acontece uma sobrecarga do método. Agindo em conformidade com o algoritmo de estabelecimento da função sobrecarregada, em determinadas situações, o compilador pode selecionar o método definido na classe base, em vez de escolher o método de substituição.
Para evitar esses erros, é necessário adicionar o modificador override ao método de substituição.
class CBar : public CFoo |
Se, durante a substituição, for alterada a assinatura do método, o compilador não conseguirá encontrar, na classe pai, o método com essa mesma assinatura e emitir o erro de compilação:
'CBar::func' method is declared with 'override' specifier but does not override any base class method |
Modificador final #
Ao contrário do anterior, o modificador final proíbe a substituição do método em classes de herança. Se a implementação do método for auto-suficiente e concluída na sua totalidade, declare esse fato usando o modificador final, para ele não ser alterado em conseqüência.
class CFoo |
Como no exemplo acima, ao tentar substituir o método usando o modificador final, o compilador irá emitir um erro:
'CFoo::func' method declared as 'final' cannot be overridden by 'CBar::func' |
Veja Também