在 C# 中,虚函数(Virtual Function) 是一种允许子类重写(Override)父类方法的机制。通过虚函数,可以实现 运行时多态(Runtime Polymorphism),即在程序运行时根据对象的实际类型调用相应的方法。
虚函数的定义
在 C# 中,使用 virtual 关键字将一个方法声明为虚函数。子类可以通过 override 关键字重写该方法。
语法
cs
class BaseClass
{
public virtual void MyMethod()
{
Console.WriteLine("BaseClass.MyMethod");
}
}
class DerivedClass : BaseClass
{
public override void MyMethod()
{
Console.WriteLine("DerivedClass.MyMethod");
}
}
virtual:在基类中声明一个方法为虚函数,表示该方法可以被子类重写。
override:在子类中重写基类的虚函数。
虚函数的原理
方法表(VTable)
在 C# 中,虚函数的实现依赖于 方法表(Virtual Method Table, VTable)。每个类都有一个方法表,其中存储了虚函数的地址。
基类的虚函数在方法表中有自己的地址。
如果子类重写了虚函数,方法表中的地址会被替换为子类方法的地址。
运行时多态
当通过基类引用调用虚函数时,运行时会根据对象的实际类型查找方法表,并调用正确的方法。这就是 动态绑定(Dynamic Binding)。
示例代码
以下是一个完整的示例,展示了虚函数的定义和使用:
cs
using System;
class Animal
{
// 虚函数
public virtual void MakeSound()
{
Console.WriteLine("Animal makes a sound");
}
}
class Dog : Animal
{
// 重写虚函数
public override void MakeSound()
{
Console.WriteLine("Dog barks");
}
}
class Cat : Animal
{
// 重写虚函数
public override void MakeSound()
{
Console.WriteLine("Cat meows");
}
}
class Program
{
static void Main(string[] args)
{
Animal myAnimal = new Animal(); // 基类对象
Animal myDog = new Dog(); // 子类对象
Animal myCat = new Cat(); // 子类对象
myAnimal.MakeSound(); // 输出: Animal makes a sound
myDog.MakeSound(); // 输出: Dog barks
myCat.MakeSound(); // 输出: Cat meows
}
}
输出
cs
Animal makes a sound
Dog barks
Cat meows
关键点
虚函数的作用
允许子类重写父类的行为。
实现运行时多态。
virtual 和 override 的关系
只有用 virtual 声明的方法才能被 override 重写。
重写的方法必须与基类方法的签名一致。
base 关键字
在子类中,可以通过 base 关键字调用基类的虚函数。例如:
cs
public override void MakeSound()
{
base.MakeSound(); // 调用基类的方法
Console.WriteLine("Dog barks");
}
与抽象方法的区别
虚函数可以有默认实现,子类可以选择是否重写。
抽象方法(abstract)没有实现,子类必须重写。
注意事项
性能开销
虚函数的调用比非虚函数稍慢,因为需要通过方法表查找方法地址。
设计原则
只有在需要子类重写方法时才将其声明为虚函数。
避免滥用虚函数,以免增加代码的复杂性。
密封方法
如果不想让子类重写某个虚函数,可以在子类中使用 sealed 关键字将其密封。例如:
cs
public sealed override void MakeSound()
{
Console.WriteLine("This method cannot be overridden further.");
}
总结
虚函数是 C# 实现多态的重要机制。
通过 virtual 和 override 关键字,可以实现方法的重写和动态绑定。
虚函数的使用需要结合具体的业务场景,合理设计类的继承关系。