Réponses:
De la fonction virtuelle de Wikipedia ...
Dans la programmation orientée objet, dans des langages tels que C ++ et Object Pascal, une fonction virtuelle ou une méthode virtuelle est une fonction ou une méthode héritable et remplaçable pour laquelle la répartition dynamique est facilitée. Ce concept est une partie importante de la portion (d'exécution) du polymorphisme de la programmation orientée objet (POO). En bref, une fonction virtuelle définit une fonction cible à exécuter, mais la cible peut ne pas être connue au moment de la compilation.
Contrairement à une fonction non virtuelle, lorsqu'une fonction virtuelle est remplacée, la version la plus dérivée est utilisée à tous les niveaux de la hiérarchie des classes, plutôt qu'au niveau auquel elle a été créée. Par conséquent, si une méthode de la classe de base appelle une méthode virtuelle, la version définie dans la classe dérivée sera utilisée à la place de la version définie dans la classe de base.
Cela contraste avec les fonctions non virtuelles, qui peuvent toujours être remplacées dans une classe dérivée, mais la "nouvelle" version ne sera utilisée que par la classe dérivée et ci-dessous, mais ne changera pas du tout la fonctionnalité de la classe de base.
tandis que..
Une fonction virtuelle pure ou une méthode virtuelle pure est une fonction virtuelle qui doit être implémentée par une classe dérivée si la classe dérivée n'est pas abstraite.
Lorsqu'une méthode virtuelle pure existe, la classe est "abstraite" et ne peut pas être instanciée seule. Au lieu de cela, une classe dérivée qui implémente la ou les méthodes pure-virtuelles doit être utilisée. Un virtuel pur n'est pas du tout défini dans la classe de base, donc une classe dérivée doit le définir, ou cette classe dérivée est également abstraite et ne peut pas être instanciée. Seule une classe qui n'a pas de méthodes abstraites peut être instanciée.
Un virtuel fournit un moyen de remplacer la fonctionnalité de la classe de base, et un pur-virtuel l' exige .
pure
mot - clé, mais que Bell Labs était sur le point de faire une version majeure de C ++, et son manager ne l'autoriserait pas à ce stade tardif. L'ajout de mots clés est un gros problème.
Je voudrais commenter la définition de Wikipédia du virtuel, comme plusieurs l'ont répété ici. [Au moment où cette réponse a été écrite,] Wikipedia a défini une méthode virtuelle comme une méthode qui peut être remplacée dans les sous-classes. [Heureusement, Wikipédia a été modifié depuis, et il explique maintenant cela correctement.] C'est incorrect: toute méthode, pas seulement virtuelle, peut être remplacée dans les sous-classes. Ce que le virtuel fait est de vous donner un polymorphisme, c'est-à-dire la possibilité de sélectionner au moment de l'exécution le remplacement le plus dérivé d'une méthode .
Considérez le code suivant:
#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();
}
Quelle est la sortie de ce programme?
Base NonVirtual called.
Base Virtual called.
Base NonVirtual called.
Derived Virtual called.
Derived remplace toutes les méthodes de Base: non seulement la virtuelle, mais aussi la non-virtuelle.
Nous voyons que lorsque vous avez un pointeur de base vers dérivé (bDerived), appeler NonVirtual appelle l'implémentation de la classe de base. Ceci est résolu au moment de la compilation: le compilateur voit que bDerived est une Base *, que NonVirtual n'est pas virtuel, donc il fait la résolution sur la classe Base.
Cependant, l'appel de Virtual appelle l'implémentation de la classe Derived. En raison du mot-clé virtual, la sélection de la méthode se produit au moment de l' exécution , pas au moment de la compilation. Ce qui se passe ici au moment de la compilation, c'est que le compilateur voit qu'il s'agit d'une Base *, et qu'il appelle une méthode virtuelle, donc il insère un appel à la table virtuelle au lieu de la classe Base. Cette table virtuelle est instanciée au moment de l'exécution, d'où la résolution au moment de la substitution la plus dérivée.
J'espère que ce n'était pas trop déroutant. En bref, n'importe quelle méthode peut être remplacée, mais seules les méthodes virtuelles vous donnent le polymorphisme, c'est-à-dire la sélection au moment de l'exécution du remplacement le plus dérivé. Dans la pratique, cependant, remplacer une méthode non virtuelle est considéré comme une mauvaise pratique et rarement utilisé, de nombreuses personnes (y compris celui qui a écrit cet article Wikipedia) pensent que seules les méthodes virtuelles peuvent être remplacées.
Derived*
avec les mêmes appels de fonction pour ramener le point d'origine. Sinon, bonne réponse
Le mot-clé virtuel donne à C ++ sa capacité à supporter le polymorphisme. Lorsque vous avez un pointeur sur un objet d'une classe telle que:
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();
}
Dans cet exemple (idiot), la fonction GetNumberOfLegs () renvoie le nombre approprié en fonction de la classe de l'objet pour lequel il est appelé.
Maintenant, considérez la fonction 'SomeFunction'. Peu importe le type d'objet animal qui lui est transmis, tant qu'il est dérivé d'Animal. Le compilateur convertira automatiquement toute classe dérivée d'un animal en animal car il s'agit d'une classe de base.
Si nous faisons cela:
Duck d;
SomeFunction(&d);
il produirait «2». Si nous faisons cela:
Horse h;
SomeFunction(&h);
il produirait «4». On ne peut pas faire ça:
Animal a;
SomeFunction(&a);
car il ne se compile pas car la fonction virtuelle GetNumberOfLegs () est pure, ce qui signifie qu'elle doit être implémentée en dérivant des classes (sous-classes).
Les fonctions virtuelles pures sont principalement utilisées pour définir:
a) classes abstraites
Ce sont des classes de base où vous devez en dériver puis implémenter les fonctions virtuelles pures.
b) interfaces
Ce sont des classes «vides» où toutes les fonctions sont entièrement virtuelles et donc vous devez dériver puis implémenter toutes les fonctions.
Dans une classe C ++, virtual est le mot-clé qui désigne cela, une méthode peut être remplacée (c'est-à-dire implémentée par) une sous-classe. Par exemple:
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;
};
Dans ce cas, une sous-classe peut remplacer la fonction initShape pour effectuer un travail spécialisé:
class Square : public Shape
{
public:
Square();
virtual ~Square();
protected:
virtual void initShape() // override the Shape::initShape function
{
setName("Square");
}
}
Le terme virtuel pur fait référence aux fonctions virtuelles qui doivent être implémentées par une sous-classe et qui n'ont pas été implémentées par la classe de base. Vous désignez une méthode comme virtuelle pure en utilisant le mot clé virtual et en ajoutant a = 0 à la fin de la déclaration de méthode.
Donc, si vous vouliez rendre Shape :: initShape pur virtuel, vous feriez ce qui suit:
class Shape
{
...
virtual void initShape() = 0; // pure virtual method
...
};
En ajoutant une méthode virtuelle pure à votre classe, vous faites de la classe une classe de base abstraite qui est très pratique pour séparer les interfaces de l'implémentation.
m_name
. Qu'est-ce que cela m_
signifie?
"Virtuel" signifie que la méthode peut être remplacée dans les sous-classes, mais a une implémentation directement appelable dans la classe de base. "Virtuel pur" signifie qu'il s'agit d'une méthode virtuelle sans implémentation directement appelable. Une telle méthode doit être remplacée au moins une fois dans la hiérarchie d'héritage - si une classe a des méthodes virtuelles non implémentées, les objets de cette classe ne peuvent pas être construits et la compilation échouera.
@quark souligne que les méthodes pure-virtual peuvent avoir une implémentation, mais comme les méthodes pure-virtual doivent être remplacées, l'implémentation par défaut ne peut pas être appelée directement. Voici un exemple d'une méthode pure-virtuelle avec une valeur par défaut:
#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;
}
Selon les commentaires, l'échec de la compilation est spécifique au compilateur. Dans GCC 4.3.3 au moins, il ne compilera pas:
class A {
public:
virtual void Hello() = 0;
};
int main()
{
A a;
return 0;
}
Production:
$ 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()
Comment fonctionne le mot-clé virtuel?
Supposons que l'homme est une classe de base, l'indien est dérivé de l'homme.
Class Man
{
public:
virtual void do_work()
{}
}
Class Indian : public Man
{
public:
void do_work()
{}
}
Déclarer do_work () comme virtuel signifie simplement: quel do_work () appeler sera déterminé UNIQUEMENT au moment de l'exécution.
Supposons que je le fasse,
Man *man;
man = new Indian();
man->do_work(); // Indian's do work is only called.
Si virtual n'est pas utilisé, le même est statiquement déterminé ou lié statiquement par le compilateur, selon l'objet qui appelle. Donc, si un objet de Man appelle do_work (), le do_work () de Man est appelé MÊME QUAND IL POINT SUR UN OBJET INDIEN
Je crois que la réponse la plus votée est trompeuse - Toute méthode, virtuelle ou non, peut avoir une implémentation remplacée dans la classe dérivée. En ce qui concerne spécifiquement C ++, la différence correcte est la liaison au moment de l'exécution (lorsque le virtuel est utilisé) et la compilation (lorsque le virtuel n'est pas utilisé mais qu'une méthode est remplacée et qu'un pointeur de base pointe vers un objet dérivé) la liaison des fonctions associées.
Il semble y avoir un autre commentaire trompeur qui dit:
"Justin, 'pur virtuel' est juste un terme (pas un mot-clé, voir ma réponse ci-dessous) utilisé pour signifier" cette fonction ne peut pas être implémentée par la classe de base. "
C'EST FAUX! Les fonctions purement virtuelles peuvent également avoir un corps ET PEUVENT ÊTRE MISES EN ŒUVRE! La vérité est que la fonction virtuelle pure d'une classe abstraite peut être appelée statiquement! Deux très bons auteurs sont Bjarne Stroustrup et Stan Lippman .... parce qu'ils ont écrit la langue.
Une fonction virtuelle est une fonction membre déclarée dans une classe de base et redéfinie par une classe dérivée. Les fonctions virtuelles sont hiérarchiques par ordre d'héritage. Lorsqu'une classe dérivée ne remplace pas une fonction virtuelle, la fonction définie dans sa classe de base est utilisée.
Une fonction virtuelle pure est une fonction qui ne contient aucune définition par rapport à la classe de base. Il n'a aucune implémentation dans la classe de base. Toute classe dérivée doit remplacer cette fonction.
Simula, C ++ et C #, qui utilisent la liaison de méthode statique par défaut, le programmeur peut spécifier que des méthodes particulières doivent utiliser la liaison dynamique en les étiquetant comme virtuelles. La liaison de méthode dynamique est au cœur de la programmation orientée objet.
La programmation orientée objet nécessite trois concepts fondamentaux: l'encapsulation, l'héritage et la liaison de méthode dynamique.
L'encapsulation permet de masquer les détails d'implémentation d'une abstraction derrière une interface simple.
L'héritage permet de définir une nouvelle abstraction comme une extension ou un raffinement d'une abstraction existante, obtenant automatiquement certaines ou toutes ses caractéristiques.
La liaison de méthode dynamique permet à la nouvelle abstraction d'afficher son nouveau comportement même lorsqu'elle est utilisée dans un contexte qui attend l'ancienne abstraction.
Les méthodes virtuelles PEUVENT être écrasées en dérivant des classes, mais ont besoin d'une implémentation dans la classe de base (celle qui sera écrasée)
Les méthodes virtuelles pures n'ont pas d'implémentation de la classe de base. Ils doivent être définis par des classes dérivées. (Donc, techniquement, ce n'est pas le bon terme, car il n'y a rien à remplacer).
Virtual correspond au comportement java par défaut, lorsque la classe dérivée remplace une méthode de la classe de base.
Les méthodes Pure Virtual correspondent au comportement des méthodes abstraites au sein des classes abstraites. Et une classe qui ne contient que des méthodes et des constantes virtuelles pures serait le cpp-pendant d'une interface.
Fonction virtuelle pure
essayez ce code
#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();
}
Dans la classe anotherClass, supprimez la fonction sayHellow et exécutez le code. vous obtiendrez une erreur! Parce que lorsqu'une classe contient une fonction virtuelle pure, aucun objet ne peut être créé à partir de cette classe et il est hérité alors sa classe dérivée doit implémenter cette fonction.
Fonction virtuelle
essayez un autre code
#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!
}
Ici, la fonction sayHellow est marquée comme virtuelle dans la classe de base.Elle dit le compilateur qui essaie de rechercher la fonction dans la classe dérivée et implémente la fonction.Si elle n'est pas trouvée, exécutez la base.Merci
"Une fonction virtuelle ou une méthode virtuelle est une fonction ou une méthode dont le comportement peut être remplacé dans une classe héritée par une fonction avec la même signature" - wikipedia
Ce n'est pas une bonne explication pour les fonctions virtuelles. Parce que, même si un membre n'est pas virtuel, l'héritage des classes peut le remplacer. Vous pouvez essayer de le voir vous-même.
La différence se montre lorsqu'une fonction prend une classe de base comme paramètre. Lorsque vous donnez une classe héritée en entrée, cette fonction utilise l'implémentation de classe de base de la fonction surchargée. Cependant, si cette fonction est virtuelle, elle utilise celle qui est implémentée dans la classe dérivée.
Les fonctions virtuelles doivent avoir une définition dans la classe de base et également dans la classe dérivée, mais pas nécessaire, par exemple la fonction ToString () ou toString () est une fonction virtuelle afin que vous puissiez fournir votre propre implémentation en la remplaçant dans la ou les classes définies par l'utilisateur.
Les fonctions virtuelles sont déclarées et définies en classe normale.
La fonction virtuelle pure doit être déclarée se terminant par "= 0" et elle ne peut être déclarée qu'en classe abstraite.
Une classe abstraite ayant une ou des fonctions virtuelles pures ne peut pas avoir de définition (s) de ces fonctions virtuelles pures, ce qui implique que l'implémentation doit être fournie dans des classes dérivées de cette classe abstraite.