Respuesta

11

NVI es un modismo, el Método de plantilla es un patrón. NVI es una implementación del patrón de método de plantilla que utiliza el despacho dinámico en C++; también es posible crear métodos de plantillas en C++ mediante la metaprogramación de plantillas para eliminar el despacho dinámico.

Un patrón es más general que una expresión idiomática, y los idiomas pueden usar diferentes expresiones idiomáticas para implementar el patrón.

+1

Entonces, ¿está diciendo que NVI es básicamente una implementación específica del lenguaje del patrón de Método de plantilla y más allá de eso no hay diferencia real? ¿Cómo usarías las plantillas de C++ para lograr el mismo resultado? –

+0

@Robert S. Barnes Por lo que puedo ver, no hay una forma obvia de usar plantillas C++ como método de plantilla. El método de la plantilla dice "haz esto, luego haz otra cosa", y aunque puedes crear un functor para una u otra de las cosas que hacer, no existe una relación real con los parámetros de tipo que las plantillas de C++ te dan. –

+0

Supongo que todavía no estoy entendiendo lo que quería decir aquí: "también es posible crear métodos de plantillas en C++ mediante la metaprogramación de plantillas para eliminar el despacho dinámico". –

8

Como se ha dicho, NVI es un modismo de programación, relacionado con una categoría de idiomas. Se ha promovido por Herb Sutter entre otros, ya que ayuda a hacer cumplir los contratos:

  • invariantes de clase
  • contratos de función (afirmaciones sobre los parámetros pasados ​​y el valor de retorno generada)
  • operaciones repetitivas (como la tala)
  • control sobre las excepciones generadas (mala idea, aunque;))

Sin embargo, la puesta en práctica de hecho pueden diferir considerablemente, por ejemplo, otro ejemplo de NVI implementación es combinarlo con Pimpl:

class FooImpl; 

class Foo 
{ 
public: 
    enum type { Type1, Type2 }; 

    Foo(type t, int i, int j); 

    int GetResult() const; 

private: 
    FooImpl* mImpl; 
}; 

Y para la puesta en práctica:

struct FooImpl 
{ 
    virtual ~FooImpl(); 
    virtual int GetResult() const; 
}; 

class FooType1: public FooImpl 
{ 
public: 
    FooType1(int i, int j); 
    virtual int GetResult() const; 
private: 
    /// ... 
}; 

siempre he encontrado que transmitió el punto mejor. ¿Lo has descubierto?

El punto principal es que virtual es un detalle de implementación. Y exponer los detalles de implementación en la interfaz es una mala idea, porque es posible que desee cambiarlos.

Además, los detalles de implementación tienden a interferir con la compatibilidad binaria. Por ejemplo, agregar un nuevo método virtual en una clase puede cambiar el diseño de la tabla virtual (técnica de implementación común) y, por lo tanto, estropear la compatibilidad binaria. En gcc, debe asegurarse de agregarlo último (entre los virtuales) si desea conservar la compatibilidad.

Al usar la combinación anterior de NVI + Pimpl, no hay ningún virtual (ni siquiera privado) en la clase expuesta. El diseño de la memoria es compatible con versiones anteriores y posteriores. Hemos logrado compatibilidad binaria.

Aquí, utilizamos varios patrones a la vez:

  • plantilla Método
  • Estrategia (ya que podemos cambiar el puntero a voluntad)
  • fábrica (para decidir qué aplicación obtenemos)
+0

+1 para el "detalle de implementación virtual" y la consideración de ABI. – neuro

+0

+1. Sin embargo, tengo que estar en desacuerdo con usted sobre la posibilidad de hacer clases separadas para los pimpl para la interfaz virtual. La desventaja más obvia es que duplica la cantidad de clases requeridas. Además, si FooImpl no era opaco, podría tentar a las personas a usarlo directamente y omitir Foo. Sin embargo, es poco probable que sea opaco, ya que el objetivo de los NVI es permitir que las personas anulen las implementaciones virtuales, por lo que FooImpl debería ser de acceso público. A pesar de que tiene sus propios inconvenientes, creo que implementar NVI en una clase y evitar todas las funciones virtuales públicas es un mejor enfoque. – stinky472

+0

También es una política más fácil de aplicar: no hay funciones virtuales públicas en oposición a una que crea casos especiales para clases similares a pimpl que proporcionan la interfaz virtual pública. – stinky472

Cuestiones relacionadas