Виртуальные функции
Виртуальная функция функцию-член, предполагается быть переопределить в производных классах.При обращении к объекту производного класса, используя указатель или ссылку на базовый класс можно вызвать виртуальные функции, объекта и выполнение версия производного типа функции.
Виртуальные функции убедитесь, что выбрана верная функция вызывается для объекта, независимо от выражения, используемого для вызова функции.
Предположим, что базовый класс содержит функцию, объявленная как Виртуальный и производный класс определяет одну и ту же функцию.Функция производного класса вызывается для объектов производного класса, даже если она вызывается с помощью указатель или ссылку на базовый класс.В следующем примере показан базовый класс, который содержит реализацию интерфейса PrintBalance функция и 2 производного класса
// 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();
}
В приведенном выше коде вызовы PrintBalance идентичны, за исключением объекта pAccount пункты.Поскольку PrintBalance фактически, называется версию функции, указанной для каждого объекта.PrintBalance функция в производных классах CheckingAccount и SavingsAccount "переопределение" функцию в базовом классе Account.
Если класс объявлен, который не предоставляет реализацию переопределяя PrintBalance функцию, реализация по умолчанию из базового класса Account используется.
Функции в производных классах переопределяют виртуальные функции в базовых классах, только если их тип одинаков.Функция в производном классе не может отличаться от виртуальной функции в базовом классе в возвращаемом типе только; список аргументов должен отличаться.
При вызове функции с помощью указателей или ссылки, применяются следующие правила.
Вызов виртуальной функции допускается в соответствии с основной тип объекта, для которого он вызывается.
Вызов функции nonvirtual разрешен в соответствии с типом указателя или ссылок.
В следующем примере показано, как виртуальные функции и nonvirtual поведение при вызове через указатели:
// 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.
}
Output
Derived::NameOf
Invoked by Base
Derived::NameOf
Invoked by Derived
Вне зависимости от того, заметьте NameOf функция, вызываемая с помощью указателя на Base или указатель Derivedон вызывается функция Derived.Вызывается функция Derived поскольку NameOf виртуальная функция, и оба pBase и pDerived наведите указатель на объект типа Derived.
Так как виртуальные функции вызываются только для объектов типов классов, нельзя объявить глобальные статические функции или Виртуальный.
Виртуальный ключевое слово может использоваться при объявлении переопределить функцию в производном классе, но необязательно. переопределение виртуальных функций всегда является виртуальным.
Виртуальные функции в базовом классе должен быть указан, если они не объявлен с помощью чисто-описатель.(Дополнительные сведения о функциях см. в разделе чисто виртуальными абстрактные классы.)
Фактически механизм вызова функции может быть подавлено явно указывать имя функции с помощью оператора разрешения области действия (::).Рассмотрим предыдущего примера include Account класс.Вызов PrintBalance в базовом классе, используйте следующий код:
CheckingAccount *pChecking = new CheckingAccount( 100.00 );
pChecking->Account::PrintBalance(); // Explicit qualification.
Account *pAccount = pChecking; // Call Account::PrintBalance
pAccount->Account::PrintBalance(); // Explicit qualification.
Оба вызова PrintBalance в предыдущем примере отключение механизма виртуальных вызова функции.