Quelle est la différence entre une fonction abstraite et une fonction virtuelle? Dans quels cas est-il recommandé d'utiliser virtuel ou abstrait? Laquelle est la meilleure approche?
Quelle est la différence entre une fonction abstraite et une fonction virtuelle? Dans quels cas est-il recommandé d'utiliser virtuel ou abstrait? Laquelle est la meilleure approche?
Réponses:
Une fonction abstraite ne peut pas avoir de fonctionnalité.Vous dites essentiellement que toute classe enfant DOIT donner sa propre version de cette méthode, mais c'est trop général pour même essayer de l'implémenter dans la classe parent.
Une fonction virtuelle , dit essentiellement look, voici les fonctionnalités qui peuvent ou non être assez bonnes pour la classe enfant. Donc, si c'est assez bon, utilisez cette méthode, sinon, remplacez-moi et fournissez vos propres fonctionnalités.
Une fonction abstraite n'a pas d'implémentation et ne peut être déclarée que sur une classe abstraite. Cela force la classe dérivée à fournir une implémentation.
Une fonction virtuelle fournit une implémentation par défaut et elle peut exister sur une classe abstraite ou une classe non abstraite.
Ainsi, par exemple:
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'a- t-elle pas à implémenter la classe abstraite , d'une manière ou d'une autre? Je ne fais pas ça souvent, donc je peux me tromper. Je ne vois pas cela dans votre exemple.
abstract
classes peuvent avoir des abstract
membres.abstract
classe qui hérite d'une abstract
classe doit override
ses abstract
membres.abstract
membre l'est implicitement virtual
.abstract
membre ne peut fournir aucune implémentation ( abstract
est appelé pure virtual
dans certaines langues).virtual
ou non virtual
. Un abstract
membre (c'est-à-dire une propriété abstraite, une méthode abstraite) est comme une méthode virtuelle, c'est-à-dire que vous pouvez la remplacer, sauf qu'elle ne comporte pas avec elle une implémentation par défaut.
Vous devez toujours remplacer une fonction abstraite.
Donc:
Fonction abstraite:
Fonction virtuelle:
Méthode abstraite: lorsqu'une classe contient une méthode abstraite, cette classe doit être déclarée abstraite. La méthode abstraite n'a pas d'implémentation et donc, les classes qui dérivent de cette classe abstraite, doivent fournir une implémentation pour cette méthode abstraite.
Méthode virtuelle: une classe peut avoir une méthode virtuelle. La méthode virtuelle a une implémentation. Lorsque vous héritez d'une classe qui a une méthode virtuelle, vous pouvez remplacer la méthode virtuelle et fournir une logique supplémentaire, ou remplacer la logique par votre propre implémentation.
Quand utiliser quoi? Dans certains cas, vous savez que certains types devraient avoir une méthode spécifique, mais vous ne savez pas quelle implémentation cette méthode devrait avoir.
Dans de tels cas, vous pouvez créer une interface qui contient une méthode avec cette signature. Cependant, si vous avez un tel cas, mais vous savez que les implémenteurs de cette interface auront également une autre méthode commune (pour laquelle vous pouvez déjà fournir l'implémentation), vous pouvez créer une classe abstraite. Cette classe abstraite contient alors la méthode abstraite (qui doit être remplacée) et une autre méthode qui contient la logique «commune».
Une méthode virtuelle doit être utilisée si vous avez une classe qui peut être utilisée directement, mais pour laquelle vous voulez que les héritiers puissent changer certains comportements, bien que ce ne soit pas obligatoire.
explication: avec analogies. j'espère que cela vous aidera.
Le contexte
Je travaille au 21e étage d'un immeuble. Et je suis paranoïaque à propos du feu. De temps en temps, quelque part dans le monde, un feu brûle un gratte-ciel. Mais heureusement, nous avons un manuel d'instructions quelque part ici sur ce qu'il faut faire en cas d'incendie:
Escalier de secours()
Il s'agit essentiellement d'une méthode virtuelle appelée FireEscape ()
Méthode virtuelle
Ce plan est assez bon pour 99% des circonstances. C'est un plan de base qui fonctionne. Mais il y a 1% de chances que l'escalier de secours soit bloqué ou endommagé, auquel cas vous êtes complètement vissé et vous deviendrez grillé à moins que vous ne preniez des mesures drastiques. Avec les méthodes virtuelles, vous pouvez faire exactement cela: vous pouvez remplacer le plan FireEscape () de base par votre propre version du plan:
En d'autres termes, les méthodes virtuelles fournissent un plan de base, qui peut être annulé si nécessaire . Les sous-classes peuvent remplacer la méthode virtuelle de la classe parent si le programmeur le juge approprié.
Méthodes abstraites
Toutes les organisations ne sont pas bien entraînées. Certaines organisations ne font pas d'exercices d'incendie. Ils n'ont pas de politique d'évasion globale. Chaque homme est pour lui-même. La direction ne s'intéresse qu'à une telle politique.
En d'autres termes, chaque personne est obligée de développer sa propre méthode FireEscape (). Un gars sortira de l'escalier de secours. Un autre gars va parachuter. Un autre gars utilisera la technologie de propulsion des fusées pour s'éloigner du bâtiment. Un autre gars va descendre en rappel. La direction ne se soucie pas de la façon dont vous vous échappez, tant que vous avez un plan FireEscape () de base - si ce n'est pas le cas, vous pouvez être assuré que la SST tombera sur l'organisation comme une tonne de briques. C'est ce que l'on entend par une méthode abstraite.
Quelle est encore la différence entre les deux?
Méthode abstraite: les sous-classes sont obligées d'implémenter leur propre méthode FireEscape. Avec une méthode virtuelle, vous avez un plan de base qui vous attend, mais pouvez choisir de mettre en œuvre le vôtre s'il n'est pas assez bon.
Maintenant, ce n'était pas si difficile, n'est-ce pas?
Une méthode abstraite est une méthode qui doit être implémentée pour créer une classe concrète. La déclaration est dans la classe abstraite (et toute classe avec une méthode abstraite doit être une classe abstraite) et elle doit être implémentée dans une classe concrète.
Une méthode virtuelle est une méthode qui peut être remplacée dans une classe dérivée à l'aide du remplacement, remplaçant le comportement dans la superclasse. Si vous ne remplacez pas, vous obtenez le comportement d'origine. Si vous le faites, vous obtenez toujours le nouveau comportement. Cela s'oppose aux méthodes non virtuelles, qui ne peuvent pas être remplacées mais peuvent masquer la méthode d'origine. Cela se fait à l'aide du new
modificateur.
Voir l'exemple suivant:
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");
}
}
Lorsque j'instancie DerivedClass
et que j'appelle SayHello
, ou SayGoodbye
, je reçois "Salut" et "A plus tard". Si j'appelle HelloGoodbye
, je reçois "Bonjour" et "A plus tard". En effet, il SayGoodbye
est virtuel et peut être remplacé par des classes dérivées. SayHello
est seulement caché, donc quand j'appelle ça depuis ma classe de base, j'obtiens ma méthode d'origine.
Les méthodes abstraites sont implicitement virtuelles. Ils définissent un comportement qui doit être présent, plus comme une interface.
Les méthodes abstraites sont toujours virtuelles. Ils ne peuvent pas avoir d'implémentation.
Voilà la principale différence.
Fondamentalement, vous utiliseriez une méthode virtuelle si vous en avez l'implémentation par défaut et que vous souhaitez autoriser les descendants à modifier son comportement.
Avec une méthode abstraite, vous forcez les descendants à fournir une implémentation.
J'ai simplifié cela en apportant quelques améliorations aux classes suivantes (à partir d'autres réponses):
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 liaison est le processus de mappage d'un nom à une unité de code.
La liaison tardive signifie que nous utilisons le nom, mais reportons le mappage. En d'autres termes, nous créons / mentionnons d'abord le nom et laissons un processus ultérieur gérer le mappage du code avec ce nom.
Considérez maintenant:
Donc, la réponse courte est: virtual
est une instruction de liaison tardive pour la machine (runtime) alors que abstract
est l'instruction de liaison tardive pour l'humain (programmeur)
En d'autres termes, virtual
signifie:
"Cher runtime , liez le code approprié à ce nom en faisant ce que vous faites le mieux: la recherche "
Alors que abstract
signifie:
"Cher programmeur , veuillez lier le code approprié à ce nom en faisant ce que vous faites le mieux: inventer "
Par souci d'exhaustivité, la surcharge signifie:
"Cher compilateur , liez le code approprié à ce nom en faisant ce que vous faites le mieux: le tri ".
Vous utilisez essentiellement une méthode virtuelle lorsque vous souhaitez que les héritiers étendent les fonctionnalités s'ils le souhaitent.
Vous utilisez des méthodes abstraites lorsque vous souhaitez que les héritiers implémentent la fonctionnalité (et dans ce cas, ils n'ont pas le choix)
Méthode virtuelle :
Virtuel signifie que nous POUVONS l'emporter.
Virtual Function a une implémentation. Lorsque nous héritons de la classe, nous pouvons remplacer la fonction virtuelle et fournir notre propre logique.
Méthode abstraite
Abstrait signifie que nous devons le remplacer.
Une fonction abstraite n'a pas d'implémentation et doit être dans une classe abstraite.
Elle ne peut être déclarée. Cela oblige la classe dérivée à en fournir l'implémentation.
Un membre abstrait est implicitement virtuel. L'abrégé peut être qualifié de pur virtuel dans certaines langues.
public abstract class BaseClass
{
protected abstract void xAbstractMethod();
public virtual void xVirtualMethod()
{
var x = 3 + 4;
}
}
J'ai vu à certains endroits la méthode abstraite est définie comme ci-dessous. **
"Une méthode abstraite doit avoir à implémenter dans la classe enfant"
** J'ai senti que c'était comme.
Il n'est pas nécessaire qu'une méthode abstraite soit implémentée dans une classe enfant, si la classe enfant est également abstraite .
1) Une méthode abstraite ne peut pas être une méthode privée. 2) Une méthode abstraite ne peut pas être mise en œuvre dans la même classe abstraite.
Je dirais que si nous implémentons une classe abstraite, vous devez remplacer les méthodes abstraites de la classe abstraite de base. Parce que .. L'implémentation de la méthode abstraite est avec un mot clé de remplacement .Similaire à la méthode virtuelle.
Il n'est pas nécessaire qu'une méthode virtuelle soit implémentée dans une classe héritée.
----------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 plupart des exemples ci-dessus utilisent du code - et ils sont très très bons. Je n'ai pas besoin d'ajouter à ce qu'ils disent, mais ce qui suit est une explication simple qui utilise des analogies plutôt que des codes / termes techniques.
Explication simple - Explication utilisant des analogies
Méthode abstraite
Pensez à George W. Bush. Il dit à ses soldats: "Allez combattre en Irak". Et c'est tout. Tout ce qu'il a précisé, c'est que les combats doivent être faits. Il ne précise pas exactement comment cela se produira. Mais je veux dire, vous ne pouvez pas simplement sortir et "combattre": qu'est-ce que cela signifie exactement? dois-je me battre avec un B-52 ou mon derringer? Ces détails spécifiques sont laissés à quelqu'un d'autre. Il s'agit d'une méthode abstraite.
Méthode virtuelle
David Petraeus est haut placé dans l'armée. Il a défini ce que signifie le combat:
Le problème est que c'est une méthode très générale. C'est une bonne méthode qui fonctionne, mais qui n'est parfois pas assez spécifique. Une bonne chose pour Petraeus est que ses ordres ont une marge de manœuvre et une portée - il a permis à d'autres de changer sa définition de "combat", selon leurs exigences particulières.
Private Job Bloggs lit l'ordre de Petraeus et est autorisé à implémenter sa propre version de combat, selon ses besoins particuliers:
Nouri al Maliki reçoit également les mêmes ordres de Petraeus. Il doit aussi se battre. Mais c'est un homme politique, pas un fantassin. De toute évidence, il ne peut pas tirer sur ses ennemis politiques dans la tête. Parce que Petraeus lui a donné une méthode virtuelle, Maliki peut implémenter sa propre version de la méthode de combat, selon ses circonstances particulières:
En d'autres termes, une méthode virtuelle fournit des instructions standard, mais ce sont des instructions générales, qui peuvent être précisées par des personnes de la hiérarchie militaire, en fonction de leur situation particulière.
La différence entre les deux
George Bush ne prouve aucun détail de mise en œuvre. Cela doit être fourni par quelqu'un d'autre. Il s'agit d'une méthode abstraite.
Petraeus d'autre part ne fournir des détails de mise en œuvre , mais il a donné l' autorisation de ses subordonnés de passer outre ses ordres avec leur propre version, si elles peuvent venir avec quelque chose de mieux.
J'espère que cela pourra aider.
Fonction abstraite (méthode):
● Une méthode abstraite est une méthode qui est déclarée avec le mot clé abstract.
● Il n'a pas de corps.
● Il doit être implémenté par la classe dérivée.
● Si une méthode est abstraite, la classe doit être abstraite.
fonction virtuelle (méthode):
● Une méthode virtuelle est la méthode qui est déclarée avec le mot clé virtual et elle peut être remplacée par la méthode de classe dérivée à l'aide du mot clé override.
● Il appartient à la classe dérivée de la remplacer ou non.
La réponse a été fournie à plusieurs reprises, mais la question de savoir quand les utiliser est une décision au moment de la conception. Je considérerais comme une bonne pratique d'essayer de regrouper les définitions de méthodes communes dans des interfaces distinctes et de les regrouper en classes aux niveaux d'abstraction appropriés. Le vidage d'un ensemble commun de définitions de méthodes abstraites et virtuelles dans une classe rend la classe impossible à établir quand il peut être préférable de définir une classe non abstraite qui implémente un ensemble d'interfaces concises. Comme toujours, cela dépend de ce qui convient le mieux aux besoins spécifiques de vos applications.
La fonction abstraite ne peut pas avoir de corps et DOIT être remplacée par les classes enfants
La fonction virtuelle aura un corps et pourra ou non être remplacée par les classes enfants
De la vue orientée objet générale:
Concernant la méthode abstraite : Lorsque vous mettez une méthode abstraite dans la classe parent, vous dites en fait aux classes enfants: Hé, notez que vous avez une signature de méthode comme celle-ci. Et si vous voulez l'utiliser, vous devez implémenter le vôtre!
Concernant la fonction virtuelle : Lorsque vous mettez une méthode virtuelle dans la classe parent, vous dites aux classes dérivées: Hé, il y a une fonctionnalité ici qui fait quelque chose pour vous. Si cela vous est utile, utilisez-le. Sinon, remplacez cela et implémentez votre code, même vous pouvez utiliser mon implémentation dans votre code!
ceci est une philosophie sur différent entre ces deux concept dans General OO
Une fonction abstraite est "juste" une signature, sans implémentation. Il est utilisé dans une interface pour déclarer comment la classe peut être utilisée. Il doit être implémenté dans l'une des classes dérivées.
La fonction virtuelle (méthode en fait) est une fonction que vous déclarez également et qui doit être implémentée dans l'une des classes de hiérarchie d'héritage.
Les instances héritées d'une telle classe héritent également de l'implémentation, sauf si vous l'implémentez, dans une classe de hiérarchie inférieure.
Il n'y a rien d'appel de classe virtuelle en C #.
Pour les fonctions
Vous pouvez décider avec votre condition.
La méthode abstraite n'a pas d'implémentation, elle est déclarée dans la classe parente. La classe enfant est responsable de l'implémentation de cette méthode.
La méthode virtuelle doit avoir une implémentation dans la classe parent et elle facilite la classe enfant pour faire le choix d'utiliser cette implémentation de la classe parent ou d'avoir une nouvelle implémentation pour elle-même pour cette méthode dans la classe enfant.
Une fonction ou une méthode abstraite est un "nom d'opération" public exposé par une classe, son but, avec les classes abstraites, est principalement de fournir une forme de contrainte dans la conception d'objets par rapport à la structure qu'un objet doit implémenter.
En fait, les classes qui héritent de sa classe abstraite doivent donner une implémentation à cette méthode, généralement les compilateurs génèrent des erreurs quand ils ne le font pas.
L'utilisation de classes et de méthodes abstraites est importante surtout pour éviter qu'en se concentrant sur les détails d'implémentation lors de la conception des classes, la structure des classes soit trop liée aux implémentations, créant ainsi des dépendances et un couplage entre les classes qui collaborent entre elles.
Une fonction ou méthode virtuelle est simplement une méthode qui modélise un comportement public d'une classe, mais que nous pouvons laisser libre de le modifier dans la chaîne d'héritage, car nous pensons que les classes enfants pourraient avoir besoin d'implémenter des extensions spécifiques pour ce comportement.
Ils représentent tous deux une forme de polymorphe dans le paradigme d'orientation d'objet.
Nous pouvons utiliser des méthodes abstraites et des fonctions virtuelles ensemble pour prendre en charge un bon modèle d'héritage.
Nous concevons une bonne structure abstraite des principaux objets de notre solution, puis créons des implémentations de base en localisant celles plus sujettes à d'autres spécialisations et nous les rendons virtuelles, enfin nous spécialisons nos implémentations de base, éventuellement «écrasantes» les héritées virtuelles.
Ici, j'écris un exemple de code en espérant que cela puisse être un exemple assez tangible pour voir les comportements des interfaces, des classes abstraites et des classes ordinaires à un niveau très basique. Vous pouvez également trouver ce code dans github en tant que projet si vous souhaitez l'utiliser comme démo: 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(){
//
// }
}
}
À ma connaissance:
Méthodes abstraites:
Seule la classe abstraite peut contenir des méthodes abstraites. La classe dérivée doit également implémenter la méthode et aucune implémentation n'est fournie dans la classe.
Méthodes virtuelles:
Une classe peut les déclarer et fournir également leur implémentation. La classe dérivée doit également implémenter la méthode pour la remplacer.