Curso completo de linguagem C++
Gameprog - Escola de programação de jogos digitais
Contato: gameprog.br@gmail.com
track13.html

index << >>

13. Classe virtual e abstrata

13.1 Visão geral virtual void atacar() { // bloco de código } A classe virtual permite que uma coleção de diversos tipos de objetos sejam todos referenciados pelo ponteiro de uma classe base e garante que cada tipo de objeto tenha o seu método chamado adequadamente conforme o seu tipo. A classe base torna-se virtual quando qualquer um de seus métodos são precedidos pela palavra chave virtual. Não é necessário repetir a palavra chave virtual na redefinição dos métodos virtuais nas classes derivadas. virtual void atacar() = 0 // Esta sintaxe define uma classe abstrata A classe abstrata ou classe virtual abstrata é quando a classe base apenas define o nome dos métodos sem implementar o código dentro de si mesma, deixando essa tarefa para as classes derivadas. Dessa forma a classe abstrata torna-se apenas um projeto que as classes derivadas têm que implementar. Nessa situação dizemos que a classe abstrata define uma interface que consiste em um núcleo comum de métodos que deverão ser implementados pelas classes derivadas. A classe abstrata não dá origem a objetos. Como exemplo hipotético de classe abstrata considere que 'ser humano' é uma classe abstrata e que 'homem' ou 'mulher' são classes derivadas que implementam a interface do que é considerado ser humano na classe abstrata. Outro exemplo, considere que as subclasses Gol e Uno são implementações da classe abstrata veículos que define o núcleo comum de propriedades e métodos pertencentes a todos os tipos de veículos. Veja agora o programa exemplo:
// classe_virtual.cpp // Este programa ilustra o uso de classe virtual abstrata #include <iostream> using namespace std; // ------------------ Classe monstro ----------------------------------------- class Monstro { public: int m_estrago; int m_id; static int nobj; Monstro(int estrago=10): m_estrago(estrago) { m_id = nobj; nobj++; } virtual void atacar() = 0; }; // fim da classe monstro // inicialização da propriedade estática int Monstro::nobj = 1; // ------------------ Classe Ogro derivada da classe monstro ----------------- class Ogro: public Monstro { public: // construtor Ogro(int estrago=12): Monstro(estrago) { } void atacar() { cout << " O ogro #" << m_id << " te atacou com uma pedra e vc perdeu "; cout << m_estrago << " pontos de energia. \n"; } // fim do método atacar() }; // fim da classe ogro // ------------------ Classe Vampiro derivada da classe monstro ----------------- class Vampiro: public Monstro { public: // construtor Vampiro(int estrago=22) { m_estrago = estrago; } void atacar() { cout << " O vampiro #" << m_id << " te mordeu e vc perdeu "; cout << m_estrago << " pontos de energia. \n"; } // fim do método atacar() }; // fim da classe vampiro // protótipo das nossas funções básicas void inicio(); void fim(); // --------------- Nossa funçao principal começa aqui... int main() { inicio(); Monstro *ptr_monstros[3]; ptr_monstros[0] = new Ogro; ptr_monstros[1] = new Ogro; ptr_monstros[2] = new Vampiro; ptr_monstros[3] = new Vampiro; cout << "\n--- Parte 02: vampiros e ogros via ponteiros :-) -------------- \n"; for (int ncx =0; ncx < 4; ncx++) ptr_monstros[ncx]->atacar(); delete[] ptr_monstros; fim(); } // endmain // -------------------------- funcoes ---------------------------------------- void inicio() { system("title classe_virtual.cpp"); system("color f0"); cout << "\n"; } // endfunction: inicio() void fim() { cout << endl; system("pause"); } // endfunction: fim()
virtual void atacar() = 0 Esta sintaxe do método atacar() da classe Monstro define que esta classe é virtual e abstrata. Depois desta sintaxe é ilegal criar objetos instanciados diretamente da classe Monstro e seu programa não compila se isto for feito. Apenas a palavra chave virtual corrige o problema apresentado no programa anterior lista_monstro.cpp quando vampiros e ogros executaram o método genérico atacar() da classe Monstro. Nesta sintaxe cada ogro e vampiro criado executará respectivamente o seu método atacar(). A classe virtual gasta um pouco mais de memória porque nos bastidores do programa é mantido uma tabela de ponteiros dos objetos criados. Monstro *ptr_monstros[3]; ptr_monstros[0] = new Ogro; delete[] ptr_monstros; Em nosso programa alocamos e liberamos a memória dentro da função main(). Se o processo de alocação de memória for feito dentro do construtor da classe é importante que o destrutor também seja virtual e que seja definido explicitamente o destrutor de cada subclasse para que seja garantido a liberação da memória na finalização do seu programa ou quando os objetos saírem de escopo como acontece no final de uma função. Na criação de objetos derivados inicialmente é chamado o construtor da classe base para inicializar seus respectivos membros, na sequência é chamado o construtor da subclasse. Veja que em nosso programa utilizamos o contrutor da classe base para fazer a contagem dos objetos, incluindo os derivados. Na destruição do objeto o caminho é o inverso, primeiro a subclasse destrói a parte especializada do objeto e depois o destrutor da classe base finaliza a sua parte.
index << >>


Produzido por Gameprog: Jair Pereira - Fev/2006 - Junho/2013 © gameprog.br@gmail.com http://www.gameprog.com.br