¿Cuál es la diferencia entre una función abstracta y una función virtual? ¿En qué casos se recomienda usar virtual o abstracto? ¿Cuál es el mejor enfoque?
¿Cuál es la diferencia entre una función abstracta y una función virtual? ¿En qué casos se recomienda usar virtual o abstracto? ¿Cuál es el mejor enfoque?
Respuestas:
Una función abstracta no puede tener funcionalidad. Básicamente estás diciendo que cualquier clase secundaria DEBE dar su propia versión de este método, sin embargo, es demasiado general incluso para tratar de implementarla en la clase principal.
Una función virtual , básicamente es mirar, aquí está la funcionalidad que puede o no ser lo suficientemente buena para la clase secundaria. Entonces, si es lo suficientemente bueno, use este método, si no, luego anúleme y proporcione su propia funcionalidad.
Una función abstracta no tiene implementación y solo puede declararse en una clase abstracta. Esto obliga a la clase derivada a proporcionar una implementación.
Una función virtual proporciona una implementación predeterminada y puede existir en una clase abstracta o en una clase no abstracta.
Así por ejemplo:
public abstract class myBase
{
//If you derive from this class you must implement this method. notice we have no method body here either
public abstract void YouMustImplement();
//If you derive from this class you can change the behavior but are not required to
public virtual void YouCanOverride()
{
}
}
public class MyBase
{
//This will not compile because you cannot have an abstract method in a non-abstract class
public abstract void YouMustImplement();
}
MyBase
clase no tiene que implementar la clase abstracta , de alguna manera? No hago esto a menudo, por lo que podría estar equivocado. No veo eso en tu ejemplo.
abstract
clases pueden tener abstract
miembros.abstract
clase que hereda de una abstract
clase imprescindible override
suabstract
miembros.abstract
miembro es implícitamentevirtual
.abstract
miembro no puede proporcionar ninguna implementación ( abstract
se llama pure virtual
en algunos idiomas).virtual
o no virtual
. Un abstract
miembro (es decir, propiedad abstracta, método abstracto) es como un método virtual, es decir, puede anularlo, excepto que no lleva consigo una implementación predeterminada.
Siempre debe anular una función abstracta.
Así:
Función abstracta:
Función virtual:
Método abstracto: cuando una clase contiene un método abstracto, esa clase debe declararse como abstracta. El método abstracto no tiene implementación y, por lo tanto, las clases que se derivan de esa clase abstracta, deben proporcionar una implementación para este método abstracto.
Método virtual: una clase puede tener un método virtual. El método virtual tiene una implementación. Cuando hereda de una clase que tiene un método virtual, puede anular el método virtual y proporcionar una lógica adicional, o reemplazar la lógica con su propia implementación.
Cuándo usar qué: en algunos casos, sabe que ciertos tipos deberían tener un método específico, pero no sabe qué implementación debería tener este método.
En tales casos, puede crear una interfaz que contenga un método con esta firma. Sin embargo, si tiene ese caso, pero sabe que los implementadores de esa interfaz también tendrán otro método común (para el cual ya puede proporcionar la implementación), puede crear una clase abstracta. Esta clase abstracta contiene el método abstracto (que debe ser anulado) y otro método que contiene la lógica 'común'.
Se debe usar un método virtual si tiene una clase que se puede usar directamente, pero para la cual desea que los herederos puedan cambiar cierto comportamiento, aunque no es obligatorio.
explicación: con analogías espero que te ayude
Contexto
Trabajo en el piso 21 de un edificio. Y estoy paranoico sobre el fuego. De vez en cuando, en algún lugar del mundo, un fuego quema un rascacielos. Pero afortunadamente tenemos un manual de instrucciones en algún lugar aquí sobre qué hacer en caso de incendio:
Salida de incendios()
Esto es básicamente un método virtual llamado FireEscape ()
Método virtual
Este plan es bastante bueno para el 99% de las circunstancias. Es un plan básico que funciona. Pero hay un 1% de posibilidades de que la salida de incendios esté bloqueada o dañada, en cuyo caso está completamente atornillado y se tostará a menos que tome alguna acción drástica. Con los métodos virtuales puede hacer exactamente eso: puede anular el plan básico FireEscape () con su propia versión del plan:
En otras palabras, los métodos virtuales proporcionan un plan básico, que puede ser anulado si es necesario . Las subclases pueden anular el método virtual de la clase padre si el programador lo considera apropiado.
Métodos abstractos
No todas las organizaciones están bien capacitadas. Algunas organizaciones no hacen simulacros de incendio. No tienen una política general de escape. Cada hombre es para sí mismo. La gerencia solo está interesada en tal política existente.
En otras palabras, cada persona se ve obligada a desarrollar su propio método FireEscape (). Un chico saldrá por la escalera de incendios. Otro tipo se lanzará en paracaídas. Otro tipo usará la tecnología de propulsión de cohetes para volar lejos del edificio. Otro chico hará rappel. A la gerencia no le importa cómo se escapa, siempre que tenga un plan básico FireEscape (); si no lo hacen, puede estar seguro de que OHS caerá en la organización como una tonelada de ladrillos. Esto es lo que se entiende por un método abstracto.
¿Cuál es la diferencia entre los dos otra vez?
Método abstracto: las subclases se ven obligadas a implementar su propio método FireEscape. Con un método virtual, tienes un plan básico esperándote, pero puedes elegir implementar el tuyo si no es lo suficientemente bueno.
Ahora que no fue tan difícil, ¿verdad?
Un método abstracto es un método que debe implementarse para hacer una clase concreta. La declaración está en la clase abstracta (y cualquier clase con un método abstracto debe ser una clase abstracta) y debe implementarse en una clase concreta.
Un método virtual es un método que se puede anular en una clase derivada utilizando la anulación, reemplazando el comportamiento en la superclase. Si no anula, obtiene el comportamiento original. Si lo haces, siempre obtienes el nuevo comportamiento. Esto se opone a los métodos no virtuales, que no pueden anularse pero pueden ocultar el método original. Esto se hace usando el new
modificador.
Vea el siguiente ejemplo:
public class BaseClass
{
public void SayHello()
{
Console.WriteLine("Hello");
}
public virtual void SayGoodbye()
{
Console.WriteLine("Goodbye");
}
public void HelloGoodbye()
{
this.SayHello();
this.SayGoodbye();
}
}
public class DerivedClass : BaseClass
{
public new void SayHello()
{
Console.WriteLine("Hi There");
}
public override void SayGoodbye()
{
Console.WriteLine("See you later");
}
}
Cuando hago una instancia DerivedClass
y llamo SayHello
, o SayGoodbye
recibo "Hola" y "Hasta luego". Si llamo HelloGoodbye
, recibo "Hola" y "Hasta luego". Esto se debe a que SayGoodbye
es virtual y se puede reemplazar por clases derivadas. SayHello
solo está oculto, así que cuando llamo a eso desde mi clase base obtengo mi método original.
Los métodos abstractos son implícitamente virtuales. Definen el comportamiento que debe estar presente, más como lo hace una interfaz.
Los métodos abstractos son siempre virtuales. No pueden tener una implementación.
Esa es la principal diferencia.
Básicamente, usaría un método virtual si tiene la implementación 'predeterminada' y desea permitir que los descendientes cambien su comportamiento.
Con un método abstracto, obliga a los descendientes a proporcionar una implementación.
Lo simplifiqué haciendo algunas mejoras en las siguientes clases (de otras respuestas):
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace TestOO
{
class Program
{
static void Main(string[] args)
{
BaseClass _base = new BaseClass();
Console.WriteLine("Calling virtual method directly");
_base.SayHello();
Console.WriteLine("Calling single method directly");
_base.SayGoodbye();
DerivedClass _derived = new DerivedClass();
Console.WriteLine("Calling new method from derived class");
_derived.SayHello();
Console.WriteLine("Calling overrided method from derived class");
_derived.SayGoodbye();
DerivedClass2 _derived2 = new DerivedClass2();
Console.WriteLine("Calling new method from derived2 class");
_derived2.SayHello();
Console.WriteLine("Calling overrided method from derived2 class");
_derived2.SayGoodbye();
Console.ReadLine();
}
}
public class BaseClass
{
public void SayHello()
{
Console.WriteLine("Hello\n");
}
public virtual void SayGoodbye()
{
Console.WriteLine("Goodbye\n");
}
public void HelloGoodbye()
{
this.SayHello();
this.SayGoodbye();
}
}
public abstract class AbstractClass
{
public void SayHello()
{
Console.WriteLine("Hello\n");
}
//public virtual void SayGoodbye()
//{
// Console.WriteLine("Goodbye\n");
//}
public abstract void SayGoodbye();
}
public class DerivedClass : BaseClass
{
public new void SayHello()
{
Console.WriteLine("Hi There");
}
public override void SayGoodbye()
{
Console.WriteLine("See you later");
}
}
public class DerivedClass2 : AbstractClass
{
public new void SayHello()
{
Console.WriteLine("Hi There");
}
// We should use the override keyword with abstract types
//public new void SayGoodbye()
//{
// Console.WriteLine("See you later2");
//}
public override void SayGoodbye()
{
Console.WriteLine("See you later");
}
}
}
La vinculación es el proceso de asignar un nombre a una unidad de código.
El enlace tardío significa que usamos el nombre, pero diferimos el mapeo. En otras palabras, primero creamos / mencionamos el nombre y dejamos que algún proceso posterior maneje la asignación de código a ese nombre.
Ahora considere:
Entonces, la respuesta corta es: virtual
es una instrucción de enlace tardío para la máquina (tiempo de ejecución) mientras que abstract
es una instrucción de enlace tardío para el humano (programador)
En otras palabras, virtual
significa:
"Estimado tiempo de ejecución , vincule el código apropiado a este nombre haciendo lo que mejor sabe hacer: buscar "
Mientras que abstract
significa:
"Estimado programador , enlace el código apropiado a este nombre haciendo lo que mejor sabe hacer: inventar "
En aras de la integridad, la sobrecarga significa:
"Estimado compilador , vincula el código apropiado a este nombre haciendo lo que mejor sabes hacer: ordenar ".
Método virtual :
Virtual significa que podemos anularlo.
La función virtual tiene una implementación. Cuando heredamos la clase, podemos anular la función virtual y proporcionar nuestra propia lógica.
Método abstracto
Resumen significa que DEBEMOS anularlo.
Una función abstracta no tiene implementación y debe estar en una clase abstracta.
Solo se puede declarar. Esto obliga a la clase derivada a proporcionar la implementación de la misma.
Un miembro abstracto es implícitamente virtual. El resumen puede llamarse como virtual puro en algunos de los idiomas.
public abstract class BaseClass
{
protected abstract void xAbstractMethod();
public virtual void xVirtualMethod()
{
var x = 3 + 4;
}
}
He visto en algunos lugares que el método abstracto se define a continuación. ** **
"Un método abstracto debe implementarse en la clase secundaria"
** Sentí que es así.
No es necesario que se implemente un método abstracto en una clase secundaria, si la clase secundaria también es abstracta .
1) Un método abstracto no puede ser un método privado. 2) No se puede implementar un método abstracto en la misma clase abstracta.
Diría que ... si estamos implementando una clase abstracta, debe anular los métodos abstractos de la clase abstracta base. Porque ... La implementación del método abstracto es con la palabra clave de anulación. Similar al método virtual.
No es necesario implementar un método virtual en una clase heredada.
----------CODE--------------
public abstract class BaseClass
{
public int MyProperty { get; set; }
protected abstract void MyAbstractMethod();
public virtual void MyVirtualMethod()
{
var x = 3 + 4;
}
}
public abstract class myClassA : BaseClass
{
public int MyProperty { get; set; }
//not necessary to implement an abstract method if the child class is also abstract.
protected override void MyAbstractMethod()
{
throw new NotImplementedException();
}
}
public class myClassB : BaseClass
{
public int MyProperty { get; set; }
//You must have to implement the abstract method since this class is not an abstract class.
protected override void MyAbstractMethod()
{
throw new NotImplementedException();
}
}
La mayoría de los ejemplos anteriores usan código, y son muy, muy buenos. No necesito agregar a lo que dicen, pero la siguiente es una explicación simple que hace uso de analogías en lugar de códigos / términos técnicos.
Explicación simple - Explicación usando analogías
Método abstracto
Piensa en George W. Bush. Él le dice a sus soldados: "Ve a pelear en Irak". Y eso es. Todo lo que ha especificado es que la lucha debe hacerse. No especifica cómo exactamente sucederá eso. Pero quiero decir, no puedes simplemente salir y "pelear": ¿qué significa eso exactamente? Cómo peleo con un B-52 o mi derringer? Esos detalles específicos se dejan a otra persona. Este es un método abstracto.
Método virtual
David Petraeus está en lo alto del ejército. Él ha definido lo que significa pelear:
El problema es que es un método muy general. Es un buen método que funciona, pero a veces no es lo suficientemente específico. Lo bueno para Petraeus es que sus órdenes tienen margen de maniobra y alcance: ha permitido que otros cambien su definición de "lucha", de acuerdo con sus requisitos particulares.
Private Job Bloggs lee la orden de Petraeus y se le da permiso para implementar su propia versión de lucha, de acuerdo con sus requisitos particulares:
Nouri al Maliki también recibe las mismas órdenes de Petraeus. Él es para pelear también. Pero él es un político, no un hombre de infantería. Obviamente no puede andar disparando a sus enemigos políticos en la cabeza. Debido a que Petraeus le ha dado un método virtual, Maliki puede implementar su propia versión del método de lucha, de acuerdo con sus circunstancias particulares:
En otras palabras, un método virtual proporciona instrucciones repetitivas, pero estas son instrucciones generales, que pueden ser más específicas para las personas de la jerarquía del ejército, de acuerdo con sus circunstancias particulares.
La diferencia entre los dos
George Bush no prueba ningún detalle de implementación. Esto debe ser proporcionado por otra persona. Este es un método abstracto.
Petraeus, por otro lado , proporciona detalles de implementación, pero ha dado permiso a sus subordinados para anular sus órdenes con su propia versión, si pueden llegar a algo mejor.
Espero que ayude.
Función abstracta (método):
● Un método abstracto es un método que se declara con la palabra clave abstract.
● No tiene cuerpo.
● Debe ser implementado por la clase derivada.
● Si un método es abstracto, la clase debería abstraer.
función virtual (método):
● Un método virtual es el método que se declara con la palabra clave virtual y puede ser anulado por el método de clase derivado usando la palabra clave override.
● Depende de la clase derivada si se debe anular o no.
La respuesta se ha proporcionado varias veces, pero la pregunta sobre cuándo usar cada una es una decisión en tiempo de diseño. Consideraría una buena práctica intentar agrupar definiciones de métodos comunes en interfaces distintas y agruparlas en clases en los niveles de abstracción apropiados. Volcar un conjunto común de definiciones de métodos abstractos y virtuales en una clase hace que la clase no se pueda resistir cuando sea mejor definir una clase no abstracta que implemente un conjunto de interfaces concisas. Como siempre, depende de lo que mejor se adapte a las necesidades específicas de sus aplicaciones.
Función abstracta no puede tener un cuerpo y DEBE ser anulada por las clases secundarias
La función virtual tendrá un cuerpo y puede ser anulada o no por las clases secundarias
Desde la vista general orientada a objetos: con
respecto al método abstracto : cuando coloca un método abstracto en la clase principal, en realidad está diciendo a las clases secundarias: Oye, tenga en cuenta que tiene una firma de método como esta. Y si quieres usarlo, ¡debes implementar el tuyo!
Con respecto a la función virtual : cuando coloca un método virtual en la clase principal, le dice a las clases derivadas: Hola, aquí hay una funcionalidad que hace algo por usted. Si esto es útil para usted, simplemente úselo. Si no, anule esto e implemente su código, ¡incluso puede usar mi implementación en su código!
Esta es una filosofía sobre la diferencia entre estos dos conceptos en General OO
Una función abstracta es "solo" una firma, sin una implementación. Se usa en una interfaz para declarar cómo se puede usar la clase. Debe implementarse en una de las clases derivadas.
La función virtual (método en realidad), es una función que usted también declara, y debe implementarse en una de las clases de jerarquía de herencia.
Las instancias heredadas de dicha clase, también heredan la implementación, a menos que la implemente, en una clase de jerarquía inferior.
No hay nada llamado clase virtual en C #.
Para funciones
Puedes decidir con tu requerimiento.
El método abstracto no tiene una implementación. Se declara en la clase padre. La clase secundaria es responsable de implementar ese método.
El método virtual debe tener una implementación en la clase principal y facilita que la clase secundaria elija si usar esa implementación de la clase principal o tener una nueva implementación para sí mismo para ese método en la clase secundaria.
Una función o método abstracto es un "nombre de operación" público expuesto por una clase, su objetivo, junto con las clases abstractas, es principalmente proporcionar una forma de restricción en el diseño de objetos contra la estructura que un objeto tiene que implementar.
De hecho, las clases que heredan de su clase abstracta tienen que dar una implementación a este método, generalmente los compiladores generan errores cuando no lo hacen.
El uso de clases y métodos abstractos es importante principalmente para evitar que al centrarse en los detalles de implementación al diseñar las clases, la estructura de las clases esté demasiado relacionada con las implementaciones, por lo que se crean dependencias y se acoplan las clases que colaboran entre ellas.
Una función o método virtual es simplemente un método que modela el comportamiento público de una clase, pero que podemos dejar libre para modificarlo en la cadena de herencia, porque creemos que las clases secundarias podrían necesitar implementar algunas extensiones específicas para ese comportamiento.
Ambos representan una forma de polimorfismo en el paradigma de orientación a objetos.
Podemos usar métodos abstractos y funciones virtuales juntos para soportar un buen modelo de herencia.
Diseñamos una buena estructura abstracta de los objetos principales de nuestra solución, luego creamos implementaciones básicas localizando aquellas más propensas a futuras especializaciones y las hacemos como virtuales, finalmente especializamos nuestras implementaciones básicas, eventualmente "anulando" las virtuales heredadas.
Aquí estoy escribiendo un código de muestra con la esperanza de que este sea un ejemplo bastante tangible para ver los comportamientos de las interfaces, clases abstractas y clases ordinarias en un nivel muy básico. También puede encontrar este código en github como proyecto si desea usarlo como demostración: https://github.com/usavas/JavaAbstractAndInterfaceDemo
public interface ExampleInterface {
// public void MethodBodyInInterfaceNotPossible(){
// }
void MethodInInterface();
}
public abstract class AbstractClass {
public abstract void AbstractMethod();
// public abstract void AbstractMethodWithBodyNotPossible(){
//
// };
//Standard Method CAN be declared in AbstractClass
public void StandardMethod(){
System.out.println("Standard Method in AbstractClass (super) runs");
}
}
public class ConcreteClass
extends AbstractClass
implements ExampleInterface{
//Abstract Method HAS TO be IMPLEMENTED in child class. Implemented by ConcreteClass
@Override
public void AbstractMethod() {
System.out.println("AbstractMethod overridden runs");
}
//Standard Method CAN be OVERRIDDEN.
@Override
public void StandardMethod() {
super.StandardMethod();
System.out.println("StandardMethod overridden in ConcreteClass runs");
}
public void ConcreteMethod(){
System.out.println("Concrete method runs");
}
//A method in interface HAS TO be IMPLEMENTED in implementer class.
@Override
public void MethodInInterface() {
System.out.println("MethodInInterface Implemented by ConcreteClass runs");
// Cannot declare abstract method in a concrete class
// public abstract void AbstractMethodDeclarationInConcreteClassNotPossible(){
//
// }
}
}
A mi entender:
Métodos abstractos:
Solo la clase abstracta puede contener métodos abstractos. Además, la clase derivada necesita implementar el método y no se proporciona ninguna implementación en la clase.
Métodos virtuales:
Una clase puede declararlos y también proporcionar la implementación de los mismos. Además, la clase derivada debe implementar el método para anularlo.