c# méthode - Quelle est la différence entre une fonction abstraite et une fonction virtuelle?




classe virtual (18)

J'ai vu dans 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 doive être 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 implémentée 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 le mot-clé override . 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();
    }
}

Quelle est la différence entre une fonction abstraite et une fonction virtuelle? Dans quels cas est-il recommandé d'utiliser virtuel ou abstrait? Quelle est l'approche la plus correcte?


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 la mise en
    fonction dans la classe des enfants (ce qui peut être dit comme un concept de
    Ombrage).

Méthode abstraite

  • Résumé signifie que nous devons l'ignorer.

  • Une fonction abstraite n'a pas d'implémentation et doit être dans une classe abstraite.

  • Cela peut seulement être déclaré. Cela force la classe dérivée à fournir l'implémentation de celle-ci.

  • Un membre abstrait est implicitement virtuel. Le résumé peut être appelé comme virtuel pur dans certaines langues.

    public abstract class BaseClass
    { 
        protected abstract void xAbstractMethod();
    
        public virtual void xVirtualMethod()
        {
            var x = 3 + 4;
        }
    } 
    

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 devrait ê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 la classe dérivée en utilisant le mot-clé override.

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


Vous utilisez essentiellement une méthode virtuelle lorsque vous voulez que les héritiers étendent la fonctionnalité SI ils le souhaitent.

Vous utilisez des méthodes abstraites lorsque vous voulez que les héritiers implémentent la fonctionnalité (et dans ce cas ils n'ont pas le choix)


Vous devez toujours remplacer une fonction abstraite.

Ainsi:

  • Fonctions abstraites - quand l'héritier doit fournir sa propre implémentation
  • Virtuel - quand il appartient à l'héritier de décider

Une fonction abstraite ne peut pas avoir de fonctionnalité. Vous êtes en train de dire que toute classe enfant DOIT donner sa propre version de cette méthode, mais il est trop général pour essayer même de l'implémenter dans la classe parente.

Une fonction virtuelle , c'est essentiellement dire look, voici la fonctionnalité qui peut ou ne peut pas être assez bon pour la classe enfant. Donc, si cela est suffisant, utilisez cette méthode, sinon, remplacez-moi, et fournissez vos propres fonctionnalités.


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' et que vous voulez permettre aux descendants de changer son comportement.

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


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


À ma compréhension:

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 en fournir l'implémentation. De plus, la classe dérivée doit implémenter la méthode pour la surcharger.


La liaison est le processus de mappage d'un nom à une unité de code.

La liaison tardive signifie que nous utilisons le nom, mais différons le mappage. En d'autres termes, nous créons / mentionnons le nom en premier, et laissons un processus ultérieur gérer le mappage du code à ce nom.

Maintenant considérez:

  • Comparé aux humains, les machines sont vraiment bonnes pour la recherche et le tri
  • Comparé aux machines, les humains sont vraiment bons en matière d'invention et d'innovation

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

En d'autres termes, virtual signifie:

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

Alors que abstract signifie:

"Cher programmeur , veuillez lier le code approprié à ce nom en faisant ce que vous faites de mieux: inventer "

Par souci d'exhaustivité, la surcharge signifie:

"Cher compilateur , attachez le code approprié à ce nom en faisant ce que vous faites de mieux: le tri ".


Je l'ai simplifié en apportant quelques améliorations sur les 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");
        }
    }
}

Méthode abstraite: Lorsqu'une classe contient une méthode abstraite, cette classe doit être déclarée comme 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 ce cas, vous pouvez créer une interface contenant 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 surchargée), et une autre méthode qui contient la logique «commune».

Une méthode virtuelle devrait ê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.


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 surchargée dans une classe dérivée en utilisant le remplacement, en remplaçant le comportement dans la superclasse. Si vous ne surchargez pas, vous obtenez le comportement original. 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 qui peuvent masquer la méthode d'origine. Ceci est fait en utilisant le 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");
    }
}

Quand DerivedClass et appelle SayHello , ou SayGoodbye , je reçois "Hi There" et "A plus tard". Si j'appelle HelloGoodbye , je reçois "Bonjour" et "A plus tard". C'est parce que SayGoodbye est virtuel, et peut être remplacé par des classes dérivées. SayHello est seulement caché, donc quand j'appelle ça de 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 comme une interface.


  1. Seules abstract classes abstract peuvent avoir abstract membres abstract .
  2. Une classe non abstract qui hérite d'une classe abstract doit override ses membres abstract .
  3. Un membre abstract est implicitement virtual .
  4. Un membre abstract ne peut fournir aucune implémentation (le abstract est appelé pure virtual dans certaines langues).

Il n'y a rien d'appeler la classe virtuelle en C #.

Pour les fonctions

  1. La fonction abstraite n'a que la signature, la classe de lecteur doit remplacer la fonctionnalité.
  2. La fonction virtuelle contiendra la partie de la fonctionnalité que la classe de lecteur peut ou ne peut pas remplacer en fonction de l'exigence

Vous pouvez décider avec votre condition.


La réponse a été fournie un certain nombre de fois, mais la question de savoir quand utiliser chacun est une décision au moment du design. Je verrais comme une bonne pratique d'essayer de regrouper des définitions de méthodes communes en interfaces distinctes et de les placer dans des classes à des 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 à distinguer lorsqu'il est 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.


Une fonction abstraite n'a pas d'implémentation et elle 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 peut exister sur une classe abstraite ou 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();
}

Peut-être qu'un exemple de code aidera: Notez la différence entre les signatures d'appel de foo , class_foo et static_foo :

class A(object):
    def foo(self,x):
        print "executing foo(%s,%s)"%(self,x)

    @classmethod
    def class_foo(cls,x):
        print "executing class_foo(%s,%s)"%(cls,x)

    @staticmethod
    def static_foo(x):
        print "executing static_foo(%s)"%x    

a=A()

Ci-dessous, la manière habituelle pour une instance d'objet d'appeler une méthode. L'instance d'objet, a , est implicitement passée en tant que premier argument.

a.foo(1)
# executing foo(<__main__.A object at 0xb7dbef0c>,1)

Avec classmethods , la classe de l'instance d'objet est implicitement passée en tant que premier argument au lieu de self .

a.class_foo(1)
# executing class_foo(<class '__main__.A'>,1)

Vous pouvez également appeler class_foo utilisant la classe. En fait, si vous définissez quelque chose comme étant une méthode de classe, c'est probablement parce que vous avez l'intention de l'appeler depuis la classe plutôt que depuis une instance de classe. A.foo(1) aurait généré une erreur TypeError, mais A.class_foo(1) fonctionne parfaitement:

A.class_foo(1)
# executing class_foo(<class '__main__.A'>,1)

Une utilisation que les utilisateurs ont trouvée pour les méthodes de classe consiste à créer des constructeurs alternatifs héritables .

Avec staticmethods , ni self (l'instance de l'objet) ni cls (la classe) ne sont implicitement passés en tant que premier argument. Ils se comportent comme des fonctions simples, sauf que vous pouvez les appeler à partir d'une instance ou de la classe:

a.static_foo(1)
# executing static_foo(1)

A.static_foo('hi')
# executing static_foo(hi)

Staticmethods sont utilisés pour grouper des fonctions qui ont une connexion logique avec une classe à la classe.

foo n'est qu'une fonction, mais lorsque vous appelez a.foo vous n'obtenez pas seulement la fonction, vous obtenez une version "partiellement appliquée" de la fonction, l'instance de l'objet étant liée comme premier argument de la fonction. foo attend 2 arguments, alors que a.foo n'attend qu'un argument.

a est lié à foo . C'est ce que l'on entend par le terme "lié" ci-dessous:

print(a.foo)
# <bound method A.foo of <__main__.A object at 0xb7d52f0c>>

Avec a.class_foo , a n'est pas lié à class_foo , mais la classe A est liée à class_foo .

print(a.class_foo)
# <bound method type.class_foo of <class '__main__.A'>>

Ici, avec une méthode static, même s’il s’agit d’une méthode, a.static_foo ne fait que a.static_foo une bonne fonction ole sans argument lié. static_foo attend 1 argument et a.static_foo attend également 1 argument.

print(a.static_foo)
# <function static_foo at 0xb7d479cc>

Et bien sûr, la même chose se produit lorsque vous appelez static_foo avec la classe A

print(A.static_foo)
# <function static_foo at 0xb7d479cc>




c# oop programming-languages virtual abstract