Enseño una clase de programación C++ y he visto suficientes clases de errores que tengo una buena idea de cómo diagnosticar errores comunes de C++. Sin embargo, hay un tipo importante de error para el cual mi intuición no es particularmente buena: ¿Qué errores de programación causan llamadas a funciones virtuales puras? El error más común que he visto que causa esto es llamar a una función virtual desde un destructor o constructor de clase base. ¿Hay algún otro que deba tener en cuenta a la hora de ayudar a depurar el código del alumno?¿Qué puede causar una llamada de función virtual pura en C++?
Respuesta
"El error más común que he visto que causa esto es llamar a una función virtual desde un destructor o constructor de clase base".
Cuando se construye un objeto, el puntero a la tabla de despacho virtual se dirige inicialmente a la superclase más alta, y solo se actualiza cuando las clases intermedias finalizan la construcción. Por lo tanto, puede llamar accidentalmente a la implementación virtual pura hasta el punto en que una subclase (con su propia implementación de funciones primordiales) complete la construcción. Esa podría ser la subclase más derivada, o cualquier punto intermedio.
Puede suceder si sigue un puntero a un objeto parcialmente construido (por ejemplo, en una condición de carrera debido a operaciones asincrónicas o roscadas).
Si un compilador tiene motivos para pensar que conoce el tipo real al que apunta una puntero-a-base-class, puede omitir razonablemente el despacho virtual. Puede confundirlo haciendo algo con un comportamiento indefinido, como un elenco de reinterpretación.
Durante la destrucción, la tabla de despacho virtual debe revertirse a medida que se destruyen las clases derivadas, por lo que puede invocarse nuevamente la implementación virtual pura.
Después de la destrucción, el uso continuado del objeto mediante punteros "colgantes" o referencias puede invocar la función virtual pura, pero no existe un comportamiento definido en tales situaciones.
En realidad, las llamadas virtuales están deshabilitadas en constructores y destructores - [se explica aquí] (https://isocpp.org/wiki/faq/strange-inheritance#calling-virtuals-from-ctors) - por lo tanto, las llamadas no son virtuales y el enlazador error sucede. Cualquier envío no virtual provocará un error del enlazador. Pero estoy de acuerdo con los objetos parcialmente construidos (o corruptos) cuando la tabla virtual es simplemente incorrecta. Sin embargo, estas situaciones requieren trucos dinámicos que el compilador no ve (subprocesos como se menciona, reinterpretar_cast, etc.). – uvsmtid
@uvsmtid: "En realidad" implica que estás corrigiendo algunas afirmaciones erróneas que hice, pero no mencioné constructores y destructores, solo * construcción * y * destrucción *. La construcción consiste en la inicialización de la clase base y de los miembros de datos no estáticos antes de que se procese la lista de inicialización y el cuerpo del constructor; es casi lo mismo a la inversa durante la destrucción. El envío a funciones virtuales puras puede suceder como se ilustra [aquí] (http://coliru.stacked-crooked.com/a/29b4fa463e39e277), sin enhebrar, async, 'reinterpret_cast' etc. –
Por separado, desde el enlace que proporcione o de lo contrario, no puedo imaginar cómo se manifiestan los errores del enlazador. ¿Podría mostrarme algún código? Tal vez el sitio coliru al que me he vinculado en el comentario anterior, ideone.com o lo que prefiera ... Saludos –
Aquí hay algunos casos en los que puede ocurrir una llamada virtual pura.
- Usando una referencia colgante - el puntero no es de un objeto válido por lo que la tabla virtual al que apunta es sólo la memoria aleatoria que puede contener NULL
- Malo fundido utilizando un
static_cast
a la equivocada tipo (o molde de estilo C) también puede hacer que el objeto al que apunta no tenga los métodos correctos en su tabla virtual (en este caso al menos realmente es una tabla virtual a diferencia de la opción anterior). - DLL se ha descargado - Si el objeto que está aferrándose a fue creado en un archivo objeto compartido (DLL, por lo que, SL), una vez descargado de nuevo la memoria puede ser llevado a cero ahora
Esto puede suceder, por ejemplo, cuando la referencia o el puntero a un objeto apunta a una ubicación NULA, y utiliza la referencia o el puntero del objeto para llamar a una función virtual en la clase. Por ejemplo:
std::vector <DerivedClass> objContainer;
if (!objContainer.empty())
const BaseClass& objRef = objContainer.front();
// Do some processing using objRef and then you erase the first
// element of objContainer
objContainer.erase(objContainer.begin());
const std::string& name = objRef.name();
// -> (name() is a pure virtual function in base class,
// which has been implemented in DerivedClass).
En este punto, el objeto almacenado en objContainer [0] no existe. Cuando la tabla virtual está indexada, no se encuentra una ubicación de memoria válida. Por lo tanto, se emite un error de tiempo de ejecución que dice "función virtual pura llamada".
Sí, lo intenté y me dieron un error "se llamó un método virtual puro". ¿Qué error estás viendo? – cppcoder
El ejemplo está incompleto, por lo que aún no lo reconstruí. Pero como supongo, está llamando a una función virtual para un puntero peligroso, lo intentaré pronto. Por cierto: este es un comportamiento indefinido, por lo que podría bloquearse de una manera diferente. – Wolf
- 1. Llamada de función virtual pura
- 2. Función virtual pura llamada error
- 3. diferencia entre una función virtual y una función virtual pura
- 4. Captura de llamada virtual pura R6025
- 5. función virtual pura C++ tienen cuerpo
- 6. Cómo implementar la función virtual pura en C++
- 7. ¿Dónde se encuentra la función virtual pura en C++?
- 8. ¿En qué circunstancias es ventajoso dar una implementación de una función virtual pura?
- 9. ¿Cuál es el sentido de una función virtual pura privada?
- 10. ¿Cuál es el uso si proporciono una implementación para una función virtual pura en C++
- 11. ¿Cuál es el equivalente de una función pura virtual de C++ en Objective-C?
- 12. Pregunta de clase virtual pura de C++
- 13. ¿Hay alguna manera de "eliminar" una función virtual pura?
- 14. ¿De dónde vienen los bloqueos de la "llamada de función virtual pura"?
- 15. ¿Por qué numCapabilities es una función pura?
- 16. ¿Qué puede causar java.lang.NoClassDefFoundError?
- 17. llamada de función virtual C++ versus boost :: llamada de función speedwise
- 18. sobrecargado llamada de función virtual resolución
- 19. explícitamente determinar qué función pura de usar
- 20. Implementación pura de la función virtual de C++ y archivos de encabezado
- 21. ¿Se utiliza una función de miembro virtual si no es pura?
- 22. redefinir una función no virtual en C++
- 23. pura definición virtual y en línea
- 24. C++ virtual Const Función
- 25. En C++, ¿es una función automáticamente virtual si anula una función virtual?
- 26. clase de Padres C++ llamar a una función virtual niño
- 27. Velocidad de llamada virtual en C# vs C++
- 28. Anular una llamada de función en C
- 29. ¿Hay alguna diferencia entre una función virtual pura privada y protegida?
- 30. ¿Puede jQuery.data causar una pérdida de memoria?
otros quizás llamándolo desde algunas funciones miembro de la clase base, ¿qué más podría estar allí? pero eso no es un error! : | – Nawaz
Eso es realmente lo que mi pregunta es. :-) Puede que no haya otra manera de activar una llamada virtual pura, y mi pregunta principal es si hay o no una. – templatetypedef