c# - virtuale - virtual c++




Qual è la differenza tra una funzione astratta e una funzione virtuale? (16)

  1. Solo le classi abstract possono avere membri abstract .
  2. Una classe non abstract che eredita da una classe abstract deve override suoi membri abstract .
  3. Un membro abstract è implicitamente virtual .
  4. Un membro abstract non può fornire alcuna implementazione (l' abstract è chiamato pure virtual in alcune lingue).

Qual è la differenza tra una funzione astratta e una funzione virtuale? In quali casi è consigliabile utilizzare virtuale o astratto? Qual è l'approccio più corretto?


È sempre necessario sovrascrivere una funzione astratta.

Così:

  • Funzioni astratte - quando l'erede deve fornire la propria implementazione
  • Virtuale - quando spetta all'erede decidere

Dalla vista orientata agli oggetti generale:

Riguardo al metodo astratto : quando metti un metodo astratto nella classe genitore, in realtà stai dicendo alle classi figlie: Ehi, nota che hai una firma del metodo come questa. E se vuoi usarlo, devi implementare il tuo!

Per quanto riguarda la funzione virtuale : quando metti un metodo virtuale nella classe genitore stai dicendo alle classi derivate: Hey c'è una funzionalità qui che fa qualcosa per te. Se questo è utile per te basta usarlo. In caso contrario, ignora questo e implementa il tuo codice, anche tu puoi usare la mia implementazione nel tuo codice!

questa è una filosofia di diverso tra questi due concetti in General OO


Fondamentalmente usi un metodo virtuale quando vuoi che gli eredi estendano la funzionalità se lo desiderano.

Usi metodi astratti quando vuoi che gli eredi implementino la funzionalità (e in questo caso non hanno scelta)


Funzione astratta:

  1. Può essere dichiarato solo all'interno della classe astratta.
  2. Contiene solo la dichiarazione del metodo e non l'implementazione in classe astratta.
  3. Deve essere sovrascritto nella classe derivata.

Funzione virtuale:

  1. Può essere dichiarato all'interno di una classe astratta e non astratta.
  2. Contiene l'implementazione del metodo.
  3. Potrebbe essere ignorato.

Ho reso questo più semplice apportando alcuni miglioramenti sulle seguenti classi (da altre risposte):

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

I metodi astratti sono sempre virtuali. Non possono avere un'implementazione.

Questa è la differenza principale.

Fondamentalmente, si userebbe un metodo virtuale se si ha l'implementazione 'predefinita' di esso e si desidera consentire ai discendenti di cambiare il suo comportamento.

Con un metodo astratto, costringi i discendenti a fornire un'implementazione.


Il metodo astratto non ha un'implementazione. Viene dichiarato nella classe genitore. La classe figlio è responsabile per l'implementazione di quel metodo.

Il metodo virtuale dovrebbe avere un'implementazione nella classe genitore e facilita la classe figlio a fare la scelta se usare quell'implementazione della classe genitore o avere una nuova implementazione per sé per quel metodo nella classe figlio.


La risposta è stata fornita diverse volte ma la domanda su quando utilizzare ciascuna è una decisione in fase di progettazione. Ritengo che sia una buona pratica cercare di raggruppare le definizioni dei metodi comuni in interfacce distinte e trascinarle in classi a livelli di astrazione appropriati. Il dumping di un insieme comune di definizioni di metodi astratti e virtuali in una classe rende la classe non controllabile quando potrebbe essere meglio definire una classe non astratta che implementa un insieme di interfacce concise. Come sempre, dipende da ciò che meglio si adatta alle esigenze specifiche delle tue applicazioni.


Metodo astratto: quando una classe contiene un metodo astratto, quella classe deve essere dichiarata come astratta. Il metodo astratto non ha implementazione e quindi, le classi che derivano da quella classe astratta, devono fornire un'implementazione per questo metodo astratto.

Metodo virtuale: una classe può avere un metodo virtuale. Il metodo virtuale ha un'implementazione. Quando si eredita da una classe che ha un metodo virtuale, è possibile sovrascrivere il metodo virtuale e fornire una logica aggiuntiva o sostituire la logica con la propria implementazione.

Quando usare cosa: In alcuni casi, sai che alcuni tipi dovrebbero avere un metodo specifico, ma non sai quale implementazione dovrebbe avere questo metodo.
In questi casi, è possibile creare un'interfaccia che contenga un metodo con questa firma. Tuttavia, se si dispone di un caso del genere, ma si sa che gli implementatori di tale interfaccia avranno anche un altro metodo comune (per il quale è già possibile fornire l'implementazione), è possibile creare una classe astratta. Questa classe astratta contiene quindi il metodo astratto (che deve essere sovrascritto) e un altro metodo che contiene la logica "comune".

È necessario utilizzare un metodo virtuale se si dispone di una classe che può essere utilizzata direttamente, ma per la quale si desidera che gli eredi siano in grado di modificare determinati comportamenti, sebbene non sia obbligatorio.


Per la mia comprensione:

Metodi astratti:

Solo la classe astratta può contenere metodi astratti. Anche la classe derivata deve implementare il metodo e non viene fornita alcuna implementazione nella classe.

Metodi virtuali:

Una classe può dichiararli e fornire anche l'implementazione della stessa. Anche la classe derivata deve implementare il metodo per sovrascriverlo.


Un metodo astratto è un metodo che deve essere implementato per fare una lezione concreta. La dichiarazione è nella classe astratta (e qualsiasi classe con un metodo astratto deve essere una classe astratta) e deve essere implementata in una classe concreta.

Un metodo virtuale è un metodo che può essere sovrascritto in una classe derivata utilizzando l'override, sostituendo il comportamento nella superclasse. Se non si esegue l'override, si ottiene il comportamento originale. Se lo fai, ottieni sempre il nuovo comportamento. Questo si oppone ai metodi non virtuali, che non possono essere sovrascritti ma possono nascondere il metodo originale. Questo viene fatto usando il new modificatore.

Guarda il seguente esempio:

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 instanziare DerivedClass e chiamare SayHello , o SayGoodbye , ottengo "Ciao" e "Ci vediamo dopo". Se chiamo HelloGoodbye , ricevo "Ciao" e "Ci vediamo dopo". Questo perché SayGoodbye è virtuale e può essere sostituito da classi derivate. SayHello è solo nascosto, quindi quando lo chiamo dalla mia classe base ottengo il mio metodo originale.

I metodi astratti sono implicitamente virtuali. Definiscono il comportamento che deve essere presente, più come fa un'interfaccia.


Una funzione astratta non ha alcuna implementazione e può essere dichiarata solo in una classe astratta. Ciò impone alla classe derivata di fornire un'implementazione. Una funzione virtuale fornisce un'implementazione predefinita e può esistere su una classe astratta o una classe non astratta. Quindi per esempio:

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();
}

spiegazione: con analogie. speriamo che ti possa aiutare.

Contesto

Lavoro al 21 ° piano di un edificio. E sono paranoico per il fuoco. Ogni tanto, in qualche parte del mondo, un fuoco sta bruciando un raschietto del cielo. Ma per fortuna abbiamo un manuale di istruzioni da qualche parte su cosa fare in caso di incendio:

Scala di sicurezza()

  1. Non raccogliere oggetti
  2. Cammina verso la scala antincendio
  3. Esci dall'edificio

Questo è fondamentalmente un metodo virtuale chiamato FireEscape ()

Metodo virtuale

Questo piano è abbastanza buono per il 99% delle circostanze. È un piano di base che funziona. Ma c'è una probabilità dell'1% che la scala antincendio sia bloccata o danneggiata, nel qual caso sei completamente fregato e diventerai pane tostato a meno che tu non compia un'azione drastica. Con i metodi virtuali puoi fare proprio questo: puoi sovrascrivere il piano di base di FireEscape () con la tua versione del piano:

  1. Corri alla finestra
  2. Salta fuori dalla finestra
  3. Paracadute sicuro fino in fondo

In altre parole, i metodi virtuali forniscono un piano di base, che può essere sostituito se necessario . Le sottoclassi possono sovrascrivere il metodo virtuale della classe genitore se il programmatore lo ritiene appropriato.

Metodi astratti

Non tutte le organizzazioni sono ben perforate. Alcune organizzazioni non fanno esercitazioni antincendio. Non hanno una politica di fuga globale. Ogni uomo è per se stesso. La gestione è interessata solo a tale politica esistente.

In altre parole, ogni persona è costretta a sviluppare il proprio metodo FireEscape (). Un ragazzo uscirà dalla scala antincendio. Un altro ragazzo farà il paracadute. Un altro ragazzo utilizzerà la tecnologia di propulsione a razzo per volare via dall'edificio. Un altro ragazzo si cala in corda doppia. Al management non importa come fuggi, purché tu abbia un piano base di FireEscape () - se non lo fai, puoi essere sicuro che OHS arriverà sull'organizzazione come una tonnellata di mattoni. Questo è ciò che si intende con un metodo astratto.

Qual è la differenza tra i due di nuovo?

Metodo astratto: le sottoclassi sono costrette ad implementare il proprio metodo FireEscape. Con un metodo virtuale, hai un piano base che ti aspetta, ma puoi scegliere di implementare il tuo se non è abbastanza buono.

Ora non è stato così difficile?


La funzione astratta non può avere un corpo e DEVE essere ignorata dalle classi figlio

La funzione virtuale avrà un corpo e potrebbe o meno essere sovrascritta dalle classi figlio


Metodo virtuale :

  • Virtuale significa che POSSO cancellarlo.

  • La funzione virtuale ha un'implementazione. Quando ereditiamo la classe, possiamo sovrascrivere la funzione virtuale e fornire la nostra logica.

  • Possiamo cambiare il tipo di ritorno della funzione virtuale mentre implementiamo il
    funzione nella classe figlio (che può essere definita come un concetto di
    Shadowing).

Metodo astratto

  • Astratto significa che DEVE prevalere su di esso.

  • Una funzione astratta non ha implementazione e deve essere in una classe astratta.

  • Può solo essere dichiarato. Questo costringe la classe derivata a fornire l'implementazione di esso.

  • Un membro astratto è implicitamente virtuale. L'astratto può essere definito come puro virtuale in alcune lingue.

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




virtual-functions