Kommentar
Åtkomst till den här sidan kräver auktorisering. Du kan prova att logga in eller ändra kataloger.
Åtkomst till den här sidan kräver auktorisering. Du kan prova att ändra kataloger.
En virtuell funktion är en medlemsfunktion som du förväntar dig ska omdefinieras i härledda klasser. När du refererar till ett härlett klassobjekt med hjälp av en pekare eller en referens till basklassen kan du anropa en virtuell funktion för objektet och köra den härledda klassens version av funktionen.
Virtuella funktioner säkerställer att rätt funktion anropas för ett objekt, oavsett vilket uttryck som används för att göra funktionsanropet.
Anta att en basklass innehåller en funktion som deklarerats som virtuell och att en härledd klass definierar samma funktion. Funktionen från den härledda klassen anropas för objekt i den härledda klassen, även om den anropas med hjälp av en pekare eller referens till basklassen. I följande exempel visas en basklass som tillhandahåller en implementering av PrintBalance funktionen och två härledda klasser
// deriv_VirtualFunctions.cpp
// compile with: /EHsc
#include <iostream>
using namespace std;
class Account {
public:
Account( double d ) { _balance = d; }
virtual ~Account() {}
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 checking( 100.00 );
SavingsAccount savings( 1000.00 );
// Call PrintBalance using a pointer to Account.
Account *pAccount = &checking;
pAccount->PrintBalance();
// Call PrintBalance using a pointer to Account.
pAccount = &savings;
pAccount->PrintBalance();
}
I föregående kod är anropen till PrintBalance identiska, förutom objektet pAccount pekar på. Eftersom PrintBalance är virtuell anropas den version av funktionen som definierats för varje objekt. Funktionen PrintBalance i de härledda klasserna CheckingAccount och SavingsAccount "åsidosätter" funktionen i basklassen Account.
Om en klass deklareras som inte tillhandahåller en övergripande implementering av PrintBalance funktionen används standardimplementeringen från basklassen Account .
Funktioner i härledda klasser åsidosätter endast virtuella funktioner i basklasser om deras typ är densamma. En funktion i en härledd klass kan inte skilja sig från en virtuell funktion i en basklass endast i sin returtyp. argumentlistan måste också skilja sig åt.
När du anropar en funktion med hjälp av pekare eller referenser gäller följande regler:
Ett anrop till en virtuell funktion matchas enligt den underliggande typen av objekt som den anropas för.
Ett anrop till en icke-virtuell funktion matchas enligt typen av pekare eller referens.
I följande exempel visas hur virtuella och icke-virtuella funktioner beter sig när de anropas via pekare:
// 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.
}
Derived::NameOf
Invoked by Base
Derived::NameOf
Invoked by Derived
Observera att oavsett om NameOf funktionen anropas via en pekare till Base eller en pekare till Derivedanropas funktionen för Derived. Den anropar funktionen för Derived eftersom NameOf är en virtuell funktion, och både pBase och pDerived pekar på ett objekt av typen Derived.
Eftersom virtuella funktioner endast anropas för objekt av klasstyper kan du inte deklarera globala eller statiska funktioner som virtual.
Nyckelordet virtual kan användas när du deklarerar övergripande funktioner i en härledd klass, men det är onödigt. Åsidosättningar av virtuella funktioner är alltid virtuella.
Virtuella funktioner i en basklass måste definieras såvida de inte deklareras med ren-specificerare. Mer information om rena virtuella funktioner finns i Abstrakta klasser.
Den virtuella funktionsanropsmekanismen kan ignoreras genom att uttryckligen kvalificera funktionsnamnet med hjälp av omfångsmatchningsoperatorn (::). Överväg det tidigare exemplet med Account klassen. Om du vill anropa PrintBalance i basklassen använder du kod som följande:
CheckingAccount *pChecking = new CheckingAccount( 100.00 );
pChecking->Account::PrintBalance(); // Explicit qualification.
Account *pAccount = pChecking; // Call Account::PrintBalance
pAccount->Account::PrintBalance(); // Explicit qualification.
Båda anropen till PrintBalance i föregående exempel undertrycker den virtuella funktionsanropsmekanismen.