Inicio > Apunte, C++, Independiente > Polimorfismo genérico

Polimorfismo genérico


Si ya tienes tiempo trabajando con programación orientada a objetos, habrás notado cuán útil es el polimorfismo. Un ejemplo muy útil de esto es el patrón de diseño de la estrategia. Pero hay muchos otros ejemplos. Gracias a esto podemos cambiar comportamientos, y bueno, todo lo chido que tenemos con el polimorfismo.

Ahora bien, también tenemos una forma de hacer una especie de polimorfismo genérico, que me gustaría comentar dado que algunas librerías (como ATL o WTL) lo emplean. Consideremos el siguiente ejemplo:

template<class T>
class Base
{
public: 
    void Foo() 
    {
        T* pT = static_cast<T*>(this);
        pT->Imprimir();
    }
 
    void Imprimir() { cout << "Base::Imprimir"; }
};
 
class Derivada1 : public Base<Derivada1>
{
    // no hay nada aquí
};
 
class Derivada2: public Base<Derivada2>
{
    void Imprimir() { cout << "Derivada2::Imprimir"; }
};
 
int main()
{
    Derivada1 d1;
    Derivada2 d2;
 
    d1.Foo();    // imprime: "Base::Imprimir
    d2.Foo();    // imrpime: "Derivada2::Imprimir
 
    return 0;
}

Interesante, ¿no? Quizás hasta desconcertante. La clase Base toma un parámetro de plantilla que, además, espera sea alguna derivada de la misma Base. Lo interesante se presenta en la función Foo. Marcado en negritas, está la siguiente llamada: T* pT = static_cast<T*>(this);. ¿Qué quiere decir? Que vamos a convertir nuestro puntero (this) a una de las clases derivadas. Esto es correcto, toda vez que estamos pensando que el parámetro de plantilla sea una derivada de Base. Entonces, al hacer un static_cast hacia el parámetro de plantilla, e invoca a la función Imprimir de la misma; dado que no es virtual, no se invocará la implementación de la clase derivada, sino la implementación del parámetro de plantilla. Por eso es necesario hacer el static_cast. Así, al convertir a Derivada1, como ésta no tiene una implementación de Imprimir queoculte al Imprimir de Base, entonces se manda llamar a la versión de ésta. Sin embargo, Derivada2 sí implementaImprimir, y por lo tanto, oculta la de Base, y por ende es ésta la versión que es llamada.

Es interesante esta técnica. Tiene algunas ventajas, como el hecho de salvar memoria dado que no hay necesidad de vtables (tablas virtuales), o que todas las llamadas se resuelven en tiempo de compilación, por lo que pueden ser (y son) optimizadas. Pero quizás lo más importante es que es polimorfismo, pero no hay necesidad de tener que declarar una función virtual. Esto es muy importante en diversos escenarios, cuando, digamos, tenemos una librería que implementa el método X y que nosotros quisiéramos sobreescribir: dicho método tendría que haber sido declarado como virtual. Si no lo fué, aún tenemos la posibilidad de emplear el polimorfismo genérico.

Esta es, quizás, la característica más importante de esto.

Categorías:Apunte, C++, Independiente Etiquetas: ,
  1. Aún no hay comentarios.
  1. No trackbacks yet.

Responder

Introduce tus datos o haz clic en un icono para iniciar sesión:

Logo de WordPress.com

Estás comentando usando tu cuenta de WordPress.com. Cerrar sesión / Cambiar )

Imagen de Twitter

Estás comentando usando tu cuenta de Twitter. Cerrar sesión / Cambiar )

Foto de Facebook

Estás comentando usando tu cuenta de Facebook. Cerrar sesión / Cambiar )

Google+ photo

Estás comentando usando tu cuenta de Google+. Cerrar sesión / Cambiar )

Conectando a %s