Fonctions virtuelles
Une fonction virtuelle est une fonction membre qui doit être redéfini dans les classes dérivées.Lorsque vous faites référence à un objet de classe dérivée à l'aide d'un pointeur ou une référence à la classe de base, vous pouvez appeler une fonction virtuelle pour cet objet et exécuter la version de classe dérivée de la fonction.
Les fonctions virtuelles garantissent que la fonction correcte est appelée pour un objet, indépendamment de l'expression utilisée pour effectuer l'appel de fonction.
Supposons qu'une classe de base contient une fonction déclarée comme virtuel et une classe dérivée définit la même fonction.La fonction de la classe dérivée est appelée pour les objets de la classe dérivée, même si elle est appelée à l'aide d'un pointeur ou une référence à la classe de base.l'exemple suivant montre une classe de base qui fournit une implémentation de la fonction d' PrintBalance et de deux classes dérivées
// deriv_VirtualFunctions.cpp
// compile with: /EHsc
#include <iostream>
using namespace std;
class Account {
public:
Account( double d ) { _balance = d; }
virtual double GetBalance() { return _balance; }
virtual void PrintBalance() { cerr << "Error. Balance not available for base type." << endl; }
private:
double _balance;
};
class CheckingAccount : public Account {
public:
CheckingAccount(double d) : Account(d) {}
void PrintBalance() { cout << "Checking account balance: " << GetBalance() << endl; }
};
class SavingsAccount : public Account {
public:
SavingsAccount(double d) : Account(d) {}
void PrintBalance() { cout << "Savings account balance: " << GetBalance(); }
};
int main() {
// Create objects of type CheckingAccount and SavingsAccount.
CheckingAccount *pChecking = new CheckingAccount( 100.00 ) ;
SavingsAccount *pSavings = new SavingsAccount( 1000.00 );
// Call PrintBalance using a pointer to Account.
Account *pAccount = pChecking;
pAccount->PrintBalance();
// Call PrintBalance using a pointer to Account.
pAccount = pSavings;
pAccount->PrintBalance();
}
Dans le code précédent, les appels à PrintBalance sont identiques, à l'exception de les points d' pAccount d'objet.Étant donné qu' PrintBalance est virtuel, la version de la fonction définie pour chaque objet est appelée.la fonction d' PrintBalance dans les classes dérivées CheckingAccount et SavingsAccount « substituent » la fonction dans la classe de base Account.
S'il déclare une classe qui ne fournit pas d'implémentation de substitution de la fonction d' PrintBalance , l'implémentation par défaut de la classe de base Account est utilisée.
Fonctions dans les fonctions virtuelles de priorité des classes dérivées des classes de base uniquement si leur type est identique.Une fonction dans une classe dérivée ne peut pas différer d'une fonction virtuelle d'une classe de base dans son type de retour uniquement ; la liste d'arguments doit différer également.
en appelant une fonction utilisant des pointeurs ou des références, les règles suivantes s'appliquent :
Un appel à une fonction virtuelle est résolu en fonction de le type sous-jacent d'objet pour lequel elle est appelée.
Un appel à une fonction non virtuelle est résolu en fonction de le type du pointeur de la référence ou.
L'exemple suivant montre comment les fonctions virtuelles et non virtuelles se comportent une fois appelé via des pointeurs :
// deriv_VirtualFunctions2.cpp
// compile with: /EHsc
#include <iostream>
using namespace std;
class Base {
public:
virtual void NameOf(); // Virtual function.
void InvokingClass(); // Nonvirtual function.
};
// Implement the two functions.
void Base::NameOf() {
cout << "Base::NameOf\n";
}
void Base::InvokingClass() {
cout << "Invoked by Base\n";
}
class Derived : public Base {
public:
void NameOf(); // Virtual function.
void InvokingClass(); // Nonvirtual function.
};
// Implement the two functions.
void Derived::NameOf() {
cout << "Derived::NameOf\n";
}
void Derived::InvokingClass() {
cout << "Invoked by Derived\n";
}
int main() {
// Declare an object of type Derived.
Derived aDerived;
// Declare two pointers, one of type Derived * and the other
// of type Base *, and initialize them to point to aDerived.
Derived *pDerived = &aDerived;
Base *pBase = &aDerived;
// Call the functions.
pBase->NameOf(); // Call virtual function.
pBase->InvokingClass(); // Call nonvirtual function.
pDerived->NameOf(); // Call virtual function.
pDerived->InvokingClass(); // Call nonvirtual function.
}
Sortie
Derived::NameOf
Invoked by Base
Derived::NameOf
Invoked by Derived
Notez que que la fonction d' NameOf est appelée par l'intermédiaire d'un pointeur vers Base ou un pointeur vers Derived, il appelle la fonction pour Derived.Il appelle la fonction pour Derived car NameOf est une fonction virtuelle, et pBase et point d' pDerived à un objet de type Derived.
Étant donné que les fonctions virtuelles sont appelées uniquement pour les objets de type de classe, vous ne pouvez pas déclarer global ou des fonctions static comme virtuel.
Le mot clé de virtuel peut être utilisé en déclarant substituer s'exécute dans une classe dérivée, mais il est inutile ; les substitutions les fonctions virtuelles sont toujours virtuelles.
Les fonctions virtuelles dans une classe de base doivent être définies à moins qu'elles soient déclarées à l'aide de le spécificateur pure.(Pour plus d'informations sur les fonctions virtuelles purs, consultez classes abstraites.)
Le mécanisme virtuel de fonction-appel peut être supprimé en qualifiant explicitement le nom de fonction à l'aide de l'opérateur de résolution de portée (::).Considérez l'exemple précédent qui impliquent la classe d' Account .Pour appeler PrintBalance dans la classe de base, utilisez un code similaire à ce qui suit :
CheckingAccount *pChecking = new CheckingAccount( 100.00 );
pChecking->Account::PrintBalance(); // Explicit qualification.
Account *pAccount = pChecking; // Call Account::PrintBalance
pAccount->Account::PrintBalance(); // Explicit qualification.
Les deux appels à PrintBalance dans l'exemple précédent supprimez le mécanisme virtuel de fonction-appel.