运行时多态:方法重写
运行时多态也称为基于继承的多态或方法重写。
继承允许你将基类继承到派生类中,基类的所有公共成员都会自动成为派生类的成员。但是,你可以在派生类中重新定义基类的成员,以提供与基类不同的实现。这称为方法重写,也称为运行时多态。
在 C# 中,默认情况下,类的所有成员都是密封的,不能在派生类中重新定义。使用 virtual
关键字修饰基类的成员使其可重写,并在派生类中使用 override
关键字表示该基类成员在派生类中被重新定义。
class Person
{
public virtual void Greet()
{
Console.WriteLine("Hi! I am a person.");
}
}
class Employee : Person
{
public override void Greet()
{
Console.WriteLine("Hello! I am an employee.");
}
}
如你所见,Person
类中的 Greet()
方法是用 virtual 关键字定义的。这意味着该方法可以在派生类中使用 override
关键字重写。在 Employee
类中,Greet()
方法用 override 关键字重新定义。因此,派生类扩展了基类的方法。
现在问题来了,哪个方法会被调用,是基类的方法还是派生类的方法?这取决于对象的类型。你能猜出下面程序的输出吗?
Person p1 = new Person();
p1.Greet();
Person p2 = new Employee();
p2.Greet();
Employee emp = new Employee();
emp.Greet();
I am a human! I am a Manager! I am a Manager!
C# 将根据对象的类型而不是变量的类型来调用方法。如果你创建一个 Person
类的对象,它将调用 Person
类的 Greet()
方法;如果你创建一个 Employee
类的对象,它将调用 Employee
类的 Greet()
方法,无论它被分配给哪种类型的变量。
正如你在上一章学到的,C# 编译器在编译时多态中决定调用哪个方法。在运行时多态中,它将在运行时根据对象的类型来决定。
要理解为什么方法重写被称为运行时多态,请看下面的例子。
class Program
{
public static void Display(Person p){
p.Greet();
}
public static void Main()
{
Person p1 = new Person();
Display(p1);
Person p2 = new Employee();
Display(p2);
Employee emp = new Employee();
Display(emp);
}
}
I am a human! I am the Manager! I am the Manager!
在上面的例子中,Display()
方法接受一个 Person
类型的参数。因此,当你调用 Display()
方法时,你可以传入 Person
类型或 Employee
类型的对象。Display()
方法在编译时不知道你传入的参数类型。它在运行时可以是任何类型。这就是为什么方法重写被称为运行时多态。
重写规则
- 方法、属性、索引器或事件可以在派生类中被重写。
- 静态方法不能被重写。
- 基类方法必须使用 virtual 关键字,以表明这些方法可以被重写。
- 派生类必须使用 override 关键字来重写基类方法。
了解更多关于 virtual 和 override 关键字的信息。
如果我们不使用 virtual 和 override 关键字,并在派生类中重新定义基类方法会发生什么?在下一章中学习。