虚函数

虚函数是在派生类所需重新定义的成员函数。 当引用派生类对象使用指针或对基类时的引用,您可以调用该对象的虚函数和执行该函数的派生类的版本。

虚函数来确保正确的功能对对象调用,无论使用何种表达式进行函数调用。

假定基类包含作为 虚拟 声明的函数,并且派生类定义了相同功能。 从派生类的功能为派生类的对象调用,因此,即使它调用使用指针或引用给基类。 下面的示例演示提供 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.
}

0y01k918.collapse_all(zh-cn,VS.110).gifOutput

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 禁止显示虚函数调用框架。

请参见

参考

对于虚函数的访问