Creo que la implementación de la función virtual se habla mucho. Mi pregunta es ¿qué hay de la función virtual pura? Sin embargo, se implementa? En la tabla virtual, ¿cómo decirlo es puro o no puro? ¿Cuál es la diferencia entre la función virtual pura y la función virtual con la implementación?Cómo implementar la función virtual pura en C++
Respuesta
Normalmente no hay diferencia de implementación entre las funciones virtuales puras y no puras. Siempre que se defina una función puramente virtual, actúa como cualquier otra función virtual. Si no está definido, solo causa un problema si se llama explícitamente.
Existen dos grandes diferencias en el comportamiento, pero generalmente no hay impacto en la implementación del mecanismo de función virtual en sí. El compilador no debe permitirle construir un objeto de un tipo que tenga funciones virtuales puras que no tengan una anulación final no pura en su jerarquía de herencia y cualquier intento de realizar una llamada virtual a una función virtual pura, directa o indirectamente desde el constructor o destructor de un objeto causa un comportamiento indefinido.
Es un comportamiento indefinido si se llama virtualmente. Si la función tiene una implementación, se puede llamar con el formato 'AbstractBase :: Foo()'. –
Si no está definido, ¿tiende a obtener un error de enlazador si intenta llamarlo explícitamente? - Pero, ¿cómo se puede llamar de manera virtual, si no se puede tener una instancia de tipo abstracto? – UncleBens
@UncleBens: No sé, solo estaba parafraseando parte de 10.4 del Estándar. –
No sé la implementación real, pero una buena opción sería implementarla como un puntero NULL
en el vtable
. En otras palabras, si tiene una implementación, hay un puntero de función válido en vtable
y si es puramente virtual, tiene un puntero NULL
.
Esto es tan lógico que incluso creo que es implementado de esta manera :-).
pero la función virtual pura todavía puede tener implementación, ¿verdad? – skydoor
Una función virtual pura no puede tener una implementación en la clase que la declara; de lo contrario, por definición, no es una función virtual pura. Tiene que ser implementado en clases derivadas. – codenheim
@skydoor: Sí, puede, pero la implementación tiene que ser llamada específicamente. Aún evitará que la clase en la que está se declare un objeto (y todas las subclases que no anulen la virtual pura). –
virtual void foo() = 0;
Una función virtual pura sigue siendo una función virtual, por lo que estaría en el vtable, pero el compilador no requiere una implementación para él, y prohibirá la creación de instancias de la clase base que declara el virtual puro. Como todavía puede desreferenciar los punteros de tipo de la clase base abstracta, la tabla virtual debe tener una entrada para el polimorfismo y el enlace de tiempo de ejecución.
¿Eso ayuda?
Declarar una función virtual pura hace que se agregue una entrada para la función en el vtable. En la clase que declara la función virtual pura (y en las clases derivadas que no la anulan), la mayoría de las implementaciones configuran esta entrada para invocar algún tipo de función de diagnóstico que muestre algún mensaje de error (por ejemplo, "Error: función virtual pura llamada "). Todavía es posible definir una función virtual pura, pero debe invocarse de forma no virtual. –
Oh, tienes razón. Gracias. Una función virtual pura también puede tener una definición en la clase base. +1 para su corrección. – codenheim
Esta no es una respuesta, sino más bien una continuación de los comentarios a this answer above
El lenguaje C++ define cómo funciona el mecanismo de despacho virtual se lleva a cabo durante la construcción. Al crear instancias de un objeto en una jerarquía, se llama al constructor base (*). En ese punto, el mecanismo de despacho virtual se inicializa para la clase base. En esta etapa, las funciones virtuales se enviarán a la implementación base. Cualquier llamada a un método virtual no puro que utilice el mecanismo de despacho virtual (sin calificación explícita de clase) llamará a la implementación base.
Después de que se complete el constructor base, el mecanismo de expedición virtual (por lo general vtable) se reseted a la versión tipo derivado, y cualquier llamada dinámica a partir de ahí se llame a la versión derivada de los métodos:
struct base {
virtual void non_pure() { std::cout << "base::non_pure" << std::endl; }
virtual void pure_not_implemented() = 0;
virtual void pure_implemented() = 0;
base() { // at this point the object is a ´base´
non_pure(); // base::non_pure
// pure_not_implemented(); // runtime error: pure virtual method called
pure_implemented(); // base::pure_implemented
// base::pure_not_implemented(); // link error
}
};
void base::pure_implemented() { std::cout << "base::pure_implemented" << std::endl; }
struct derived : base {
virtual void non_pure() { std::cout << "derived::non_pure" << std::endl; }
virtual void pure_not_implemented() { std::cout << "derived::pure_not_implemented" << std::endl; }
virtual void pure_implemented() { std::cout << "derived::pure_implemented" << std::endl;
derived() { // after the implicit call to the base class
// this is a ´derived´ object, now calls will
// get dispatched to derived:: implementations
non_pure(); // derived::non_pure
pure_not_implemented(); // derived::pure_not_implemented
pure_implemented(); // derived::pure_implemented
base::non_pure(); // base::non_pure
// base::pure_not_implemented() // link error
}
};
Tenga en cuenta que existen diferencias entre utilizar el mecanismo de despacho dinámico (generalmente, vtable) y llamar a un método específico con el nombre completo. Se permitirá una llamada a un método virtual puro no implementado a través de la calificación completa en tiempo de compilación, pero fallará en el momento del enlace (el vinculador no puede encontrar una implementación para llamar).
Esta es una decisión importante en el diseño del idioma. La otra opción (la que tomó Java) es inicializar el mecanismo de despacho virtual al tipo más derivado desde el principio, antes de llamar al constructor de la clase base.El problema que tiene este enfoque es que si el constructor base llama a un método virtual (que en Java son todos) se enviará a la implementación más derivada y se ejecutará en un objeto aún no construido, posiblemente causando resultados inesperados:
public class Base
{
public Base() {
f();
}
public void f() {
System.out.println("Base.f");
}
}
public class Derived extends Base {
public final int constant;
public Derived() { constant = 5; }
public void f() {
System.out.println("Derived.f() " + constant);
}
public static void main(String args[]) {
Derived d = new Derived(); // prints Derived.f() 0
}
}
En la versión de Java, el mecanismo de envío dinámico considera que el objeto es del tipo Derived
desde el principio. La llamada al f()
en el constructor base se enviará dinámicamente a la implementación derivada. En el ejemplo anterior, incluso si la variable se declara como final y por lo tanto una constante por el valor de 5 (parece obvio en el código), el valor impreso real es 0 porque el constructor de Derived
no se ha ejecutado.
(*) Esto es demasiado simplista, pero los detalles en realidad no afectan el argumento.
Realmente me preguntaba por qué llamar a un virtual puro desde el constructor sería un comportamiento indefinido, pero llamar a uno no puro no lo sería. Específicamente, ¿sería tan difícil de detectar para los compiladores? Si no se desea realizar una llamada a una función pura (por el motivo que sea), ¿por qué no necesita el diagnóstico del compilador? – UncleBens
Llamar a una llamada de método virtual no pura tendrá el efecto de llamar a la implementación más derivada e incluir el tipo actual, pero no de sus descendientes. El efecto de llamar a un método virtual puro no está definido ya que podría depender del mecanismo de envío. La mayoría de los compiladores llamará al código sintetizado para diagnosticar y matar la aplicación con un mensaje sensato. –
En el punto donde el compilador está procesando el constructor puede saber si es un método virtual puro implementado (si puede ver la definición), pero no puede garantizar que el método virtual puro no se implemente en una unidad de traducción diferente (tal vez su constructor está subrayado en la declaración de clase y se está incluyendo desde una unidad de traducción, mientras que el método virtual puro se define en una unidad de traducción diferente) –
- 1. función virtual pura C++ tienen cuerpo
- 2. Llamada de función virtual pura
- 3. ¿Dónde se encuentra la función virtual pura en C++?
- 4. Función virtual pura llamada error
- 5. diferencia entre una función virtual y una función virtual pura
- 6. Pregunta de clase virtual pura de C++
- 7. Implementación pura de la función virtual de C++ y archivos de encabezado
- 8. ¿Cuál es el equivalente de una función pura virtual de C++ en Objective-C?
- 9. ¿Cuál es el sentido de una función virtual pura privada?
- 10. Captura de llamada virtual pura R6025
- 11. ¿Hay alguna manera de "eliminar" una función virtual pura?
- 12. ¿Qué puede causar una llamada de función virtual pura en C++?
- 13. pura definición virtual y en línea
- 14. ¿Cuál es el uso si proporciono una implementación para una función virtual pura en C++
- 15. Herencia virtual pura, herencia múltiple, y C4505
- 16. C++ virtual Const Función
- 17. Denominación de la función `pura` en Control.Applicative
- 18. Cómo aplicar la función virtual en javascript
- 19. ¿En qué circunstancias es ventajoso dar una implementación de una función virtual pura?
- 20. ¿De dónde vienen los bloqueos de la "llamada de función virtual pura"?
- 21. Comportamiento de función virtual en C++
- 22. ¿Cómo anular la función virtual con buen estilo? [C++]
- 23. ¿Cómo implementar la función getch() de C en Linux?
- 24. función virtual en línea
- 25. redefinir una función no virtual en C++
- 26. ¿Se utiliza una función de miembro virtual si no es pura?
- 27. C++, base virtual abstracta protegida virtual virtual privado destructor
- 28. ¿Cómo implementar la función recordarme?
- 29. C++: Llamar a la función virtual de la clase derivada
- 30. clase de Padres C++ llamar a una función virtual niño
http://stackoverflow.com/questions/2156634/why-pure-virtual-function-is-initialized-by-0 –