Programar em C++/Polimorfismo


Esta página precisa ser reciclada (discuta).
Ao melhorá-la, você estará ajudando o Wikilivros.

Conceito

editar

Polimorfismo em linguagens orientadas a objeto, é a capacidade de objetos se comportarem de forma diferenciada em face de suas características ou do ambiente ao qual estejam submetidos, mesmo quando executando ação que detenha, semanticamente, a mesma designação.

O polimorfismo em C++ se apresenta sob diversas formas diferentes, desde as mais simples, como funções com mesmo nome e lista de parâmetros diferentes, até as mais complexas como funções virtuais, cujas formas de execução são dependentes da classe a qual o objeto pertence e são identificadas em tempo de execução.

Funções virtuais

editar
#include <iostream>

using std::cout;
using std::endl;

class Base {
public:
    // declaração da função virtual
    virtual void Quem_VIRTUAL()
    {
        cout << "Base\n";
    }
    // função comum
    void Quem_NAO_VIRTUAL()
    {
        cout << "Base\n";
    }
};

class Derivada : public Base {
public:
    // função virtual sobrescrita
    virtual void Quem_VIRTUAL()
    {
        cout << "Derivada\n";
    }
    // função comum sobrescrita
    void Quem_NAO_VIRTUAL()
    {
        cout << "Derivada\n";
    }
};

int main ()
{
    Base *ptr_base;
    Derivada derivada;

    ptr_base = &derivada;           // conversão implícita permissível
    ptr_base->Quem_VIRTUAL();       // chamada polimórfica (mostra: "Derivada")
    ptr_base->Quem_NAO_VIRTUAL();   // chamada comum, não-polimórfica (mostra: "Base")

    cout << endl;

    return 0;
}

Chamando múltiplas funções virtuais

editar

Funções virtuais e passagem por valor

editar

Construtor de cópia virtual

editar

Classe base virtual

editar

Consideremos o seguinte programa:

// Este programa contém um erro e não será compilado.
 #include <iostream>
 using namespace std;
 class base
    {
    public:
           int i;
    };

 class derived1 : public base // derived1 inherits base.
    {
    public:
           int j;
    };

 class derived2 : public base // derived2 inherits base.
    {
    public:
           int k;
    };

/* 
 * "derived3" herda características de "derived1" e "derived2". 
 * Isto significa que há duas cópias da base em "derived3"! 
 */
 class derived3 : public derived1, public derived2
    {
    public: 
            int sum;
    };

 int main()
 {
    derived3 ob;
    ob.i = 10; // Isto se torna ambíguo; A qual "i" estamos nos referindo???
    ob.j = 20;
    ob.k = 30;
    ob.sum = ob.i + ob.j + ob.k;// "i" ambíguo aqui, também
    cout << ob.i << " ";// também ambíguo, Qual "i"?
    cout << ob.j << " " << ob.k << " ";
    cout << ob.sum;
#ifdef WIN32
    system ("pause");
#endif
    return 0;
 }

As classes derived1 e derived2 são herdadas como classes base. A classe derived3 herda tanto de derived1 quanto de derived2. Como resultado temos 2 cópias da classe base presentes no objeto da derived3, por exemplo presente na linha ob.i=10; isto resulta numa ambiguidade e o programa não vai compilar.

Há duas maneiras para remediar a situação:

1. Aplicar o operador de resolução de escopo manualmente:

//Este programa usa resolução de escopo explicita para selecionar "i".
 #include <iostream>
 using namespace std;
 class base 
    {
    public:
           int i;
    };

 class derived1 : public base // derived1 inherits base.
    {
    public:
           int j;
    };

 class derived2 : public base // derived2 inherits base.
    {
    public:
           int k;
    };

 class derived3 : public derived1, public derived2 /* "derived3" herda as bases "derived1" e "derived2". Isto significa que há duas cópias de bases em "derived3"! */
    {
    public:
           int sum;
    };

 int main()
 {
    derived3 ob;
    ob.derived1::i = 10; 	// escopo resolvido, usa o "i" em "derived1".
    ob.j = 20;
    ob.k = 30;
    ob.sum = ob.derived1::i + ob.j + ob.k;		// escopo resolvido.
    cout << ob.derived1::i << " ";		// também resolvido aqui.
    cout << ob.j << " " << ob.k << " ";
    cout << ob.sum;
#ifdef WIN32
    system ("pause");
#endif
    return 0;
 }


2. A segunda maneira é através de classes bases virtuais:

Quando temos 2 ou mais objetos que são derivados da mesma base class, podemos prevenir múltiplas cópias da base class declarando a base class como virtual quando ela é herdada. Exemplificando:

 // Este program usa classes bases virtuais.
 #include <iostream>
 using namespace std;
 class base 
        {
        public:
               int i;
        };
 class derived1 : virtual public base // derived1 inherits base as virtual.
        {
        public:
               int j;
        };
 class derived2 : virtual public base // derived2 inherits base as virtual.
        {
        public:
               int k;
        };
 class derived3 : public derived1, public derived2 /* derived3 inherits both derived1 and derived2. This time, there is only one copy of base class. */
        { 
        public:
               int sum;
        };
 int main()
 {
    derived3 ob;
    ob.i = 10; // now unambiguous
    ob.j = 20;
    ob.k = 30;
    ob.sum = ob.i + ob.j + ob.k;// unambiguous
    cout << ob.i << " ";// unambiguous
    cout << ob.j << " " << ob.k << " ";
    cout << ob.sum;
    system ("pause");
    return 0;
 }

Repare que agora temos a palavra virtual antes da classe.