虚函数

程序示例

例如，一个基类Animal 有一个虚函数eat。子类Fish 要实做一个函数eat()，这个子类Fish 与子类Wolf 是完全不同的，但是你可以引用类别Animal 底下的函数eat() 定义，而使用子类Fish 底下函数eat() 的进程。

C++

以下代码是C++ 的程序示例。要注意的是，这个示例没有异常处理的代码。尤其是new 或是vector::push_back 丢出一个异常时，程序在运行时有可能会出现崩溃或是错误的现象。
# include <iostream># include <vector>using namespace std;class Animal{public:
    virtual void eat() const { cout << "I eat like a generic Animal." << endl; }
    virtual ~Animal() {}};
 
class Wolf : public Animal{public:
    void eat() const { cout << "I eat like a wolf!" << endl; }};
 
class Fish : public Animal{public:
    void eat() const { cout << "I eat like a fish!" << endl; }};
 
class GoldFish : public Fish{public:
    void eat() const { cout << "I eat like a goldfish!" << endl; }};
 
 
class OtherAnimal : public Animal{};
 
int main(){
    std::vector<Animal*> animals;
    animals.push_back( new Animal() );
    animals.push_back( new Wolf() );
    animals.push_back( new Fish() );
    animals.push_back( new GoldFish() );
    animals.push_back( new OtherAnimal() );
 
    for( std::vector<Animal*>::const_iterator it = animals.begin();
       it != animals.end(); ++it) 
    {
        (*it)->eat();
        delete *it;
    }
 
   return 0;}
以下是虚函数Animal::eat() 的输出：
I eat like a generic Animal.
I eat like a wolf!
I eat like a fish!
I eat like a goldfish!
I eat like a generic Animal.
当 Animal::eat() 不是被宣告为虚函数时，输出如下所示：
I eat like a generic Animal.
I eat like a generic Animal.
I eat like a generic Animal.
I eat like a generic Animal.
I eat like a generic Animal.

Java

在Java语言中, 所有的方法默认都是"虚函数". 只有以关键字final 标记的方法才是非虚函数. 以下是Java 中虚方法的一个例子:
import java.util.*;public class Animal {
   public void eat() { System.out.println("I eat like a generic Animal."); }
 
   public static void main(String[] args) {
      List<Animal> animals = new LinkedList<Animal>();

      animals.add(new Animal());
      animals.add(new Wolf());
      animals.add(new Fish());
      animals.add(new OtherAnimal());

      for (Animal currentAnimal : animals) {
         currentAnimal.eat();
      }
   }}
 
public class Wolf extends Animal {
   public void eat() { System.out.println("I eat like a wolf!"); }}
 
public class Fish extends Animal {
   public void eat() { System.out.println("I eat like a fish!"); }}
 
public class OtherAnimal extends Animal {}
 
输出:
I eat like a generic Animal.
I eat like a wolf!
I eat like a fish!
I eat like a generic Animal.

C#

在 C# 语言中, 对基类中的任何虚方法必须用virtual 修饰, 而派生类中由基类继承而来的重载方法必须用override 修饰. 以下是C# 的一个程序实例:
using System;using System.Collections.Generic;namespace ConsoleApplication1{
  public class Animal
  {
    public virtual void Eat()
    {
      Console.WriteLine("I eat like a generic Animal.");
    }
  }

  public class Wolf : Animal
  {
    public override void Eat()
    {
      Console.WriteLine("I eat like a wolf!");
    }
  }

  public class Fish : Animal
  {
    public override void Eat()
    {
      Console.WriteLine("I eat like a fish!");
    }
  }

  public class GoldFish : Fish
  {
    public override void Eat()
    {
      Console.WriteLine("I eat like a goldfish!");
    }
  }

  public class OtherAnimal : Animal
  {
    // Eat() method is not overridden, so the base class method will be used.
  }

  public class Program
  {
    public static void Main(string[] args)
    {
      IList<Animal> animals = new List<Animal>();
      
      animals.Add(new Animal());
      animals.Add(new Wolf());
      animals.Add(new Fish());
      animals.Add(new GoldFish());
      animals.Add(new OtherAnimal());

      foreach (Animal currentAnimal in animals)
      {
        currentAnimal.Eat();
      }
    }
  }}
 
输出:
I eat like a generic Animal.
I eat like a wolf!
I eat like a fish!
I eat like a goldfish!
I eat like a generic Animal.

抽象类和纯虚函数

纯虚函数或纯虚方法是一个需要被非抽象的派生类覆盖（override）的虚函数. 包含纯虚方法的类被称作抽象类; 抽象类不能被直接实例化。 一个抽象基类的一个子类只有在所有的纯虚函数在该类(或其父类)内给出实现时, 才能直接实例化. 纯虚方法通常只有声明(签名)而没有定义(实现)，但有特例情形要求纯虚函数必须给出函数体定义.
作为一个例子, 抽象基类"MathSymbol"可能提供一个纯虚函数doOperation(), 和派生类"Plus" 和 "Minus" 提供doOperation() 的具体实现. 由于 "MathSymbol" 是一个抽象概念, 为其每个子类定义了同一的动作, 在 "MathSymbol" 类中执行doOperation() 没有任何意义. 类似的, 一个给定的"MathSymbol" 子类如果没有doOperation() 的具体实现是不完全的.
虽然纯虚方法通常在定义它的类中没有实现, 在 C++ 语言中, 允许纯虚函数在定义它的类中包含其实现, 这为派生类提供了备用或默认的行为. C++的虚基类的虚析构函数必须提供函数体定义，否则链接时（linking）在析构该抽象类的派生实例对象的语句处会报错。

C++

在C++语言中, 纯虚函数用一种特别的语法[=0]定义（但 VS 也支持abstract 关键字：virtual ReturnType Function()abstract;）, 见以下示例.
class Abstract {public:
   virtual void pure_virtual() = 0;};
纯虚函数的定义仅提供方法的原型. 虽然在抽象类中通常不提供纯虚函数的实现, 但是抽象类中可以包含其实现, 而且可以不在声明的同时给出定义. 每个非抽象子类仍然需要重载该方法, 抽象类中实现的调用可以采用以下这种形式:
 void Abstract::pure_virtual() {
   // do something
 }
 
 class Child : public Abstract {
   virtual void pure_virtual(); // no longer abstract, this class may be
                                // instantiated.
 };
 
 void Child::pure_virtual() {
   Abstract::pure_virtual(); // the implementation in the abstract class 
                             // is executed
 }

构造与析构时的行为

在对象的构造函数和析构函数中涉及虚函数时，不同的语言有不同的规定。在以C++ 为代表的一些语言中，虚函数调度机制在对象的构造和析构时有不同的语义，一般建议尽可能避免在C++ 的构造函数中调用虚函数。而在C#、Java 等另一些语言中，构造时可以调用派生类中的实现，抽象工厂模式等设计模式也鼓励在支持这一特性的语言中使用这种用法。