He oído que las plantillas de funciones miembro de clase C ++ no pueden ser virtuales. ¿Es esto cierto?
Si pueden ser virtuales, ¿cuál es un ejemplo de un escenario en el que uno usaría tal función?
c++
templates
virtual-functions
function-templates
c++-faq
WannaBeGeek
fuente
fuente
Respuestas:
Las plantillas tienen que ver con el código de generación del compilador en tiempo de compilación . Las funciones virtuales tienen que ver con el sistema de tiempo de ejecución para determinar qué función llamar en tiempo de ejecución .
Una vez que el sistema de tiempo de ejecución descubrió que necesitaría llamar a una función virtual con plantilla, la compilación está lista y el compilador ya no puede generar la instancia adecuada. Por lo tanto, no puede tener plantillas de funciones miembro virtuales.
Sin embargo, existen algunas técnicas poderosas e interesantes derivadas de la combinación de polimorfismo y plantillas, en particular el llamado borrado de tipo .
fuente
Virtual functions are all about the run-time system figuring out which function to call at run-time
- Lo siento, pero esta es una forma bastante incorrecta, y bastante confuso. Es solo indirección, y no hay un "tiempo de ejecución que se resuelva", se sabe durante el tiempo de compilación que la función a llamar es la señalada por el enésimo puntero en la tabla. "Resolver" implica que hay verificaciones de tipo y tal, que no es el caso.Once the run-time system figured out it would need to call a templatized virtual function
- Se sabe si la función es virtual o no en tiempo de compilación.void f(concr_base& cb, virt_base& vb) { cb.f(); vb.f(); }
, entonces "sabe" qué función se invoca en el puntocb.f()
llamado, y no lo sabe paravb.f()
. Este último tiene que ser encontrado en tiempo de ejecución , por el sistema de tiempo de ejecución . Si desea llamar a esto "descifrar" y si esto es más o menos eficiente, no cambia un poco estos hechos.Desde plantillas de C ++ La guía completa:
fuente
C ++ no permite funciones de miembro de plantilla virtual en este momento. La razón más probable es la complejidad de implementarlo. Rajendra da una buena razón por la que no se puede hacer en este momento, pero podría ser posible con cambios razonables del estándar. Especialmente determinar cuántas instancias de una función con plantilla existen realmente y construir la tabla virtual parece difícil si considera el lugar de la llamada a la función virtual. La gente de estándares solo tiene muchas otras cosas que hacer en este momento y C ++ 1x también es mucho trabajo para los redactores del compilador.
¿Cuándo necesitarías una función miembro con plantilla? Una vez me encontré con una situación en la que intenté refactorizar una jerarquía con una clase base virtual pura. Era un estilo pobre para implementar diferentes estrategias. Quería cambiar el argumento de una de las funciones virtuales a un tipo numérico y, en lugar de sobrecargar la función miembro y anular cada sobrecarga en todas las subclases, intenté usar funciones de plantilla virtual (y tuve que descubrir que no existen .)
fuente
Tablas de funciones virtuales
Comencemos con algunos antecedentes sobre tablas de funciones virtuales y cómo funcionan ( fuente ):
Mi problema o como vine aquí
Estoy intentando usar algo como esto ahora para una clase base de cubefile con funciones de carga optimizadas con plantillas que se implementarán de manera diferente para diferentes tipos de cubos (algunos almacenados por píxel, otros por imagen, etc.).
Algún código:
Lo que me gustaría que fuera, pero no se compilará debido a un combo virtual con plantilla:
Terminé moviendo la declaración de plantilla al nivel de clase. Esta solución habría obligado a los programas a conocer los tipos específicos de datos que leerían antes de leerlos, lo cual es inaceptable.Solución
advertencia, esto no es muy bonito pero me permitió eliminar el código de ejecución repetitivo
1) en la clase base
2) y en las clases infantiles
Tenga en cuenta que LoadAnyCube no se declara en la clase base.
Aquí hay otra respuesta de desbordamiento de pila con una solución alternativa : necesita una solución de miembro de plantilla virtual .
fuente
El siguiente código puede compilarse y ejecutarse correctamente, utilizando MinGW G ++ 3.4.5 en Windows 7:
y la salida es:
Y luego agregué una nueva clase X:
Cuando intenté usar la clase X en main () así:
g ++ informa el siguiente error:
Entonces es obvio que:
fuente
No, no pueden. Pero:
tiene el mismo efecto si todo lo que quiere hacer es tener una interfaz común y diferir la implementación a las subclases.
fuente
Foo
puntero está calificado comoFoo<Bar>
, no puede apuntar a unFoo<Barf>
oFoo<XXX>
.No, las funciones miembro de la plantilla no pueden ser virtuales.
fuente
En las otras respuestas, la función de plantilla propuesta es una fachada y no ofrece ningún beneficio práctico.
El lenguaje no permite funciones de plantilla virtual, pero con una solución alternativa es posible tener ambas, por ejemplo, una implementación de plantilla para cada clase y una interfaz común virtual.
Sin embargo, es necesario definir para cada combinación de tipo de plantilla una función de contenedor virtual ficticio:
Salida:
Pruébalo aquí
fuente
Para responder a la segunda parte de la pregunta:
Esto no es una cosa irrazonable querer hacer. Por ejemplo, Java (donde cada método es virtual) no tiene problemas con los métodos genéricos.
Un ejemplo en C ++ de querer una plantilla de función virtual es una función miembro que acepte un iterador genérico. O una función miembro que acepta un objeto de función genérico.
La solución a este problema es utilizar el borrado de tipo con la función boost :: any_range y boost ::, que le permitirá aceptar un iterador genérico o un functor sin la necesidad de convertir su función en una plantilla.
fuente
Existe una solución alternativa para el 'método de plantilla virtual' si se conoce de antemano un conjunto de tipos para el método de plantilla.
Para mostrar la idea, en el ejemplo a continuación solo se usan dos tipos (
int
ydouble
).Allí, un método de plantilla 'virtual' (
Base::Method
) llama al método virtual correspondiente (uno deBase::VMethod
) que, a su vez, llama a la implementación del método de plantilla (Impl::TMethod
).Solo se necesita implementar el método de plantilla
TMethod
en implementaciones derivadas (AImpl
,BImpl
) y usarDerived<*Impl>
.Salida:
NB: en
Base::Method
realidad es excedente para el código real (VMethod
puede hacerse público y usarse directamente). Lo agregué para que parezca un método de plantilla 'virtual' real.fuente
Base
clase original cada vez que necesita llamar a una función de plantilla con un tipo de argumento no compatible con los implementados hasta ahora. Evitar esta necesidad es la intención de las plantillas ...Si bien una pregunta anterior que ha sido respondida por muchos, creo que un método sucinto, no muy diferente de los demás publicados, es utilizar una macro menor para ayudar a facilitar la duplicación de declaraciones de clase.
Entonces, para implementar nuestra subclase:
El beneficio aquí es que, al agregar un tipo recientemente admitido, todo se puede hacer desde el encabezado abstracto y renunciar posiblemente a la rectificación en múltiples archivos de origen / encabezado.
fuente
Al menos con gcc 5.4, las funciones virtuales podrían ser miembros de plantilla, pero tienen que ser plantillas en sí mismas.
Salidas
fuente
Prueba esto:
Escribe en classeder.h:
Marque, si trabaja con esto, para escribir este código en main.cpp:
fuente