c# puro Qual è la differenza tra una funzione astratta e una funzione virtuale?




virtual c++ (20)

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.

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


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.


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.


  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).

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

Da uno sfondo C ++, C # virtual corrisponde a C ++ virtual, mentre i metodi C # abstract corrisponde alla pura funzione virtuale di C ++


È sempre necessario sovrascrivere una funzione astratta.

Così:

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

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.


Una funzione astratta non può avere funzionalità. In pratica, stai dicendo che qualsiasi classe figlio DEVE fornire la propria versione di questo metodo, tuttavia è troppo generico per tentare di implementare anche nella classe genitore.

Una funzione virtuale , in pratica sta dicendo look, ecco la funzionalità che può o non può essere abbastanza buona per la classe bambino. Quindi, se è abbastanza buono, utilizzare questo metodo, in caso contrario, quindi eseguire l'override di me e fornire le proprie funzionalità.


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


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.

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.


Non ci sono chiamate call class virtuali in C #.

Per le funzioni

  1. La funzione astratta ha solo la firma, la classe di unità dovrebbe prevalere sulla funzionalità.
  2. La funzione virtuale terrà la parte di funzionalità che la classe di unità può o non può sovrascrivere in base al requisito

Puoi decidere con la tua richiesta.


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

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

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 maggior parte degli esempi precedenti utilizza il codice e sono molto molto validi. Non ho bisogno di aggiungere ciò che dicono, ma la seguente è una semplice spiegazione che fa uso di analogie piuttosto che di termini tecnici / di codice.

Spiegazione semplice - Spiegazione che usa le analogie

Metodo astratto

Pensa a George W. Bush. Dice ai suoi soldati: "Andate a combattere in Iraq". E questo è tutto. Tutto quello che ha specificato è che bisogna combattere. Non specifica come esattamente ciò accadrà. Ma voglio dire, non puoi semplicemente uscire e "combattere": cosa significa esattamente? combatto con un B-52 o con la mia derringer? Quei dettagli specifici sono lasciati a qualcun altro. Questo è un metodo astratto.

Metodo virtuale

David Petraeus è in alto nell'esercito. Ha definito cosa significa combattere:

  1. Trova il nemico
  2. Neutralizzarlo.
  3. Avere una birra dopo

Il problema è che è un metodo molto generale. È un buon metodo che funziona, ma a volte non è abbastanza specifico. La cosa buona per Petraeus è che i suoi ordini hanno margine di manovra e portata - ha permesso ad altri di cambiare la sua definizione di "combattimento", secondo le loro particolari esigenze.

Private Job Bloggs legge l'ordine di Petraeus e gli viene dato il permesso di implementare la propria versione di combattimento, in base alle sue particolari esigenze:

  1. Trova nemico.
  2. Sparagli in testa
  3. Andare a casa
  4. Bevi birra

Anche Nouri al Maliki riceve gli stessi ordini da Petraeus. Anche lui deve combattere. Ma è un politico, non un uomo di fanteria. Ovviamente non può andare in giro a sparare ai suoi nemici politici in testa. Poichè Petraeus gli ha dato un metodo virtuale, Maliki può implementare la sua versione del metodo di combattimento, secondo le sue particolari circostanze:

  1. Trova nemico.
  2. Fallo arrestare con alcune accuse di BS.
  3. Andare a casa
  4. Bevi birra

In altre parole, un metodo virtuale fornisce le istruzioni per l'uso, ma queste sono istruzioni generali, che possono essere rese più specifiche dalle persone che si trovano sotto l'egarchia dell'esercito, in base alle loro particolari circostanze.

La differenza tra i due

  • George Bush non prova alcun dettaglio di implementazione. Questo deve essere fornito da qualcun altro. Questo è un metodo astratto.

  • Dall'altra parte, Petraeus fornisce dettagli sull'implementazione, ma ha dato il permesso ai suoi subordinati di ignorare i suoi ordini con la loro versione, se riescono a trovare qualcosa di meglio.

spero che sia d'aiuto.


Una funzione astratta è "giusta" una firma, senza un'implementazione. È usato in un'interfaccia per dichiarare come la classe può essere usata. Deve essere implementato in una delle classi derivate.

La funzione virtuale (metodo in realtà), è una funzione dichiarata e dovrebbe essere implementata in una delle classi di gerarchia di ereditarietà.

Le istanze ereditate di tale classe ereditano anche l'implementazione, a meno che non la si implementi, in una classe gerarchica inferiore.


Funzione astratta (metodo):

● Un metodo astratto è un metodo dichiarato con la parola chiave abstract.

● Non ha il corpo.

● Dovrebbe essere implementato dalla classe derivata.

● Se un metodo è astratto, la classe deve essere astratta.

funzione virtuale (metodo):

● Un metodo virtuale è il metodo dichiarato con la parola chiave virtual e può essere sovrascritto dal metodo della classe derivata utilizzando la parola chiave override.

● È compito della classe derivata se sostituirlo o meno.


Binding è il processo di mappatura di un nome a un'unità di codice.

L'associazione tardiva significa che usiamo il nome, ma rimandiamo la mappatura. In altre parole, creiamo / menzioniamo prima il nome e lasciamo che alcuni processi successivi gestiscano la mappatura del codice a quel nome.

Considerare ora:

  • Rispetto agli esseri umani, le macchine sono davvero brave nella ricerca e nell'ordinamento
  • Rispetto alle macchine, gli umani sono davvero bravi nell'invenzione e nell'innovazione

Quindi, la risposta breve è: virtual è un'istruzione di binding tardiva per la macchina (runtime) mentre l' abstract è l'ultima istruzione di binding per l'umano (programmatore)

In altre parole, virtual significa:

"Caro runtime , associa il codice appropriato a questo nome facendo ciò che sai fare meglio: cercare "

Mentre l' abstract significa:

"Gentile programmatore , ti preghiamo di legare il codice appropriato a questo nome facendo ciò che sai fare meglio: inventare "

Per completezza, sovraccaricare significa:

"Caro compilatore , collega il codice appropriato a questo nome facendo ciò che sai fare meglio: ordinare ".





virtual-functions