sábado, 23 de fevereiro de 2013

C++: O que são métodos Virtuais?

Hoje estou fazendo um tutorial de programação de nível intermediário, que são os métodos virtuais. Estou fazendo isso, porque apesar de ser básico da linguagem (mas classifico como intermediário porque são poucas as instituições que explicam métodos virtuais), você não encontra praticamente NADA na internet que explique. Só coisas avançadas como métodos virtuais em heranças múltiplas e tal, mas o básico: NADA. Bem, vamos começar:

Métodos virtuais são métodos que são declaradas em uma classe base, mas serão implementadas nas classes que herdarão a classe base. Imaginemos a seguinte situação: nós vamos implementar uma classe chamada Animal. Todos os animais precisam comer, entretanto, o que eles comem depende de cada animal em particular. Por exemplo, uma Zebra comerá grama, enquanto um Leão comerá carne, mas todos os animais comem. Então, teríamos um diagrama de classe assim:

Todo animal precisa comer, entretanto, como eles comem variam de acordo com a espécie


Então, como a forma de comer varia de animal para animal, é impossível saber o como vai comer, então, jogamos essa responsabilidade para a classe que deriva do animal, neste caso, o Leão e a Zebra. Entretanto, se tivermos uma lista de animais, e queremos fazer eles comerem, então como a função está declarada no Animal, então sabemos que todos os animais comem, o que não seria possível se declarasse a função comer() somente nas classes derivadas.

Então, vamos para a parte de programação: como declaramos uma função virtual? Na classe base, usa-se a palavra-chave virtual antes da declaração da função. Vejamos o exemplo:

Arquivo: Animal.h
class Animal{
public:
  virtual void comer();
}

Aqui temos uma definição de um método virtual, neste caso, posso estar implementando um procedimento padrão caso classes que herdam não implemente o método. Também posso criar um método virtual puro, adicionando logo após as definições de parâmetros o símbolo "=0" dessa forma:


Arquivo: Animal.h
class Animal{
public:
  virtual void comer()=0;
}


Com isso, estou indicando que o método comer() não possui implementação e cada classe derivada terá que implementar seu próprio método. Como o método não é implementado na classe base, a classe se tornará uma classe abstrata, ou seja, não será possível instanciar um objeto da classe Animal, somente seus derivados, embora possa criar um ponteiro para classe Animal apontando para os objetos. Então, vamos ver como é que fica as outras classes:

Arquivo: Zebra.h
class Zebra:public Animal{
public:
  void comer();
}

Arquivo: Zebra.cpp
void Zebra::comer(){
  cout<<"Coma grama";
}


Arquivo: Leao.h
class Leao:public Animal{
public:
  void comer();
}

Arquivo: Leao.cpp
void Zebra::comer(){
  cout<<"Coma carne";
}

Aqui podemos ver que cada classe derivada de Animal, implementou o método comer da forma apropriada para cada animal. Agora, em alguma parte do código principal tenho a seguinte situação:

Animal *animal1 = new Zebra();
Animal *animal2 = new Leao();
animal1->comer();
animal2->comer();

Aqui temos duas instancia, uma para Zebra e outra para Leão. Os dois estão sendo guardados por um ponteiro da classe Animal. Isso está ok porque Zebra e Leão são da classe Animal. E em seguida, chamamos o método comer.  No animal1, o método vai dizer "Coma grama", enquanto no animal2, o método vai exibir "Coma carne", isso tudo por causa do método virtual, em que usará o método implementado a qual foi declarado na hora da instanciação.

Bem, esse é o que tenho dizer com os métodos virtuais, espero que esse tutorial dê uma mão para os perdidos que nem eu estava. Até mais.

10 comentários:

  1. Amigo, na hora em que vc declara que leao come carne, vc repete o da zebra. Fora isto, parabens pela post, me ajudou bastante, eu queria em java mas ta muito bom este. Vlw.

    Arquivo: Leao.cpp
    void Zebra::comer(){
    cout<<"Coma carne";
    }

    ResponderExcluir
  2. Excelente exemplo.
    Parabens!!!
    Tirou minha duvida,pois estou lendo o livro Padroes de Projetos - Solucoes reutilizaveis e tem muito este metodo, mas nao sabia do que se tratava.

    ResponderExcluir
  3. Vi isso na faculdade a alguns anos na faculdade e achei q tinha entendido, mais dpois da sua explicação ficou tudo muito mais claro. Parabéns!!

    ResponderExcluir
  4. Show amigo valeu pela sua colaboração e gentileza realmente este assunto
    é escasso na net e até mesmo em alguns livros.

    ResponderExcluir
  5. Muito obrigado pela explicação, estou fazendo uns exercicios de POO na faculdade utilizando c++ e sanou minhas duvidas sobre o assunto!

    ResponderExcluir
  6. Gostei muito, foi muito esclarecedor!
    Só um errinho de digitação no Arquivo Leao.cpp.
    Muito Obrigado!!!

    ResponderExcluir
  7. Parabéns pelo post parceiro, muito claro e conciso!

    ResponderExcluir
  8. Muito bom, esclareceu bem mais que alguns livros por ai.

    ResponderExcluir
  9. Entendo o quesito. Porém , posso utilizar ela fora do tipo 'void' , como por exemplo : virtual double calculox(int x , int y) == 0 ? Ou somente se aplica ao tipo exemplificado ?

    ResponderExcluir