2012-05-11 39 views
8

Hola a todos Tengo una duda con respecto a las plantillas y el polimorfismo. Por definición, el polimorfismo proporciona reutilización de código y, en cierto sentido, las plantillas permiten al usuario utilizar el mismo código al proporcionar programación genérica con diferentes tipos de datos. Entonces, ¿cuál es el beneficio de usar polimorfismo sobre plantillas? Puede ser una pregunta tonta, pero tengo curiosidad por saber la diferencia exacta.cuál es la diferencia entre las plantillas y el polimorfismo

+1

Las plantillas proporcionan polimorfismo de tiempo de compilación/estático. Mientras que * virtualism * proporciona polimorfismo dinámico. –

+1

¿Qué es diferente? Todo. El polimorfismo no es ni remotamente sobre la reutilización del código. Las plantillas son –

+1

@MooingDuck: el polimorfismo permite la reutilización del código. Código antiguo (escrito contra una clase base polimórfica) con código nuevo (escrito para la misma clase base). –

Respuesta

11

Parece que no entiende qué es el polimorfismo.

El polimorfismo, en su esencia, no tiene nada que ver con las clases derivadas. El polimorfismo simplemente significa la capacidad de usar un tipo sin saber todo sobre él. En lugar de utilizar un tipo concreto, el polimorfismo se basa en alguna forma de prototipo para definir qué tipos toma. Cualquier tipo que se ajuste a ese prototipo es aceptado.

El polimorfismo en tiempo de ejecución, en C++, se obtiene derivando clases de una clase base que contiene funciones virtuales. La clase base y las funciones virtuales forman el prototipo polimórfico. El código escrito para aceptar la clase base que llama a estas funciones virtuales aceptará cualquier instancia de clase derivada de la clase base.

tiempo de compilación polimorfismo es el polimorfismo que pasa ... en tiempo de compilación;) Lo que esto significa es que el compilador debe saber lo que está pasando. Puede haber escrito el código C++ contra un prototipo polimórfico, pero al compilador no le importa. Obtiene tipos concretos específicos después de la compilación.

El polimorfismo en tiempo de compilación es proporcionado por plantillas en C++. Una función o clase de plantilla puede tomar cualquier tipo que se ajuste a un prototipo, generalmente denominado "concepto". A diferencia de las clases base y las funciones virtuales, el prototipo es implícito: el prototipo se define solo por la forma en que el tipo es utilizado por la función/clase de la plantilla.

Si usted tiene esta función de plantilla:

template<typename T> 
void Stuff(T &t) 
{ 
    t.call(15); 
} 

No es un requisito implícito en T. Este requisito es que tiene una función de miembro llamada call. Debe haber una única sobrecarga de esta función miembro que puede invocarse con un valor entero.

Esto significa que cualquier tipo de que coincida con este prototipo se puede utilizar.

El polimorfismo de la plantilla es más amplio que el polimorfismo de herencia, ya que puede ser utilizado por una variedad más amplia de tipos. Un tipo tiene que diseñarse específicamente para usar el polimorfismo de herencia; tienes que derivarte de una clase. Un tipo puede ser no destructivo (es decir, no es necesario cambiar el tipo en sí) adaptado al polimorfismo de la plantilla. Más aún si su prototipo de plantilla está bien diseñado:

template<typename T> 
void Stuff(T &t) 
{ 
    call(t, 15); 
} 

Todo lo que esta versión de Stuff requiere es que hay alguna función que toma un valor y un T& entero. Si tengo algún tipo que quiero usar con Stuff, todo lo que tengo que hacer es definir una función call en un espacio de nombre apropiado (es decir, el espacio de nombres en el que se definió el tipo). Y esto funcionará bien. Todo sin modificando el tipo en sí.

Por supuesto, el polimorfismo en tiempo de compilación es ... en tiempo de compilación. Si deseo que un usuario ingrese o archivo de datos para seleccionar el tipo polimórfico, las plantillas no ayudarán mucho (aunque el borrado de tipos, una técnica basada en plantillas, puede ayudar). El principal beneficio del polimorfismo en tiempo de ejecución es que, de hecho, es el tiempo de ejecución.

Otra ventaja es que es más precisa sobre sus prototipos. Todo está explícitamente establecido sobre la herencia. La interfaz de función virtual en una clase base está claramente diseñada. El compilador impedirá que intente utilizar esa clase base de forma incorrecta (llamando a métodos que no existen en él). De hecho, un IDE decente guiará su código para que solo vea los métodos en la clase base.

El polimorfismo de la plantilla es mucho más implícito. Como C++ no tiene forma de deletrear el prototipo que una clase/función de plantilla en particular pone en un tipo, es muy fácil llamar accidentalmente a algo en un tipo de plantilla que no debería. El compilador solo detectará esto cuando intente usar un tipo que no se ajusta al prototipo. Y aun así, generalmente obtendrás un flujo de error masivo (dependiendo de cuán profundamente anidado esté tu código de plantilla) que hace que sea difícil saber dónde está el problema.

También es mucho más difícil implementar el prototipo de plantilla polimórfica implícita, ya que no está escrito. Implementar una clase derivada requiere recorrer la clase base, observar todas las funciones virtuales e implementarlas. Hacer esto para un prototipo de plantilla es mucho más difícil, a menos que haya documentación en algún lugar que lo deletree. Si no puede implementar algo, nuevamente obtendrá un mensaje de error que generalmente es menos pronunciado sobre el problema.

+1

"Debe haber una única sobrecarga de esta función de miembro a la que se puede llamar con un valor entero". - y esa llamada con 'int' no debe ser ambigua, y posiblemente alguna otra condición que he olvidado. Es por eso que el prototipo polimórfico generalmente se documenta en términos de "esta expresión debe tener las siguientes propiedades: ...". Si intenta documentarlo en términos de qué funciones y sobrecargas * existen *, entonces entra en todo tipo de casos extremos. –

Cuestiones relacionadas