Qual é a diferença entre uma função abstrata e uma função virtual? Em quais casos é recomendável usar virtual ou abstrato? Qual é a melhor abordagem?
Qual é a diferença entre uma função abstrata e uma função virtual? Em quais casos é recomendável usar virtual ou abstrato? Qual é a melhor abordagem?
Respostas:
Uma função abstrata não pode ter funcionalidade. Você está basicamente dizendo que qualquer classe filho DEVE fornecer sua própria versão desse método, no entanto, é muito geral para tentar implementar na classe pai.
Uma função virtual , basicamente, está dizendo olha, aqui está a funcionalidade que pode ou não ser boa o suficiente para a classe filho. Portanto, se for bom o suficiente, use esse método, se não, substitua-me e forneça sua própria funcionalidade.
Uma função abstrata não tem implementação e só pode ser declarada em uma classe abstrata. Isso força a classe derivada a fornecer uma implementação.
Uma função virtual fornece uma implementação padrão e pode existir em uma classe abstrata ou em uma classe não abstrata.
Então, por exemplo:
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
classe não precisa implementar a classe abstrata , de alguma forma? Eu não faço isso frequentemente, então posso estar enganado. Não vejo isso no seu exemplo.
abstract
classes podem ter abstract
membros.abstract
classe que herda de uma abstract
classe deve ter override
seus abstract
membros.abstract
membro é implicitamente virtual
.abstract
membro não pode fornecer nenhuma implementação ( abstract
é chamado pure virtual
em alguns idiomas).virtual
ou não virtual
. Um abstract
membro (ou seja, propriedade abstrata, método abstrato) é como um método virtual, ou seja, você pode substituí-lo, exceto que ele não carrega consigo uma implementação padrão.
Você sempre deve substituir uma função abstrata.
Portanto:
Função abstrata:
Função Virtual:
Método abstrato: quando uma classe contém um método abstrato, essa classe deve ser declarada como abstrata. O método abstrato não tem implementação e, portanto, as classes que derivam dessa classe abstrata devem fornecer uma implementação para esse método abstrato.
Método virtual: uma classe pode ter um método virtual. O método virtual tem uma implementação. Ao herdar de uma classe que possui um método virtual, você pode substituir o método virtual e fornecer lógica adicional ou substituir a lógica por sua própria implementação.
Quando usar o quê: Em alguns casos, você sabe que certos tipos devem ter um método específico, mas não sabe qual implementação esse método deve ter.
Nesses casos, você pode criar uma interface que contenha um método com esta assinatura. No entanto, se você tiver esse caso, mas sabe que os implementadores dessa interface também terão outro método comum (para o qual você já pode fornecer a implementação), você pode criar uma classe abstrata. Essa classe abstrata contém o método abstrato (que deve ser substituído) e outro método que contém a lógica 'comum'.
Um método virtual deve ser usado se você tiver uma classe que possa ser usada diretamente, mas para a qual deseja que os herdeiros possam alterar determinado comportamento, embora isso não seja obrigatório.
explicação: com analogias. espero que ajude você.
Contexto
Eu trabalho no 21º andar de um prédio. E eu sou paranóico sobre o fogo. De vez em quando, em algum lugar do mundo, um fogo queima um arranha-céu. Mas, felizmente, temos um manual de instruções em algum lugar aqui sobre o que fazer em caso de incêndio:
Saída de incêndio()
Este é basicamente um método virtual chamado FireEscape ()
Método virtual
Este plano é muito bom para 99% das circunstâncias. É um plano básico que funciona. Mas existe uma chance de 1% de que a escada de incêndio esteja bloqueada ou danificada. Nesse caso, você estará completamente ferrado e ficará torrado, a menos que tome alguma ação drástica. Com métodos virtuais, você pode fazer exatamente isso: você pode substituir o plano básico FireEscape () por sua própria versão do plano:
Em outras palavras, os métodos virtuais fornecem um plano básico, que pode ser substituído, se necessário . As subclasses podem substituir o método virtual da classe pai, se o programador considerar apropriado.
Métodos abstratos
Nem todas as organizações são bem treinadas. Algumas organizações não fazem exercícios de fogo. Eles não têm uma política geral de fuga. Todo homem é para si mesmo. A gerência está interessada apenas na existência dessa política.
Em outras palavras, cada pessoa é forçada a desenvolver seu próprio método FireEscape (). Um cara vai sair pela escada de incêndio. Outro cara vai de pára-quedas. Outro cara usará a tecnologia de propulsão de foguetes para fugir do prédio. Outro cara vai rapel. A gerência não se importa com a maneira como você escapa, desde que você tenha um plano básico FireEscape () - se não o fizerem, você pode ter certeza de que a OHS cairá sobre a organização como uma tonelada de tijolos. É isso que se entende por método abstrato.
Qual é a diferença entre os dois novamente?
Método abstrato: as subclasses são forçadas a implementar seu próprio método FireEscape. Com um método virtual, você tem um plano básico esperando por você, mas pode optar por implementar o seu próprio se não for bom o suficiente.
Agora isso não foi tão difícil, foi?
Um método abstrato é um método que deve ser implementado para criar uma classe concreta. A declaração está na classe abstrata (e qualquer classe com um método abstrato deve ser uma classe abstrata) e deve ser implementada em uma classe concreta.
Um método virtual é um método que pode ser substituído em uma classe derivada usando a substituição, substituindo o comportamento na superclasse. Se você não substituir, você obtém o comportamento original. Se o fizer, você sempre obtém o novo comportamento. Isso é contrário aos métodos não virtuais, que não podem ser substituídos, mas podem ocultar o método original. Isso é feito usando o new
modificador.
Veja o seguinte exemplo:
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");
}
}
Quando instancia DerivedClass
e ligo SayHello
, ou SayGoodbye
recebo "Olá" e "Até mais". Se eu ligar HelloGoodbye
, recebo "Olá" e "Até mais". Isso ocorre porque SayGoodbye
é virtual e pode ser substituído por classes derivadas. SayHello
está apenas oculto; portanto, quando chamo isso da minha classe base, obtenho meu método original.
Métodos abstratos são implicitamente virtuais. Eles definem o comportamento que deve estar presente, mais como uma interface.
Métodos abstratos são sempre virtuais. Eles não podem ter uma implementação.
Essa é a principal diferença.
Basicamente, você usaria um método virtual se tiver a implementação 'padrão' e desejar permitir que os descendentes alterem seu comportamento.
Com um método abstrato, você força os descendentes a fornecer uma implementação.
Simplifiquei isso ao fazer algumas melhorias nas seguintes classes (de outras respostas):
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");
}
}
}
A ligação é o processo de mapear um nome para uma unidade de código.
A associação tardia significa que usamos o nome, mas adiamos o mapeamento. Em outras palavras, criamos / mencionamos o nome primeiro e deixamos que algum processo subsequente lide com o mapeamento de código para esse nome.
Agora considere:
Portanto, a resposta curta é: virtual
é uma instrução de ligação tardia para a máquina (tempo de execução) enquanto que abstract
é a instrução de ligação tardia para o humano (programador)
Em outras palavras, virtual
significa:
"Caro tempo de execução , vincule o código apropriado a esse nome, fazendo o que você faz de melhor: pesquisando "
Considerando que abstract
significa:
"Caro programador , vincule o código apropriado a esse nome, fazendo o que você faz de melhor: inventando "
Por uma questão de exaustividade, sobrecarregar significa:
“Caro compilador , vincule o código apropriado a esse nome, fazendo o que você faz de melhor: classificando ”.
Método virtual :
Virtual significa que podemos substituí-lo.
Função Virtual tem uma implementação. Quando herdamos a classe, podemos substituir a função virtual e fornecer nossa própria lógica.
Método abstrato
Resumo significa que DEVE substituí-lo.
Uma função abstrata não tem implementação e deve estar em uma classe abstrata.
Só pode ser declarado. Isso força a classe derivada a fornecer a implementação dela.
Um membro abstrato é implicitamente virtual. O resumo pode ser chamado como virtual puro em alguns idiomas.
public abstract class BaseClass
{
protected abstract void xAbstractMethod();
public virtual void xVirtualMethod()
{
var x = 3 + 4;
}
}
Já vi em alguns lugares que o método abstrato é definido como abaixo. **
"Um método abstrato deve ser implementado na classe filho"
** Eu senti que é assim.
Não é necessário que um método abstrato seja implementado em uma classe filho, se a classe filho também for abstrata .
1) Um método abstrato não pode ser um método privado. 2) Um método abstrato não pode ser implementado na mesma classe abstrata.
Eu diria ... se estamos implementando uma classe abstrata, você deve substituir os métodos abstratos da classe abstrata base. Porque .. A implementação do método abstrato é feita com a substituição da palavra-chave. Semelhante ao método Virtual.
Não é necessário que um método virtual seja implementado em uma classe herdada.
----------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();
}
}
A maioria dos exemplos acima usa código - e eles são muito, muito bons. Não preciso acrescentar o que eles dizem, mas a seguir é uma explicação simples que utiliza analogias em vez de termos técnicos / de código.
Explicação simples - Explicação usando analogias
Método abstrato
Pense em George W. Bush. Ele diz a seus soldados: "Vá lutar no Iraque". E é isso. Tudo o que ele especificou é que a luta deve ser feita. Ele não especifica como exatamente isso vai acontecer. Mas quero dizer, você não pode simplesmente sair e "brigar": o que isso significa exatamente? eu luto com um B-52 ou meu derringer? Esses detalhes específicos são deixados para outra pessoa. Este é um método abstrato.
Método virtual
David Petraeus está no alto do exército. Ele definiu o que significa luta:
O problema é que é um método muito geral. É um bom método que funciona, mas às vezes não é específico o suficiente. O bom para Petraeus é que suas ordens têm margem de manobra e escopo - ele permitiu que outras pessoas mudassem sua definição de "luta", de acordo com seus requisitos particulares.
O Private Job Bloggs lê a ordem de Petraeus e recebe permissão para implementar sua própria versão da luta, de acordo com seus requisitos particulares:
Nouri al Maliki também recebe as mesmas ordens de Petraeus. Ele também deve lutar. Mas ele é um político, não um homem de infantaria. Obviamente, ele não pode sair por aí atirando na cabeça de seus inimigos políticos. Como Petraeus deu a ele um método virtual, Maliki pode implementar sua própria versão do método de luta, de acordo com suas circunstâncias particulares:
Em outras palavras, um método virtual fornece instruções padrão - mas essas são instruções gerais, que podem ser mais específicas pelas pessoas da hierarquia do exército, de acordo com suas circunstâncias particulares.
A diferença entre os dois
George Bush não prova nenhum detalhe de implementação. Isso deve ser fornecido por outra pessoa. Este é um método abstrato.
Petraeus, por outro lado , fornece detalhes de implementação, mas ele deu permissão para que seus subordinados substituíssem seus pedidos com sua própria versão, se puderem encontrar algo melhor.
espero que ajude.
Função abstrata (método):
● Um método abstrato é um método declarado com a palavra-chave resumo.
● Não possui corpo.
● Deve ser implementado pela classe derivada.
● Se um método é abstrato, a classe deve abstrair.
função virtual (método):
● Um método virtual é o método declarado com a palavra-chave virtual e pode ser substituído pelo método de classe derivada usando a palavra-chave override.
● Cabe à classe derivada substituí-la ou não.
A resposta foi fornecida várias vezes, mas a pergunta sobre quando usar cada uma é uma decisão em tempo de design. Eu consideraria uma boa prática tentar agrupar definições de métodos comuns em interfaces distintas e colocá-las em classes em níveis de abstração apropriados. O despejo de um conjunto comum de definições de métodos abstratos e virtuais em uma classe torna a classe não confiável, quando for melhor definir uma classe não abstrata que implemente um conjunto de interfaces concisas. Como sempre, depende do que melhor se adapte às necessidades específicas de seus aplicativos.
A função abstrata não pode ter um corpo e DEVE ser substituída por classes filho
A Função Virtual terá um corpo e poderá ou não ser substituída por classes filho
Da visão geral orientada a objetos:
Com relação ao método abstrato : Quando você coloca um método abstrato na classe pai, na verdade você está dizendo para as classes filho: Ei, observe que você tem uma assinatura de método como esta. E se você quiser usá-lo, deve implementar o seu!
Em relação à função virtual : Quando você coloca um método virtual na classe pai, está dizendo às classes derivadas: Ei, há uma funcionalidade aqui que faz algo por você. Se isso for útil, basta usá-lo. Caso contrário, substitua isso e implemente seu código, mesmo você pode usar minha implementação em seu código!
esta é uma filosofia sobre diferente entre esses dois conceitos no General OO
Uma função abstrata é "apenas" uma assinatura, sem uma implementação. É usado em uma interface para declarar como a classe pode ser usada. Ele deve ser implementado em uma das classes derivadas.
Função virtual (método realmente), é uma função que você declara também e deve ser implementada em uma das classes de hierarquia de herança.
As instâncias herdadas dessa classe também herdam a implementação, a menos que você a implemente, em uma classe de hierarquia mais baixa.
Não há nada chamado classe virtual em C #.
Para funções
Você pode decidir com sua exigência.
O método abstrato não possui uma implementação. Ele é declarado na classe pai. A classe filho é responsável por implementar esse método.
O método virtual deve ter uma implementação na classe pai e facilita a classe filho a optar por usar essa implementação da classe pai ou ter uma nova implementação para esse método na classe filho.
Uma função ou método abstrato é um "nome de operação" público exposto por uma classe; seu objetivo, juntamente com as classes abstratas, é principalmente fornecer uma forma de restrição no design de objetos em relação à estrutura que um objeto precisa implementar.
De fato, as classes que herdam de sua classe abstrata precisam dar uma implementação a esse método, geralmente os compiladores geram erros quando não o fazem.
O uso de classes e métodos abstratos é importante principalmente para evitar que, concentrando-se nos detalhes da implementação ao projetar classes, a estrutura de classes esteja muito relacionada às implementações, criando assim dependências e acoplamentos entre as classes que colaboram entre elas.
Uma função ou método virtual é simplesmente um método que modela o comportamento público de uma classe, mas que podemos deixá-lo livre para modificá-lo na cadeia de herança, porque pensamos que as classes filho podem precisar implementar algumas extensões específicas para esse comportamento.
Ambos representam uma forma de polimorfismo no paradigma de orientação a objetos.
Podemos usar métodos abstratos e funções virtuais juntos para suportar um bom modelo de herança.
Projetamos uma boa estrutura abstrata dos principais objetos de nossa solução, em seguida, criamos implementações básicas, localizando aquelas mais propensas a especializações adicionais e as tornamos virtuais, finalmente, especializamos nossas implementações básicas, eventualmente "substituindo" as virtuais herdadas.
Aqui estou escrevendo um código de exemplo, esperando que este seja um exemplo bastante tangível para ver os comportamentos das interfaces, classes abstratas e classes comuns em um nível muito básico. Você também pode encontrar esse código no github como um projeto, se quiser usá-lo como uma demonstração: 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(){
//
// }
}
}
Para meu entendimento:
Resumo Métodos:
Somente a classe abstrata pode conter métodos abstratos. Além disso, a classe derivada precisa implementar o método e nenhuma implementação é fornecida na classe.
Métodos virtuais:
Uma classe pode declarar isso e também fornecer a implementação do mesmo. Além disso, a classe derivada precisa implementar o método para substituí-lo.