Estoy aprendiendo acerca de C++ en una clase en este momento y no entiendo muy bien las funciones virtuales puras. Entiendo que luego se describen en una clase derivada, pero ¿por qué querrías declararlo igual a 0 si vas a definirlo en la clase derivada?¿Cuáles son los usos de funciones virtuales puras en C++?
Respuesta
En resumen, es para hacer que la clase sea abstracta, de modo que no se pueda crear una instancia, pero una clase infantil puede anular los métodos virtuales puros para formar una clase concreta. Esta es una buena forma de definir una interfaz en C++.
Recomiendo cambiar: "... una clase infantil puede ..." a "... una clase de hoja debe ...". –
Traté de permanecer intencionalmente vago para permitir la posibilidad de que un niño anule algunos, pero no todos, los métodos virtuales puros, lo que da como resultado una clase base abstracta que requiere menos reemplazos para convertirse en algo concreto. Sin embargo, no lo llamaría una hoja, porque incluso un niño concreto puede tener sus propios hijos, y algunos de ellos pueden ser abstractos. De hecho, una clase puede anular simultáneamente todos los métodos virtuales previamente puros y declarar nuevos. Teniendo en cuenta todo esto, creo que es mejor dejar la explicación original y breve con este comentario largo y tendido. –
El problema probablemente sea solo uno de los términos. En mi humilde opinión, una función solo es puramente virtual si no se ha implementado en una de las clases derivadas. En otras palabras, si una clase en cualquier nivel todavía tiene una función virtual pura, esa clase todavía es abstracta. De ahí mi solicitud. ¡Pero diría que estos comentarios probablemente explican las cosas lo suficiente en este momento! :) –
Esto fuerza a una clase derivada a definir la función.
La idea con las clases abstractas es que todavía puede tener una variable declarada con ese tipo (es decir, es el tipo estático), pero la variable realmente se refiere o apunta a un tipo concreto real (el tipo dinámico).
Cuando invoca un método en C++, el compilador necesita asegurarse de que el método sea compatible con ese objeto.
Al declarar la función virtual pura, está poniendo un "marcador de posición" que el compilador puede usar para decir "oh ... sé que cualquier cosa que termine siendo referida por esta variable aceptará esa llamada" porque el real tipos concretos lo implementarán. Sin embargo, no es necesario que proporcione una implementación en el tipo abstracto.
Si no declaró nada, entonces el compilador no tendría una forma efectiva de garantizar que sería implementado por todos los subtipos.
Por supuesto, si estás preguntando por qué querrías hacer un resumen de clase, hay mucha información al respecto.
Los métodos virtuales puros en C++ son básicamente una forma de definir las interfaces sin necesidad de implementarlas.
Correcto, más precisamente: "una forma de forzar a todos los herederos a seguir la firma definida" –
Para añadir a la respuesta de Steven Sudit:
"En pocas palabras, es para hacer la clase abstracta, por lo que no se pueden crear instancias, pero una clase hija puede anular los métodos virtuales puros para formar una clase concreta. Esta es una buena manera de definir una interfaz en C++ ".
Un ejemplo de esto sería si tuvieras una clase base (quizás Shape) que utilizas para definir un número de funciones miembro que sus clases derivadas pueden usar, pero quieres evitar que se declare una instancia de Shape y forzar a los usuarios utilizar sólo las clases derivadas (que puede ser, rectángulo, triángulo, pentágono, etc.)
RE: la respuesta de Jeff anteriormente
clases no abstracta puede contener funciones miembro virtuales y ser instanciada. De hecho, para sobrecargar las funciones miembro esto es necesario ya que C++ no determina el tipo de tiempo de ejecución de una variable, pero cuando se define utilizando la palabra clave virtual, lo hará.
Considere este código (nota, descriptores de acceso, mutadores, constructores, etc, no están incluidos en aras de la claridad):
class Person{
int age;
public:
virtual void print(){
cout << age <<endl;
}
}
class Student: public Person{
int studentID
public:
void print(){
cout << age << studentID <<endl;
}
}
Ahora cuando se ejecuta este código:
Person p = new Student();
p.print();
sin lo virtual palabra clave, solo se imprimirá la edad, no la edad y el ID del alumno como se supone que suceda para la clase de Estudiante
(este ejemplo se basa en uno muy similar de C++ fo r programadores java http://www.amazon.com/Java-Programmers-Mark-Allen-Weiss/dp/013919424X)
@Steven Sudit: está en lo cierto, olvidé incluir la herencia real, doh! Los accesorios no están incluidos para mantener las cosas más claras, y lo he hecho más obvio ahora. 3-7-09: todo arreglado
Creo que su ejemplo está roto, ya que no incluye la herencia, y no hay forma de establecer los valores de los miembros de datos privados . La idea detrás de esto es correcta, por supuesto. –
Eso es mejor, pero aún no está del todo bien: la clase infantil no debe tener su propio miembro de datos de edad. –
Además, la creación de instancias en la parte inferior carece de paréntesis alrededor del constructor. –
Cualquier clase que contenga un método virtual puro será abstracta, es decir, no se podrá crear una instancia. Las clases abstractas son útiles para definir algunos comportamientos centrales que las subclases deberían compartir, pero que permiten (de hecho, requieren) que las subclases implementen el resumen individualmente.
Un ejemplo de una clase abstracta:
class Foo {
// pure virtual, must be implemented by subclasses
virtual public void myMethod() = 0;
// normal method, will be available to all subclasses,
// but *can* be overridden
virtual public void myOtherMethod();
};
Una clase en la que cada método es abstracto se puede utilizar como una interfaz, requiriendo todas las subclases para ajustarse a la interfaz mediante la aplicación de todos los métodos contenidos en ella.
Un ejemplo de una interfaz:
class Bar {
// all method are pure virtual; subclasses must implement
// all of them
virtual public void myMethod() = 0;
virtual public void myOtherMethod() = 0;
};
Creo que quiso decir que la primera oración es "Cualquier clase que contenga un * método virtual * puro * .... – Dan
Probablemente añadiría que una clase base abstracta puede contener no solo implementaciones de métodos, pero los miembros de datos también. Una interfaz no debería tener ninguno. En C++, esto es solo una convención. En C# o Java, es una regla. –
Imagínese que desea modelar varios tipos de formas, y todas tienen un área bien definida. Decido que cada forma debe heredar IShape
("I" para la interfaz), y IShape
incluirá un método GetArea()
:
class IShape {
virtual int GetArea();
};
Ahora el problema: ¿cómo debo calcular el área de una figura que se forma si no lo hace anular GetArea()
? Es decir, ¿cuál es la mejor implementación predeterminada? Los círculos usan pi * radio^2, los cuadrados usan longitud^2, los paralelogramos y rectángulos usan base * altura, los triángulos usan 1/2 base * altura, rombos, pentágonos, octágonos, etc. usan otras fórmulas.
Así que dicen "si usted es una forma debe definir una forma de calcular el área, pero maldito si sé lo que habrá" definiendo el método virtual pura:
class IShape {
virtual int GetArea() = 0;
};
¿No se debe declarar GetArea virtual en ambos casos? –
Necesita ser declarado virtual en la clase base. Gracias por la corrección. –
En esencia, los virtuales puros se usan para crear una interfaz (similar a java). Esto se puede usar como un acuerdo entre dos módulos (o clases, o lo que sea) en cuanto a qué tipo de funcionalidad esperar, sin tener que saber nada sobre la implementación de la otra pieza. Esto le permite conectar y reproducir fácilmente piezas utilizando la misma interfaz sin tener que cambiar nada en el otro módulo que está utilizando su interfaz.
Por ejemplo:
class IStudent
{
public:
virtual ~IStudent(){};
virtual std::string getName() = 0;
};
class Student : public IStudent
{
public:
std::string name;
std::string getName() { return name; };
void setName(std::string in) { name = in; };
};
class School
{
public:
void sendStudentToDetention(IStudent *in) {
cout << "The student sent to detention is: ";
cout << in->getName() << endl;
};
};
int main()
{
Student student;
student.setName("Dave");
School school;
school.sendStudentToDetention(&student);
return 0;
}
La escuela no tiene que saber cómo configurar el nombre del estudiante, todo lo que necesita saber es cómo obtener el nombre del estudiante.Al proporcionar una interfaz para que los estudiantes implementen y la escuela la use, hay un acuerdo entre las dos piezas sobre qué funcionalidad necesita la escuela para realizar su trabajo. Ahora podemos cambiar todas las implementaciones de la clase de Student sin afectar a la escuela (siempre que implementemos la misma interfaz cada vez).
Sugeriría que el miembro de datos de "nombre" en Estudiante debe ser privado, o al menos estar protegido. También recomendaría pasar al alumno por referencia, no por puntero. Finalmente, una clase de Estudiante del mundo real probablemente tomaría el nombre en su constructor. –
Estoy de acuerdo con todo eso. esos fueron solo descuidos cuando escribí este ejemplo muy rápido. – davidivins
- 1. C++: funciones virtuales privadas, frente a las funciones virtuales puras
- 2. Herencia de diamantes y funciones virtuales puras
- 3. Casos de uso de funciones virtuales puras con el cuerpo?
- 4. ¿Cuáles son todos los usos de '@' en C#?
- 5. ¿Cuáles son los usos de svn copy?
- 6. ¿Cuáles son los usos comunes de UDP?
- 7. ¿Cuáles son los usos de Cross Join?
- 8. ¿Las funciones virtuales no puras con los parámetros son una mala práctica?
- 9. ¿Cuáles son los usos de buffer circular?
- 10. ¿Cuáles son los usos de la construcción C++ "placement new"?
- 11. ¿Cómo pedir una pequeña adición? (sintaxis de funciones virtuales puras)
- 12. ¿Cuáles son los diferentes usos de los [corchetes] en Ruby?
- 13. ¿Cuáles son los buenos usos de los módulos empaquetados OCaml?
- 14. ¿Cuáles son los usos de los tipos polimórficos?
- 15. ¿Cuáles son los usos de las subrutinas lvalue en Perl?
- 16. ¿Cuáles son los usos del predicado de falla en Prolog?
- 17. ¿Las funciones idempotentes son las mismas que las funciones puras?
- 18. Funciones virtuales en constructores, ¿por qué los idiomas son diferentes?
- 19. ¿Qt admite ranuras virtuales puras?
- 20. ¿Cuáles son los usos prácticos del módulo (%) en la programación?
- 21. ¿Cuáles son algunos usos de los metadatos de Clojure?
- 22. ¿Cuáles son algunos de los usos inteligentes de LINQ?
- 23. ¿Cuáles son los mejores usos de las tiendas de documentos?
- 24. ¿Cuáles son algunos usos de los cierres para OOP?
- 25. ¿Cuáles son los usos prácticos de Factory Method Pattern?
- 26. Iron Python: cuáles son los buenos usos de Iron Python
- 27. ¿Cuáles son los usos prácticos de un constructor protegido?
- 28. ¿Cuáles son los usos del código de auto modificación?
- 29. ¿Cuáles son algunos usos interesantes para los agentes de Java?
- 30. funciones virtuales estáticos en C++
Para usted y los pocos que lo votaron: el libro de texto no explicó el POR QUÉ; y como estoy seguro de que alguien más lo buscará en Google, lo pregunté aquí. De esa forma, alguien más puede beneficiarse. – patricksweeney
¿Qué libro de texto fue eso, entonces? Francamente, las respuestas aquí (como es típico para tales preguntas generales) no son particularmente buenas ni precisas. Entonces no sienta que está haciendo un servicio haciendo preguntas como esta. –
puede preguntarse por qué quiere que una clase base sea abstracta. es, entre otras cosas, para controlar el uso de su jerarquía de clases, recuerde que cuando crea clases no solo modela el problema, también necesita tener en cuenta cómo serán utilizadas en el futuro y por otros. –