Freigeben über


Virtuelle Funktionen

Eine virtuelle Funktion ist eine Memberfunktion, die Sie erwarten, dass in abgeleiteten Klassen neu definiert werden.Wenn Sie ein Objekt der abgeleiteten Klasse mithilfe eines Zeigers oder einen Verweis auf die Basisklasse zugreifen, können Sie eine virtuelle Funktion für dieses Objekt aufrufen und die Version der abgeleiteten Klasse der Funktion ausführen.

Virtuelle Funktionen sicherzustellen, dass die richtige Funktion für ein Objekt aufgerufen wird, unabhängig vom Ausdruck, der verwendet wird, um den Funktionsaufruf ausführen.

Angenommen, eine Basisklasse eine Funktion enthält, die als virtuell deklariert und eine abgeleitete Klasse die gleiche Funktion definiert.Die Funktion von der abgeleiteten Klasse wird für Objekte der abgeleiteten Klasse aufgerufen, selbst wenn sie mithilfe eines Zeigers oder eines Verweises auf die Basisklasse aufgerufen wird.Im folgenden Beispiel wird eine Basisklasse, die eine Implementierung der PrintBalance-Funktion und zwei abgeleiteter Klassen werden

// 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();   
}

Im vorherigen Code ist die Aufrufe PrintBalance , mit Ausnahme des pAccount-Objekt verweist auf identisch.Da PrintBalance virtuell ist, wird die Version der Funktion, die für jedes Objekt definiert wird, aufgerufen.Die PrintBalance-Funktion in abgeleiteten Klassen überschrieben CheckingAccountSavingsAccount „und“ die Funktion in der Basisklasse Account.

Wenn eine Klasse deklariert wird, die keine PrintBalance Implementierung der überschreibenden Funktion bietet, ist die Standardimplementierung von der Basisklasse Account verwendet.

Funktionen in abgeleiteten Klassen überschrieben werden virtuelle Funktionen in Basisklassen nur, wenn ihr Typ derselbe ist.Eine Funktion in einer abgeleiteten Klasse kann nicht von einer virtuellen Funktion in einer Basisklasse nur in den Rückgabetyp unterscheiden. Außerdem muss sich die Argumentliste unterscheiden.

Wenn eine Funktion mithilfe der Zeiger oder der Verweise aufrufen, gelten folgende Regeln:

  • Ein Aufruf einer virtuellen Funktion wird entsprechend dem zugrunde liegenden Typ des Objekts aufgelöst, für den sie aufgerufen wird.

  • Ein Aufruf einer nicht virtuelle Funktion wird entsprechend dem Typ der Zeiger oder Verweis aufgelöst.

Im folgenden Beispiel wird gezeigt, wie virtuelle und nicht virtuelle Funktionen verhalten, wenn Sie von Zeigern aufgerufen werden:

// 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.
}

0y01k918.collapse_all(de-de,VS.110).gifOutput

Derived::NameOf
Invoked by Base
Derived::NameOf
Invoked by Derived

Beachten Sie, dass unabhängig davon, ob die NameOf-Funktion durch einen Zeiger auf Base oder einen Zeiger auf Derivedaufgerufen wird, es Derivedfür die Funktion aufgerufen wird.Er ruft die Funktion für Derived , da NameOf eine virtuelle Funktion ist und pBase und pDerived Punkt in ein Objekt des Typs Derivedan.

Da virtuelle Funktionen nur für Objekte von Klassentypen bezeichnet werden, können Sie nicht deklarieren oder global als statische Funktionen virtuell.

Das virtuell-Schlüsselwort kann verwendet werden, wenn überschreibende Funktionen in einer abgeleiteten Klasse deklariert. Es ist jedoch nicht erforderlich. Überschreibungen virtueller Funktionen sind immer praktisch.

Virtuelle Funktionen in einer Basisklasse müssen definiert werden, es sei denn, sie mithilfe des Rein Bezeichnerdeklariert werden.(Weitere Informationen über rein virtuelle Funktionen finden Sie unter Abstrakte Klassen).

Der Mechanismus zur virtuellen Funktionsaufruf unterdrückt werden kann, indem Sie explizit den Funktionsnamen mithilfe des Bereichsauflösungsoperators (::) gekennzeichnet.Betrachten Sie das vorherige Beispiel, das die Account-Klasse enthält.So PrintBalance in der Basisklasse aufrufen, um Code wie dem folgenden:

CheckingAccount *pChecking = new CheckingAccount( 100.00 );

pChecking->Account::PrintBalance();  //  Explicit qualification.

Account *pAccount = pChecking;  // Call Account::PrintBalance

pAccount->Account::PrintBalance();   //  Explicit qualification.

Beide Aufrufe PrintBalance im vorherigen Beispiel unterdrücken den Mechanismus zur Verbindungsanforderungs.

Siehe auch

Referenz

Zugriff auf die virtuellen Funktionen