虚函数
虚函数是在派生类所需重新定义的成员函数。 当引用派生类对象使用指针或对基类时的引用,您可以调用该对象的虚函数和执行该函数的派生类的版本。
虚函数来确保正确的功能对对象调用,无论使用何种表达式进行函数调用。
假定基类包含作为 虚拟 声明的函数,并且派生类定义了相同功能。 从派生类的功能为派生类的对象调用,因此,即使它调用使用指针或引用给基类。 下面的示例演示提供 PrintBalance 功能和两个派生类中实现的基类
// 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 是虚拟的,为每个对象定义的函数的版本调用。 在派生类 CheckingAccount 和 SavingsAccount 的 PrintBalance 函数 “重写”在基类 Account的功能。
如果未提供 PrintBalance 函数的一个重写实现的类声明,使用从基类 Account 的默认实现。
,只有在其类型相同,在派生类中的函数重写基类中的虚函数。 在派生类中的函数不能与基类中的虚函数不同于其仅返回类型;参数列表必须不同。
在调用函数使用指针或引用,必须遵守以下规则时:
对于虚拟函数的调用以调用对象的基础类型解析。
对一个非虚拟函数的调用基于指针的类型解析或引用。
下面的示例演示虚方法或其功能的行为方式,在调用将指针:
// 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对象。
因为虚函数的类类型对象仅调用,不能声明全局或静态函数作为 虚拟。
在派生类可以使用 虚拟 关键字,在声明重写函数时,但是,它不是必需的;重写虚函数始终是虚拟的。
在基类中的虚函数使用这种 纯说明符,,,除非它们声明必须定义。 (有关纯虚函数的更多信息,请参见 抽象类。)
使用范围解析运算符 (::),虚函数调用框架可以通过显式限定函数名取消。 考虑对 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 禁止显示虚函数调用框架。