2011-11-07 7 views
8

Supongamos que tengo una clase que puede usar diferentes tipos de funciones de distancia (distancia euclidiana, etc.) para hacer algunas comparaciones. He implementado estas funciones como subclases de una distancia de clase:Diferencia entre elegir una subclase mediante un parámetro de plantilla o instanciar una variable miembro

class Distance; 
class EuclideanDistance : public Distance; 
class OtherDistance : public Distance; 

Parece que para elegir el tipo de distancia de usar, lo que podía hacer:

template <typename TDistance> 
class MyClass; 

y cree una instancia con:

MyClass<EuclideanDistance> instance; 

o lograr lo mismo con:

class MyClass 
{ 
public: 
Distance* myDistanceFunction; 
} 

y no crear instancias con

MyClass instance; 
instance.myDistanceFunction = new EuclideanDistance; 

son las ventajas de un método sobre el otro?

Gracias,

David

Respuesta

6

La asociación (es decir, la solución sin plantillas) es preferible ya que le ofrece más flexibilidad, le permite cambiar la implementación de distancia en tiempo de ejecución, genera mensajes de error más limpios y archivos de objetos más limpios (menos símbolos).

Además, las clases generadas a partir de la plantilla parametrizada con diferentes tipos (implementaciones de distancia) se considerarán tipos diferentes y no serán intercambiables: MyClass<EuclideanDistance> es un tipo diferente de MyClass<MinkowskiDistance>. Esto lo forzará a realizar todas las funciones que operan en las plantillas MyClass, y finalmente dará lugar a una mayor complejidad sin beneficios adicionales.

Las plantillas se deben usar cuando necesite relajar la seguridad de tipos del lenguaje, por ejemplo, cuando está escribiendo una clase que debería funcionar en un número de tipos no relacionados (no derivados de una clase base/interfaz común) que, sin embargo, se comportan de manera similar (p. ej.todos tienen una función de miembro kwak()). Esto se llama duck-typing: los tipos formalmente no están relacionados pero todos exhiben propiedades similares.

En caso de que no pueda garantizar que todas las implementaciones a distancia deriven de una clase base/interfaz común, es posible que necesite utilizar plantillas. De lo contrario, prefiere la asociación simple y flexible.

2

El primero fija la distancia métrica para la clase en tiempo de compilación, mientras que la segunda lo hace en tiempo de ejecución. El primero es probablemente más eficiente porque permite al compilador optimizar partes de él, mientras que el segundo puede ser más flexible.

+0

En el segundo método, ¿hay alguna manera de crear un segundo objeto del mismo tipo que el primero? –

+0

@DavidDoria: ¿qué tipo de objeto quieres decir? Un 'MyClass', un' EuclideanDistance'? –

+0

Otro objeto del mismo tipo que myDistanceFunction dentro de MyClass. –

4

Bueno, aparte del tiempo de compilación frente al problema de tiempo de ejecución, la mayor diferencia ha sido anulada por su código preexistente. El uso de una plantilla le hubiera permitido usar cualquier tipo que admitiera una operación común (es decir, getDistance) sin que tengan que ser de la misma jerarquía. Esto hubiera significado que la distancia euclidiana y su otra clase podrían haber sido completamente diferentes, pero todavía utilizables en la plantilla, siempre y cuando admitieran el subconjunto de miembros que la plantilla utilizaba.

+0

Veo - entonces yo solo tendría que EuclideanDistance y OtherDistance sean clases separadas, no derivadas de ninguna clase de Distancia para padres. –

+0

Sería perfectamente posible :) Las plantillas permiten la programación genérica, tratando las cosas que tienen la misma interfaz implícita (las cosas requeridas por la plantilla) como iguales. Es el mismo concepto que la forma en que el STL a menudo le permite pasar en un functor (un objeto de función) o una función real: a la plantilla que utiliza la función pasada o al functor no le importa cuál es, solo le preocupa que el parámetro es invocable con la sintaxis(). Por lo tanto, las plantillas son mucho más flexibles que las jerarquías de herencia (pero definitivamente hay ventajas y desventajas para ambas). –

1

Herencia pública significa IS-A. ¿Es un EuclideanDisatance interoperable con "LorentzDistance" o "QuaternionDistance" (o lo que sea) de alguna manera significativa? ¿Son ambas "distancias" en el sentido de que algún código en algún lugar estaría contento de utilizar cualquiera de una manera no trivial (es decir, algo diferente a la impresión del valor, etc ...)? Mi conjetura es no, no lo es.

Así que quiere genéricos, no herencia. Las plantillas son una promesa más simple: dos cosas "se parecen" entre sí sintácticamente.

Cuestiones relacionadas