Je suis un peu familier avec C ++, mais le mot-clé virtuel me confond toujours. Qu'est-ce que ça veut dire exactement? Si une fonction est définie comme virtuelle, est-ce la même chose que le virtuel pur?
Réponses
Trop de publicités?"Une fonction virtuelle ou une méthode virtuelle est une fonction ou une méthode dont le comportement peut être redéfinie dans une classe qui hérite d'une fonction avec la même signature" - wikipedia
"Une fonction virtuelle pure ou méthode virtuelle pure est une fonction virtuelle qui doit être mise en œuvre par une classe dérivée qui n'est pas abstrait" - Wikipedia
Ainsi, la fonction virtuelle peut être changé et le pur virtuel doit être mis en œuvre.
Aussi, un bon lien pour des questions de ce genre est http://www.parashift.com/c++-faq-lite/
Je voudrais commenter sur Wikipédia la définition du virtuel, comme répété par plusieurs ici. Wikipedia définit une méthode virtuelle comme celle qui peut être redéfinie dans les sous-classes. C'est faux: toute méthode, et pas seulement virtuels, peut être redéfinie dans les sous-classes. Ce virtuel n'est pour vous donner le polymorphisme, c'est la capacité à sélectionner au moment de l'exécution de la plupart des dérivés de substitution de méthode.
Considérons 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();
}
Qu'est-ce que la sortie de ce programme?
Base NonVirtual called.
Base Virtual called.
Base NonVirtual called.
Derived Virtual called.
Dérivé remplace chaque méthode de Base: pas seulement virtuelle, mais aussi les non-virtuel.
Nous voyons que lorsque vous avez une Base de pointeur-à-Dérivé (bDerived), l'appel de NonVirtual appelle la classe de Base de la mise en œuvre. Ce problème est résolu au moment de la compilation: le compilateur voit que bDerived est une Base*, qui NonVirtual n'est pas du virtuel, de sorte qu'il ne la résolution sur la classe de Base.
Toutefois, appeler les appels Virtuels de l'implémentation de la classe Dérivée. Parce que le mot-clé virtuel, la sélection de la méthode qui se passe au moment de l'exécution, et non pas au moment de la compilation. Ce qui se passe ici au moment de la compilation, le compilateur voit que c'est une Base de*, et qu'il appelle une méthode virtuelle, de sorte qu'il insérer un appel à la vtable au lieu de la classe de Base. Cette vtable est instanciée au moment de l'exécution, d'où le moment de l'exécution de la résolution de la plupart des dérivés de remplacement.
J'espère que ce n'était pas trop compliqué. En bref, toute méthode peut être remplacée, mais seulement des méthodes virtuelles vous donner le polymorphisme, qui est, au moment de l'exécution de sélection de la plupart des dérivés de remplacement. Dans la pratique, toutefois, le remplacement d'une non-méthode virtuelle est considéré comme une mauvaise pratique et rarement utilisé, de sorte que beaucoup de gens (y compris celui qui a écrit cette article de Wikipedia) pense que ce n'est que virtuel méthodes peuvent être remplacées.
Le mot-clé virtuel donne C++ sa capacité à prendre en charge le polymorphisme. Lorsque vous avez un pointeur vers un objet de classe tels 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 ce (idiot), par exemple, la GetNumberOfLegs() renvoie le nombre approprié basé sur la classe de l'objet qui lui est demandé.
Maintenant, considérons la fonction 'SomeFunction'. Il ne se soucie pas de quel type d'animal objet est passé pour elle, tant qu'il est dérivé de l'Animal. Le compilateur va automatiquement un cast d'un Animal de la classe dérivée d'un Animal, c'est une classe de base.
Si nous faisons cela:
Duck d;
SomeFunction(&d);
il avait sortie '2'. Si nous faisons cela:
Horse h;
SomeFunction(&h);
il avait sortie de '4'. Nous ne pouvons pas faire cela:
Animal a;
SomeFunction(&a);
parce qu'il ne compile pas en raison de la GetNumberOfLegs() fonction virtuelle pure, ce qui signifie qu'il doit être mis en œuvre par la dérivation des classes (sous-classes).
Des Fonctions Virtuelles pures sont principalement utilisés pour définir:
a) les classes abstraites
Ce sont les classes de base où vous devez tirer et ensuite mettre en œuvre les fonctions virtuelles pures.
b) les interfaces
Ce sont le "vide", les classes où toutes les fonctions sont virtuelles pures et par conséquent, vous devez tirer et ensuite de mettre en œuvre toutes les fonctions.
Dans une classe C++, le virtuel est le mot qui désigne qu'une méthode peut être remplacé (c'est à dire mis en œuvre 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 le initShape fonction pour effectuer certains travaux spécialisés:
class Square : public Shape
{
public:
Square();
virtual ~Square();
protected:
virtual void initShape() // override the Shape::initShape function
{
setName("Square");
}
}
Le terme virtuelle pure se réfère à des fonctions virtuelles qui doivent être mis en œuvre par une sous-classe et n'ont pas été mis en œuvre par la classe de base. Vous désigner une méthode virtuelle pure en utilisant le virtuel mot-clé et l'ajout d'un =0 à la fin de la déclaration de la méthode.
Donc, si vous avez voulu faire de la Forme::initShape virtuelle pure vous effectuez les opérations suivantes:
class Shape
{
...
virtual void initShape() = 0; // pure virtual method
...
};
Par l'ajout d'une méthode virtuelle pure dans votre classe, vous faites de la classe d'une classe de base abstraite ce qui est très pratique pour séparer les interfaces à partir de la mise en œuvre.
"Virtuelle" signifie que la méthode peut être redéfinie dans les sous-classes, mais a un directement-callable mise en œuvre dans la classe de base. "Virtuelle Pure" signifie qu'il s'agit d'une méthode virtuelle avec pas directement rachetables par anticipation de la mise en œuvre. Une telle méthode doit être remplacé au moins une fois dans la hiérarchie d'héritage -- si une classe a des, mis en oeuvre des méthodes virtuelles, des objets de cette classe ne peut pas être construit et la compilation échouera.
@quark souligne que pure méthodes virtuelles peuvent avoir une mise en œuvre, mais comme pure méthodes virtuelles doit être remplacée, l'implémentation par défaut ne peut pas être appelé directement. Voici un exemple d'un pur-méthode 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, qu'ils soient ou non de la compilation échouera est spécifique au compilateur. Dans GCC 4.3.3 au moins, il ne compile pas:
class A {
public:
virtual void Hello() = 0;
};
int main()
{
A a;
return 0;
}
Sortie:
$ 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()