poo polimorfismo parametrico hoc estatico dinamico c++ optimization polymorphism static-polymorphism

c++ - hoc - polimorfismo parametrico



Polimorfismo dinámico vs estático en C++: ¿cuál es preferible? (4)

El polimorfismo estático puede proporcionar una ventaja significativa si el compilador puede incorporar el método llamado. Por ejemplo, si el método virtual se ve así:

protected: virtual bool is_my_class_fast_enough() override {return true;}

entonces el polimofismo estático debería ser la forma preferida (de lo contrario, el método debería ser honesto y devolver falso :).

La llamada virtual "verdadera" (en la mayoría de los casos) no se puede insertar.

Otras diferencias (como la dirección indirecta adicional en la llamada vtable) son despreciables

[EDITAR]

Sin embargo, si realmente necesita polimorfismo en tiempo de ejecución (si la persona que llama no debe conocer la implementación del método y, por lo tanto, el método no se puede insertar en el lado de la persona que llama), entonces no reinvente vtable (como mencionó Emilio Garavaglia), simplemente úselo .

Entiendo que el polimorfismo dinámico / estático depende del diseño y los requisitos de la aplicación. Sin embargo, ¿es aconsejable SIEMPRE elegir polimorfismo estático sobre dinámico si es posible? En particular, puedo ver las siguientes 2 opciones de diseño en mi aplicación, las cuales parecen desaconsejarse:

  1. Implemente el polimorfismo estático utilizando CRTP: no hay sobrecarga de búsqueda vtable al tiempo que sigue proporcionando una interfaz en forma de plantilla de clase base. Pero, usa una gran cantidad de switch y static_cast para acceder a la clase / método correcto, lo que es peligroso

  2. Polimorfismo dinámico: implemente interfaces (clases virtuales puras), asociando el costo de búsqueda incluso para funciones triviales como los accesores / mutadores

Mi aplicación es crítica en el tiempo, así que estoy a favor del polimorfismo estático. Pero debe saber si usar demasiada static_cast es una indicación de un diseño deficiente y cómo evitarlo sin incurrir en la latencia.

EDIT: Gracias por la visión. Tomando un caso específico, ¿cuál de estos es un mejor enfoque?

class IMessage_Type_1 { virtual long getQuantity() =0; ... } class Message_Type_1_Impl: public IMessage_Type_1 { long getQuantity() { return _qty;} ... }

O

template <class T> class TMessage_Type_1 { long getQuantity() { return static_cast<T*>(this)->getQuantity(); } ... } class Message_Type_1_Impl: public TMessage_Type_1<Message_Type_1_Impl> { long getQuantity() { return _qty; } ... }

Tenga en cuenta que hay varios mutadores / accesores en cada clase, y necesito especificar una interfaz en mi aplicación. En el polimorfismo estático, cambio solo una vez, para obtener el tipo de mensaje. Sin embargo, en el polimorfismo dinámico, estoy usando funciones virtuales para cada llamada de método. ¿Eso no hace que sea un caso para usar poly estático? Creo que static_cast en CRTP es bastante seguro y no hay penalización de rendimiento (límite de tiempo de compilación)?


El polimorfismo estático y dinámico está diseñado para resolver diferentes problemas, por lo que rara vez hay casos en que ambos sean apropiados. En tales casos, el polimorfismo dinámico dará como resultado un diseño más flexible y más fácil de administrar. Pero la mayoría de las veces, la elección será obvia, por otras razones.

Una categorización aproximada de las dos: las funciones virtuales permiten diferentes implementaciones para una interfaz común; Las plantillas permiten diferentes interfaces para una implementación común.


Un interruptor no es más que una secuencia de saltos que, después de optimizado, se convierte en un salto a una dirección buscada por una tabla. Exactamente como es una llamada de función virtual.

Si tiene que saltar dependiendo de un tipo, primero debe seleccionar el tipo. Si la selección no se puede realizar en tiempo de compilación (esencialmente porque depende de la entrada), siempre debe realizar dos operaciones: seleccionar y saltar. La herramienta sintáctica que utiliza para seleccionar no cambia el rendimiento, ya que optimiza la misma.

De hecho estás reinventando la v-table.


Usted ve los problemas de diseño asociados con el polimorfismo puramente basado en plantillas. Si bien una clase base virtual con aspecto te da una idea bastante buena de lo que se espera de una clase derivada, esto se vuelve mucho más difícil en los diseños con muchas plantillas. Se puede demostrar fácilmente eso introduciendo un error de sintaxis al usar una de las bibliotecas boost.

Por otro lado, tiene miedo de los problemas de rendimiento cuando utiliza funciones virtuales. Probar que esto será un problema es mucho más difícil.

En mi humilde opinión esta no es una pregunta. Stick con funciones virtuales hasta que se indique lo contrario. Las llamadas a funciones virtuales son mucho más rápidas de lo que la mayoría de la gente piensa (Llamar a una función desde una biblioteca enlazada dinámicamente también agrega una capa de direccionamiento indirecto. Nadie parece pensar en eso).

Solo consideraría un diseño con plantillas si hace que el código sea más fácil de leer (algoritmos genéricos), usa uno de los pocos casos conocidos como lentos con funciones virtuales (algoritmos numéricos) o ya lo identificó como un cuello de botella en el rendimiento.