La palabra clave virtual se utiliza para modificar un método, propiedad, indexador o declaración de evento, y permitir que se anule en una clase derivada. Por ejemplo, este método puede ser reemplazado por cualquier clase que lo herede: use el nuevo modificador para ocultar explícitamente un miembro heredado de una clase base. Para ocultar un miembro heredado, declárelo en la clase derivada con el mismo nombre y modifíquelo con el nuevo modificador.
Todo esto tiene que ver con el polimorfismo. Cuando se llama a un método virtual en una referencia, el tipo real de objeto al que se refiere la referencia se utiliza para decidir qué implementación de método utilizar. Cuando un método de una clase base se reemplaza en una clase derivada, se usa la versión en la clase derivada, incluso si el código de llamada no "sabía" que el objeto era una instancia de la clase derivada. Por ejemplo:
public class Base
{
public virtual void SomeMethod()
{
}
}
public class Derived : Base
{
public override void SomeMethod()
{
}
}
...
Base d = new Derived();
d.SomeMethod();
terminará llamando a Derived.SomeMethod si eso anula Base.SomeMethod.
Ahora, si usa la palabra clave new en lugar de anular , el método de la clase derivada no anula el método de la clase base, simplemente lo oculta. En ese caso, codifique como este:
public class Base
{
public virtual void SomeOtherMethod()
{
}
}
public class Derived : Base
{
public new void SomeOtherMethod()
{
}
}
...
Base b = new Derived();
Derived d = new Derived();
b.SomeOtherMethod();
d.SomeOtherMethod();
Primero llamará Base.SomeOtherMethod, luego Derived.SomeOtherMethod. Son efectivamente dos métodos completamente separados que tienen el mismo nombre, en lugar de que el método derivado anule el método base.
Si no especifica new o overrides, la salida resultante es la misma que si hubiera especificado new, pero también recibirá una advertencia del compilador (ya que es posible que no sepa que está ocultando un método en la clase base método, o de hecho puede haber querido anularlo, y simplemente se olvidó de incluir la palabra clave).
Una declaración de propiedad primordial puede incluir el modificador sellado . El uso de este modificador evita que una clase derivada anule aún más la propiedad. Los accesos de una propiedad sellada también están sellados.
Derived
objeto y almacenando la referencia en unaBase
variable. Esto es válido porque unDerived
objeto también es unBase
objeto. Eso es como decir que necesitamos una "persona" para que tengamos a "Johnny" que resulta ser una persona. Mismo trato aquí.Base b = new Derived()
establece queBase
se puede acceder a una clase a través de unaDerived class
referencia porquederived class
es una especialización de su clase base.Derived
las clases pueden realizar todas las operaciones (por ejemplo, invocar métodos de clase base, etc. ) quebase class
puede hacer. PeroBase class
no puede realizar las operaciones queDerived class
puede hacer. EntoncesDerived d = new Base()
no es correcto peroBase b = new Derived()
es correcto.new
modificador parahide a base class method
? En el segundo ejemplo, la llamadab.SomeOtherMethod()
invoca la implementación de la clase base (se podría decir que ha ocultado el método de la clase derivada). Si ese es un ejemplo típico de uso, entoncesnew
parece que se usa cuando la persona que llama tiene la intención de tener una variable de acompile-time type
para usar su método, y no el método de cualquieraruntime types
que se le pueda asignar.Cualquier método puede ser reemplazable (=
virtual
) o no. La decisión la toma quien define el método:class Person { // this one is not overridable (not virtual) public String GetPersonType() { return "person"; } // this one is overridable (virtual) public virtual String GetName() { return "generic name"; } }
Ahora puede anular los métodos que se pueden anular:
class Friend : Person { public Friend() : this("generic name") { } public Friend(String name) { this._name = name; } // override Person.GetName: public override String GetName() { return _name; } }
Pero no puede anular el
GetPersonType
método porque no es virtual.Creemos dos instancias de esas clases:
Person person = new Person(); Friend friend = new Friend("Onotole");
Cuando
GetPersonType
se llama a un método no virtual porFiend
instancia, en realidadPerson.GetPersonType
se llama:Console.WriteLine(friend.GetPersonType()); // "person"
Cuando
GetName
se llama al método virtual porFriend
instancia,Friend.GetName
se llama:Console.WriteLine(friend.GetName()); // "Onotole"
Cuando
GetName
se llama al método virtual porPerson
instancia,Person.GetName
se llama:Console.WriteLine(person.GetName()); // "generic name"
Cuando se llama a un método no virtual, no se busca el cuerpo del método; el compilador ya conoce el método real que debe llamarse. Mientras que con los métodos virtuales, el compilador no puede estar seguro de cuál llamar, y se busca en el tiempo de ejecución en la jerarquía de clases de abajo hacia arriba, comenzando en el tipo de instancia en la que se llama al método: porque
friend.GetName
parece que comienza en laFriend
clase y lo encuentra de inmediato, para laperson.GetName
clase en que comienzaPerson
y lo encuentra allí.A veces crea una subclase, anula un método virtual y no desea más anulaciones hacia abajo en la jerarquía; lo usa
sealed override
para eso (diciendo que es el último que anula el método):class Mike : Friend { public sealed override String GetName() { return "Mike"; } }
Pero a veces tu amigo Mike decide cambiar su género y, por lo tanto, su nombre a Alice :) Podrías cambiar el código original o subclase Mike:
class Alice : Mike { public new String GetName() { return "Alice"; } }
Aquí crea un método completamente diferente con el mismo nombre (ahora tiene dos). ¿Qué método y cuándo se llama? Depende de cómo lo llames:
Alice alice = new Alice(); Console.WriteLine(alice.GetName()); // the new method is called, printing "Alice" Console.WriteLine(((Mike)alice).GetName()); // the method hidden by new is called, printing "Mike"
Cuando lo llamas desde
Alice
la perspectiva de, llamasAlice.GetName
, cuando desdeMike
, llamasMike.GetName
. Aquí no se realiza ninguna búsqueda en tiempo de ejecución, ya que ambos métodos no son virtuales.Siempre puede crear
new
métodos, ya sea que los métodos que está ocultando sean virtuales o no.Esto también se aplica a las propiedades y eventos: se representan como métodos debajo.
fuente
De forma predeterminada, un método no se puede anular en una clase derivada a menos que se declare
virtual
, oabstract
.virtual
significa verificar implementaciones más nuevas antes de llamar yabstract
significa lo mismo, pero se garantiza que se anulará en todas las clases derivadas. Además, no se necesita implementación en la clase base porque se volverá a definir en otro lugar.La excepción a lo anterior es el
new
modificador. Un método no declaradovirtual
oabstract
puede redefinirse con elnew
modificador en una clase derivada. Cuando se llama al método en la clase base, se ejecuta el método base, y cuando se llama en la clase derivada, se ejecuta el nuevo método. Todo lo que lasnew
palabras clave le permiten hacer es tener dos métodos con el mismo nombre en una jerarquía de clases.Finalmente, un
sealed
modificador rompe la cadena devirtual
métodos y los hace no anulables nuevamente. Esto no se usa con frecuencia, pero la opción está ahí. Tiene más sentido con una cadena de 3 clases cada una derivada de la anteriorsi
A
tiene un métodovirtual
oabstract
, es decir ,overridden
enB
, entonces también puede evitarC
cambiarlo nuevamente declarándolosealed
enB
.sealed
también se usa enclasses
, y ahí es donde comúnmente encontrará esta palabra clave.Espero que esto ayude.
fuente
public class Base { public virtual void SomeMethod() { Console.WriteLine("B"); } } public class Derived : Base { //Same method is written 3 times with different keywords to explain different behaviors. //This one is Simple method public void SomeMethod() { Console.WriteLine("D"); } //This method has 'new' keyword public new void SomeMethod() { Console.WriteLine("D"); } //This method has 'override' keyword public override void SomeMethod() { Console.WriteLine("D"); } }
Ahora lo primero es lo primero
Base b=new Base(); Derived d=new Derived(); b.SomeMethod(); //will always write B d.SomeMethod(); //will always write D
Ahora las palabras clave tienen que ver con el polimorfismo.
Base b = new Derived();
virtual
en la clase base y anular enDerived
dará D (polimorfismo).override
sinvirtual
inBase
dará error.virtual
escribirá 'B' con una advertencia (porque no se realiza ningún polimorfismo).new
antes de ese método simple enDerived
.new
La palabra clave es otra historia, simplemente oculta la advertencia que dice que la propiedad con el mismo nombre está en la clase base.virtual
onew
ambos son iguales excepto el nuevo modificadornew
yoverride
no se puede utilizar antes del mismo método o propiedad.sealed
antes de que cualquier clase o método lo bloquee para usarlo en la clase derivada y da un error de tiempo de compilación.fuente