web-dev-qa-db-fra.com

Quelle est la différence entre une fonction abstraite et une fonction virtuelle?

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? 

1406
Moran Helman

Une fonction abstraite ne peut pas avoir de fonctionnalité. En gros, vous dites que chaque classe enfant DOIT donner sa propre version de cette méthode, cependant c'est trop général pour même essayer d'implémenter dans la classe parent. 

Une fonction virtuelle , dit fondamentalement look, voici la fonctionnalité qui peut ne pas être suffisante pour la classe enfant. Donc, si elle est suffisante, utilisez cette méthode, sinon, remplacez-moi et fournissez vos propres fonctionnalités.

2477
BFree

Une fonction abstraite n'a pas d'implémentation et ne peut être déclarée que sur une classe abstraite. Cela oblige la classe dérivée à fournir une implémentation. Une fonction virtuelle fournit une implémentation par défaut et peut exister sur une classe abstraite ou sur une classe non abstraite. Donc 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();
}
264
JoshBerke
  1. Seules les classes abstract peuvent avoir des membres abstract.
  2. Une classe non -abstract qui hérite d'une abstract classe doit override ses abstract membres.
  3. Un membre abstract est implicitement virtual.
  4. Un membre abstract ne peut fournir aucune implémentation (abstract est appelé pure virtual dans certaines langues).
75
Mehrdad Afshari

Vous devez toujours remplacer une fonction abstraite.

Ainsi:

  • Fonctions abstraites - lorsque l'héritier doit fournir sa propre implémentation
  • Virtuel - Quand C'est à l'héritier de décider
57
Rinat Abdullin

Fonction abstraite:

  1. Il ne peut être déclaré que dans une classe abstraite. 
  2. Il ne contient que la déclaration de méthode Pas l'implémentation dans la classe abstraite. 
  3. Il doit être remplacé dans la classe dérivée.

Fonction virtuelle:

  1. Il peut être déclaré dans une classe abstraite ou non abstraite.
  2. Il contient l'implémentation de la méthode.
  3. Il peut être annulé.
34
Lexnim

Méthode abstraite: Lorsqu'une classe contient une méthode abstraite, cette classe doit être déclarée comme étant abstraite . La méthode abstraite n'a pas d'implémentation et les classes dérivées de cette classe abstraite doivent donc 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 ayant une méthode virtuelle, vous pouvez remplacer la méthode virtuelle et fournir une logique supplémentaire, ou la remplacer 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 ce cas, vous pouvez créer une interface contenant une méthode portant cette signature . Toutefois, si vous avez un tel cas, mais vous savez que les implémenteurs de cette interface auront également une autre méthode commune 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 contenant 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 souhaitez que les héritiers puissent modifier certains comportements, même si ce n'est pas obligatoire.

29
Frederik Gheysels

explication: avec des analogies. j'espère que cela vous aidera.

Le contexte

Je travaille au 21 e é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 la marche à suivre en cas d’incendie:

Escalier de secours()

  1. Ne ramassez pas vos affaires
  2. Marche pour échapper au feu
  3. Sortir de l'immeuble

Il s’agit 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'évacuation en cas d'incendie soit bloquée ou endommagée, auquel cas vous êtes complètement foutu et vous deviendrez du pain grillé à moins que vous ne preniez des mesures radicales. Avec les méthodes virtuelles, vous pouvez le faire: vous pouvez remplacer le plan de base de FireEscape () par votre propre version du plan:

  1. Courir à la fenêtre
  2. Sauter par la fenêtre
  3. Parachute en toute sécurité vers le bas

En d'autres termes, les méthodes virtuelles fournissent un plan de base, qui peut être remplacé si nécessaire. Les sous-classes peuvent remplacer la méthode virtuelle de la classe parente si le programmeur le juge approprié.

Méthodes abstraites

Toutes les organisations ne sont pas bien foré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 existante.

En d'autres termes, chaque personne est forcée développer sa propre méthode FireEscape (). Un gars va sortir de la sortie de secours. Un autre gars va parachuter. Un autre gars utilisera la technologie de propulsion de fusée pour voler loin du bâtiment. Un autre gars va descendre en rappel. La direction s'en moque comment vous vous échappez, tant que vous disposez d'un plan FireEscape () de base; sinon, vous pouvez être assuré que la santé et la sécurité au travail résulteront en une tonne de briques. C'est ce que l'on entend par méthode abstraite. 

Quelle est la différence entre les deux encore?

Méthode abstraite: les sous-classes sontforcéespour implémenter leur propre méthode FireEscape. Avec une méthode virtuelle, un plan de base vous attend, mais vous pouvez choisir pour mettre en œuvre le vôtre si ce n’est pas suffisant.

Maintenant, ce n'était pas si difficile, n'est-ce pas?

25
BKSpurgeon

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 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 en utilisant le remplacement, en remplaçant le comportement de la superclasse. Si vous ne remplacez pas, vous obtenez le comportement d'origine. Si vous le faites, vous obtenez toujours le nouveau comportement. Ceci est opposé aux méthodes non virtuelles, qui ne peuvent pas être remplacées mais peuvent masquer la méthode originale. Ceci est fait en utilisant le modificateur new.

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 là-bas" et "À plus tard". Si j'appelle HelloGoodbye, j'obtiens "Bonjour" et "À plus tard". En effet, 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 originale.

Les méthodes abstraites sont implicitement virtuelles. Ils définissent un comportement qui doit être présent, plus exactement comme une interface.

22
Kamiel Wanrooij

Les méthodes abstraites sont toujours virtuelles. Ils ne peuvent pas avoir une implémentation.

C'est la principale différence.

Fondamentalement, vous utiliseriez une méthode virtuelle si vous avez l'implémentation 'par défaut' de celle-ci et souhaitez autoriser les descendants à modifier son comportement.

Avec une méthode abstraite, vous forcez les descendants à fournir une implémentation.

10
Rashack

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");
        }
    }
}
10
MeqDotNet

Liaison est le processus de mappage d'un nom sur une unité de code.

Liaison tardive signifie que nous utilisons le nom mais différons le mappage. En d’autres termes, nous créons/mentionnons d’abord le nom, et nous laissons un processus ultérieur gérer le mappage du code avec ce nom.

Considérons maintenant:

  • Par rapport aux humains, les machines sont vraiment douées pour la recherche et le tri
  • Comparativement aux machines, les humains sont vraiment doués pour l'invention et l'innovation

Donc, la réponse courte est: virtual est une instruction de liaison tardive pour la machine (runtime) alors que abstract est une instruction de liaison tardive pour l'humain (programmeur)

En d'autres termes, virtual signifie:

"Cher runtime , associez le code approprié à ce nom en faisant ce que vous faites le mieux: search"

Considérant que abstract signifie:

“Cher programmeur , veuillez associer le code approprié à ce nom en faisant ce que vous faites le mieux: inventer

Par souci d’exhaustivité, surcharge signifie:

“Cher compilateur , associez le code approprié à ce nom en faisant ce que vous faites le mieux: tri”.

5
Rodrick Chapman

Méthode virtuelle :

  • Virtual signifie que nous pouvons le remplacer. 

  • La fonction virtuelle a une implémentation. Lorsque nous héritons de la classe, nous pouvons remplacer la fonction virtuelle et fournir notre propre logique. 

  • Nous pouvons changer le type de retour de la fonction virtuelle lors de l’implémentation de
    fonction dans la classe enfant (ce qui peut être dit comme un concept de
    Shadowing).

Méthode abstraite

  • Résumé signifie que nous devons le remplacer. 

  • Une fonction abstraite n'a aucune implémentation et doit figurer dans une classe abstraite.

  • Il ne peut être déclaré. Cela oblige la classe dérivée à en implémenter la charge. 

  • Un membre abstrait est implicitement virtuel. Le résumé 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;
        }
    } 
    
3
flik

Vous utilisez essentiellement une méthode virtuelle lorsque vous souhaitez que les héritiers étendent les fonctionnalités SI 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)

3
Brann

La plupart des exemples ci-dessus utilisent du code - et ils sont vraiment très bons. Je n'ai pas besoin d'ajouter quelque chose à ce qu'ils disent, mais voici une explication simple qui utilise des analogies plutôt que des termes de code/techniques.

Explication simple - Explication utilisant des analogies

Méthode abstraite

Pensez George W Bush. Il dit à ses soldats: "Allez vous battre en Irak". Et c'est tout. Tout ce qu'il a précisé, c'est qu'il faut se battre. Il ne précise pas comment cela se produira-t-il exactement. Mais je veux dire, vous ne pouvez pas simplement sortir et "vous battre": qu'est-ce que cela signifie exactement? est-ce que je me bats avec un B-52 ou mon derringer? Ces détails spécifiques sont laissés à quelqu'un d'autre. Ceci est une méthode abstraite.

Méthode virtuelle

David Petraeus est haut dans l'armée. Il a défini ce que signifie combat:

  1. Trouver l'ennemi
  2. Neutralisez-le.
  3. Prendre une bière après

Le problème est que c'est une méthode très générale. C'est une bonne méthode qui fonctionne, mais parfois ce n'est pas assez spécifique. Le bon côté pour Petraeus est que ses ordres ont une marge de manœuvre et une portée - il a permis aux autres de changer sa définition du "combat", en fonction de leurs besoins particuliers.

Private Job Bloggs lit la commande de Petraeus et obtient l'autorisation d'implémenter sa propre version du combat, selon ses exigences particulières:

  1. Trouvez l'ennemi.
  2. Lui tirer dans la tête.
  3. Rentrer chez soi
  4. Avoir de la bière.

Nouri al Maliki reçoit également les mêmes ordres de Petraeus. Il doit se battre aussi. Mais c'est un politicien, 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 alors mettre en œuvre sa propre version de la méthode de combat, en fonction de sa situation particulière: 

  1. Trouvez l'ennemi.
  2. Faites-le arrêter avec des accusations fabriquées de toutes pièces.
  3. Rentrer chez soi
  4. Avoir de la bière.

En d’autres termes, une méthode virtuelle fournit des instructions standard, mais il s’agit d’instructions générales, que les gens de la hiérarchie de l’armée peuvent préciser, en fonction de leur situation particulière.

La différence entre les deux

  • George Bush ne prouve aucun détail de mise en oeuvre. Cela doit être fourni par quelqu'un d'autre. Ceci est une méthode abstraite.

  • D'autre part, Petraeus fournit des détails sur la mise en œuvre, mais il a donné la permission à ses subordonnés de modifier ses ordres avec leur propre version, s'ils peuvent proposer quelque chose de mieux.

j'espère que cela pourra aider.

2
BKSpurgeon

Fonction abstraite ne peut pas avoir de corps et DOIT être remplacée par des classes enfant

Fonction virtuelle aura un corps et peut ou non être remplacé par des classes enfants

2
Yeasin Abedin Siam

Fonction abstraite (méthode):

● Une méthode abstraite est une méthode déclarée avec le mot-clé abstract.

● Il n'a pas de corps.

● Il devrait être implémenté par la classe dérivée.

● Si une méthode est abstraite, la classe doit alors être abstraite.

fonction virtuelle (méthode):

● Une méthode virtuelle est la méthode déclarée avec le mot-clé virtual. Elle peut être remplacée par la méthode de la classe dérivée à l'aide du mot-clé override.

● Il appartient à la classe dérivée de la remplacer ou non.

2
Kedarnath M S

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 parente, ce qui permet à la classe enfant de choisir entre l’utilisation de cette implémentation ou une nouvelle implémentation pour cette méthode dans la classe enfant.

1
Vinay Chanumolu

Une fonction abstraite est "juste" une signature, sans implémentation . Elle est utilisée dans une interface pour déclarer comment la classe peut être utilisée . Elle doit être implémentée dans l'une des classes dérivées.

La fonction virtuelle (méthode en fait) est une fonction que vous déclarez également et que vous devez implémenter dans l'une des classes de hiérarchie d'héritage.

Les instances héritées de cette classe héritent également de l'implémentation, sauf si vous l'implémentez, dans une classe de hiérarchie inférieure.

1
Sagi Berco

De la vue générale orientée objet:

Concernant la méthode abstraite : Lorsque vous mettez une méthode abstraite dans la classe parente, vous dites aux classes enfants: Hé, notez que vous avez une signature de méthode comme celle-ci. Et si vous voulez l'utiliser, vous devez mettre en œuvre le vôtre!

Concernant la fonction virtuelle : Lorsque vous mettez une méthode virtuelle dans la classe parente, vous dites aux classes dérivées: Hé, il existe une fonctionnalité qui fait quelque chose pour vous. Si cela vous est utile, utilisez-le simplement. Sinon, remplacez ceci et implémentez votre code, même si vous pouvez utiliser mon implémentation dans votre code!

C’est une philosophie sur la différence entre ces deux concepts en général OO

1

La réponse a été fournie à plusieurs reprises, mais la question de savoir quand utiliser chacune d'elles est une décision prise au moment de la conception. Selon moi, il serait judicieux d'essayer de regrouper les définitions de méthodes communes dans des interfaces distinctes et de les extraire 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 non contrôlable lorsqu'il est préférable de définir une classe non abstraite mettant en œuvre un ensemble d'interfaces concises. Comme toujours, cela dépend de ce qui convient le mieux aux besoins spécifiques de vos applications.

1
ComeIn

Il n'y a rien d'appel virtual class en C #.

Pour les fonctions

  1. Les fonctions abstraites ont uniquement une signature, la classe de lecteurs doit être remplacée par une fonctionnalité.
  2. La fonction virtuelle contiendra la partie des fonctionnalités que la classe de lecteurs peut ou non remplacer en fonction des besoins.

Vous pouvez décider avec vos besoins.

À partir d'un arrière-plan C++, C # virtual correspond à C++, alors que les méthodes abstraites C # correspondent à C++, fonction virtuelle pure.

0
Yituo

J'écris quelques exemples de code dans l'espoir que ce soit un exemple assez concret 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(){
    //
    //    }
    }
}
0
U.Savas

Une fonction ou une méthode abstraite est un "nom d'opération" public exposé par une classe. Son objectif, ainsi que les classes abstraites, est principalement de fournir une forme de contrainte dans la conception des 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. En général, les compilateurs génèrent des erreurs quand ils ne le font pas.

L'utilisation de classes et de méthodes abstraites est essentielle pour éviter qu'en mettant l'accent sur les détails d'implémentation lors de la conception de 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 le 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 polymorpfhisme dans le paradigme de l'orientation d'objet. 

Nous pouvons utiliser ensemble des méthodes abstraites et des fonctions virtuelles pour prendre en charge un bon modèle d’héritage.

Nous concevons une bonne structure abstraite des principaux objets de notre solution, puis nous créons des implémentations de base en localisant celles qui sont le plus sujettes à de nouvelles spécialisations et nous les transformons en logiciels virtuels. Enfin, nous spécialisons nos implémentations de base, en "annulant" éventuellement les virtualités héritées.

0
Ciro Corvino