Risposte:
Dalla funzione virtuale di Wikipedia ...
Nella programmazione orientata agli oggetti, in linguaggi come C ++ e Object Pascal, una funzione o metodo virtuale è una funzione o metodo ereditabile e sostituibile per cui è facilitato l'invio dinamico. Questo concetto è una parte importante della parte del polimorfismo (runtime) della programmazione orientata agli oggetti (OOP). In breve, una funzione virtuale definisce una funzione di destinazione da eseguire, ma la destinazione potrebbe non essere nota al momento della compilazione.
A differenza di una funzione non virtuale, quando una funzione virtuale viene ignorata, la versione più derivata viene utilizzata a tutti i livelli della gerarchia di classi, anziché solo al livello in cui è stata creata. Pertanto, se un metodo della classe base chiama un metodo virtuale, verrà utilizzata la versione definita nella classe derivata anziché la versione definita nella classe base.
Ciò è in contrasto con le funzioni non virtuali, che possono ancora essere ignorate in una classe derivata, ma la "nuova" versione verrà utilizzata solo dalla classe derivata e inferiore, ma non cambierà affatto la funzionalità della classe base.
mentre..
Una funzione virtuale pura o metodo virtuale puro è una funzione virtuale che deve essere implementata da una classe derivata se la classe derivata non è astratta.
Quando esiste un metodo virtuale puro, la classe è "astratta" e non può essere istanziata da sola. Invece, deve essere utilizzata una classe derivata che implementa i metodi pure-virtual. Un puro-virtuale non è affatto definito nella classe base, quindi una classe derivata deve definirlo, o anche quella classe derivata è astratta e non può essere istanziata. Solo una classe che non ha metodi astratti può essere istanziata.
Un virtuale fornisce un modo per sovrascrivere la funzionalità della classe base e un puro-virtuale lo richiede .
pure
parola chiave, ma che Bell Labs stava per rilasciare un'importante versione di C ++ e che il suo manager non glielo avrebbe permesso in quella fase avanzata. L'aggiunta di parole chiave è un grosso problema.
Vorrei commentare la definizione di virtual di Wikipedia, come ripetuto da molti qui. [Al momento della stesura di questa risposta,] Wikipedia ha definito un metodo virtuale come uno che può essere ignorato in sottoclassi. [Fortunatamente, Wikipedia è stata modificata da allora e ora lo spiega correttamente.] Ciò è errato: qualsiasi metodo, non solo quelli virtuali, può essere ignorato in sottoclassi. Ciò che fa virtuale è darti polimorfismo, cioè la possibilità di selezionare in fase di esecuzione l'override più derivato di un metodo .
Considera il seguente codice:
#include <iostream>
using namespace std;
class Base {
public:
void NonVirtual() {
cout << "Base NonVirtual called.\n";
}
virtual void Virtual() {
cout << "Base Virtual called.\n";
}
};
class Derived : public Base {
public:
void NonVirtual() {
cout << "Derived NonVirtual called.\n";
}
void Virtual() {
cout << "Derived Virtual called.\n";
}
};
int main() {
Base* bBase = new Base();
Base* bDerived = new Derived();
bBase->NonVirtual();
bBase->Virtual();
bDerived->NonVirtual();
bDerived->Virtual();
}
Qual è l'output di questo programma?
Base NonVirtual called.
Base Virtual called.
Base NonVirtual called.
Derived Virtual called.
Derivata ignora ogni metodo di Base: non solo quello virtuale, ma anche quello non virtuale.
Vediamo che quando hai un Base-pointer-to-Derived (bDerived), chiamare NonVirtual chiama l'implementazione della classe Base. Questo viene risolto in fase di compilazione: il compilatore vede che bDerived è una Base *, che NonVirtual non è virtuale, quindi esegue la risoluzione sulla classe Base.
Tuttavia, la chiamata a Virtual chiama l'implementazione della classe Derived. A causa della parola chiave virtuale, la selezione del metodo avviene in fase di esecuzione , non in fase di compilazione. Quello che succede qui al momento della compilazione è che il compilatore vede che si tratta di una Base * e che sta chiamando un metodo virtuale, quindi inserisce una chiamata alla vtable anziché alla classe Base. Questa vtable viene istanziata in fase di runtime, quindi la risoluzione di runtime alla sostituzione più derivata.
Spero che non sia stato troppo confuso. In breve, qualsiasi metodo può essere sovrascritto, ma solo i metodi virtuali offrono polimorfismo, ovvero la selezione runtime della sostituzione più derivata. In pratica, tuttavia, l'override di un metodo non virtuale è considerato una cattiva pratica e raramente utilizzato, quindi molte persone (incluso chiunque abbia scritto l'articolo di Wikipedia) pensano che solo i metodi virtuali possano essere ignorati.
Derived*
con le stesse chiamate di funzione per portare il punto a casa. Altrimenti ottima risposta
La parola chiave virtuale dà al C ++ la sua 'capacità di supportare il polimorfismo. Quando hai un puntatore a un oggetto di qualche classe come:
class Animal
{
public:
virtual int GetNumberOfLegs() = 0;
};
class Duck : public Animal
{
public:
int GetNumberOfLegs() { return 2; }
};
class Horse : public Animal
{
public:
int GetNumberOfLegs() { return 4; }
};
void SomeFunction(Animal * pAnimal)
{
cout << pAnimal->GetNumberOfLegs();
}
In questo esempio (sciocco), la funzione GetNumberOfLegs () restituisce il numero appropriato in base alla classe dell'oggetto per cui è richiesto.
Ora, considera la funzione 'SomeFunction'. Non importa quale tipo di oggetto animale gli sia passato, purché sia derivato da Animale. Il compilatore eseguirà automaticamente il cast di qualsiasi classe derivata da animali su un animale in quanto è una classe base.
Se lo facciamo:
Duck d;
SomeFunction(&d);
avrebbe prodotto '2'. Se lo facciamo:
Horse h;
SomeFunction(&h);
avrebbe prodotto '4'. Non possiamo farlo:
Animal a;
SomeFunction(&a);
perché non verrà compilato perché la funzione virtuale GetNumberOfLegs () è pura, il che significa che deve essere implementata derivando le classi (sottoclassi).
Le funzioni virtuali pure vengono utilizzate principalmente per definire:
a) classi astratte
Queste sono classi base in cui devi derivarne e quindi implementare le funzioni virtuali pure.
b) interfacce
Queste sono classi 'vuote' in cui tutte le funzioni sono pure virtuali e quindi devi derivare e quindi implementare tutte le funzioni.
In una classe C ++, virtuale è la parola chiave che indica che un metodo può essere sovrascritto (ovvero implementato da) una sottoclasse. Per esempio:
class Shape
{
public:
Shape();
virtual ~Shape();
std::string getName() // not overridable
{
return m_name;
}
void setName( const std::string& name ) // not overridable
{
m_name = name;
}
protected:
virtual void initShape() // overridable
{
setName("Generic Shape");
}
private:
std::string m_name;
};
In questo caso una sottoclasse può sovrascrivere la funzione initShape per eseguire alcune operazioni specializzate:
class Square : public Shape
{
public:
Square();
virtual ~Square();
protected:
virtual void initShape() // override the Shape::initShape function
{
setName("Square");
}
}
Il termine puro virtuale si riferisce a funzioni virtuali che devono essere implementate da una sottoclasse e non sono state implementate dalla classe base. Si definisce un metodo come puro virtuale usando la parola chiave virtuale e aggiungendo un = 0 alla fine della dichiarazione del metodo.
Quindi, se volessi rendere Shape :: initShape puro virtuale, dovrai fare quanto segue:
class Shape
{
...
virtual void initShape() = 0; // pure virtual method
...
};
Aggiungendo un metodo virtuale puro alla tua classe, rendi la classe una classe base astratta che è molto utile per separare le interfacce dall'implementazione.
m_name
. Che cosa m_
significa?
"Virtuale" significa che il metodo può essere sovrascritto in sottoclassi, ma ha un'implementazione richiamabile direttamente nella classe base. "Pure virtual" significa che è un metodo virtuale senza implementazione richiamabile direttamente. Tale metodo deve essere sostituito almeno una volta nella gerarchia dell'ereditarietà - se una classe ha metodi virtuali non implementati, gli oggetti di quella classe non possono essere costruiti e la compilazione fallirà.
@quark sottolinea che i metodi pure-virtual possono avere un'implementazione, ma poiché i metodi pure-virtual devono essere sovrascritti, l'implementazione predefinita non può essere chiamata direttamente. Ecco un esempio di metodo puro-virtuale con un valore predefinito:
#include <cstdio>
class A {
public:
virtual void Hello() = 0;
};
void A::Hello() {
printf("A::Hello\n");
}
class B : public A {
public:
void Hello() {
printf("B::Hello\n");
A::Hello();
}
};
int main() {
/* Prints:
B::Hello
A::Hello
*/
B b;
b.Hello();
return 0;
}
Secondo i commenti, la mancata compilazione della compilazione è specifica del compilatore. Almeno in GCC 4.3.3, non verrà compilato:
class A {
public:
virtual void Hello() = 0;
};
int main()
{
A a;
return 0;
}
Produzione:
$ g++ -c virt.cpp
virt.cpp: In function ‘int main()’:
virt.cpp:8: error: cannot declare variable ‘a’ to be of abstract type ‘A’
virt.cpp:1: note: because the following virtual functions are pure within ‘A’:
virt.cpp:3: note: virtual void A::Hello()
Come funziona la parola chiave virtuale?
Supponiamo che l'uomo sia una classe base, l'indiano è derivato dall'uomo.
Class Man
{
public:
virtual void do_work()
{}
}
Class Indian : public Man
{
public:
void do_work()
{}
}
Dichiarare do_work () come virtuale significa semplicemente: quale do_work () chiamare sarà determinato SOLO in fase di esecuzione.
Supponiamo che lo faccia
Man *man;
man = new Indian();
man->do_work(); // Indian's do work is only called.
Se non viene utilizzato virtuale, lo stesso viene determinato staticamente o associato staticamente dal compilatore, a seconda di quale oggetto sta chiamando. Quindi se un oggetto di Man chiama do_work (), Man's do_work () viene chiamato ANCHE PENSANDO CHE PUNTA A UN OGGETTO INDIANO
Credo che la risposta più votata sia fuorviante - Qualsiasi metodo, virtuale o meno, può avere un'implementazione ignorata nella classe derivata. Con specifico riferimento a C ++ la differenza corretta è l'associazione runtime (quando viene utilizzato il virtuale) e la compilazione (quando non viene utilizzato il virtuale ma un metodo viene ignorato e un puntatore di base è puntato su un oggetto derivato) l'associazione delle funzioni associate.
Sembra che ci sia un altro commento fuorviante che dice:
"Justin, 'puro virtuale' è solo un termine (non una parola chiave, vedi la mia risposta di seguito) usato per indicare" questa funzione non può essere implementata dalla classe base. "
QUESTO È SBAGLIATO! Le funzioni puramente virtuali possono anche avere un corpo E POSSONO ESSERE REALIZZATE! La verità è che la pura funzione virtuale di una classe astratta può essere chiamata staticamente! Due autori molto bravi sono Bjarne Stroustrup e Stan Lippman .... perché hanno scritto la lingua.
Una funzione virtuale è una funzione membro dichiarata in una classe base e ridefinita dalla classe derivata. Le funzioni virtuali sono gerarchiche in ordine di eredità. Quando una classe derivata non sostituisce una funzione virtuale, viene utilizzata la funzione definita all'interno della sua classe base.
Una funzione virtuale pura è quella che non contiene alcuna definizione relativa alla classe base. Non ha implementazione nella classe base. Qualsiasi classe derivata deve sovrascrivere questa funzione.
Simula, C ++ e C #, che utilizzano per impostazione predefinita l'associazione di metodi statici, il programmatore può specificare che determinati metodi dovrebbero utilizzare l'associazione dinamica etichettandoli come virtuali. Il binding dinamico dei metodi è fondamentale per la programmazione orientata agli oggetti.
La programmazione orientata agli oggetti richiede tre concetti fondamentali: incapsulamento, ereditarietà e associazione dinamica dei metodi.
L'incapsulamento consente di nascondere i dettagli di implementazione di un'astrazione dietro una semplice interfaccia.
L'ereditarietà consente di definire una nuova astrazione come un'estensione o un perfezionamento di alcune astrazioni esistenti, ottenendo automaticamente alcune o tutte le sue caratteristiche.
L'associazione dinamica del metodo consente alla nuova astrazione di mostrare il suo nuovo comportamento anche se utilizzata in un contesto che prevede la vecchia astrazione.
I metodi virtuali POSSONO essere sovrascritti dalle classi derivate, ma necessitano un'implementazione nella classe base (quella che verrà sovrascritta)
I metodi virtuali puri non hanno implementato la classe base. Devono essere definiti da classi derivate. (Quindi tecnicamente sovrascritto non è il termine giusto, perché non c'è nulla da ignorare).
Virtual corrisponde al comportamento java predefinito, quando la classe derivata sovrascrive un metodo della classe base.
I metodi virtuali puri corrispondono al comportamento dei metodi astratti all'interno delle classi astratte. E una classe che contiene solo metodi e costanti virtuali puri sarebbe il cpp-pendente di un'interfaccia.
Pura funzione virtuale
prova questo codice
#include <iostream>
using namespace std;
class aClassWithPureVirtualFunction
{
public:
virtual void sayHellow()=0;
};
class anotherClass:aClassWithPureVirtualFunction
{
public:
void sayHellow()
{
cout<<"hellow World";
}
};
int main()
{
//aClassWithPureVirtualFunction virtualObject;
/*
This not possible to create object of a class that contain pure virtual function
*/
anotherClass object;
object.sayHellow();
}
Nella classe anotherClass rimuovere la funzione sayHellow ed eseguire il codice. si otterrà un errore! Perché quando una classe contiene una funzione virtuale pura, nessun oggetto può essere creato da quella classe ed è ereditato, quindi la sua classe derivata deve implementare quella funzione.
Funzione virtuale
prova un altro codice
#include <iostream>
using namespace std;
class aClassWithPureVirtualFunction
{
public:
virtual void sayHellow()
{
cout<<"from base\n";
}
};
class anotherClass:public aClassWithPureVirtualFunction
{
public:
void sayHellow()
{
cout<<"from derived \n";
}
};
int main()
{
aClassWithPureVirtualFunction *baseObject=new aClassWithPureVirtualFunction;
baseObject->sayHellow();///call base one
baseObject=new anotherClass;
baseObject->sayHellow();////call the derived one!
}
Qui la funzione sayHellow è contrassegnata come virtuale nella classe base. Dice il compilatore che prova a cercare la funzione nella classe derivata e implementa la funzione. Se non lo trovi, esegui quello di base. Grazie
"Una funzione virtuale o un metodo virtuale è una funzione o un metodo il cui comportamento può essere sovrascritto all'interno di una classe ereditaria da una funzione con la stessa firma" - wikipedia
Questa non è una buona spiegazione per le funzioni virtuali. Perché, anche se un membro non è virtuale, ereditare le classi può sovrascriverlo. Puoi provare a vederlo da solo.
La differenza si mostra quando una funzione accetta una classe base come parametro. Quando si assegna una classe ereditaria come input, tale funzione utilizza l'implementazione della classe base della funzione overriden. Tuttavia, se tale funzione è virtuale, utilizza quella implementata nella classe derivante.
Le funzioni virtuali devono avere una definizione in classe base e anche in classe derivata ma non necessaria, ad esempio la funzione ToString () o toString () è virtuale, quindi è possibile fornire la propria implementazione sovrascrivendola in classi definite dall'utente.
Le funzioni virtuali sono dichiarate e definite in classe normale.
La funzione virtuale pura deve essere dichiarata che termina con "= 0" e può essere dichiarata solo in classe astratta.
Una classe astratta che ha una (e) funzione (i) virtuale (i) pura (e) non può avere una (e) definizione (e) di quelle funzioni virtuali pure, quindi implica che l'implementazione deve essere fornita nelle classi derivate da quella classe astratta.