链接: 源码
在C#中,虚方法(virtual method)是一种特殊的方法,它允许派生类(子类)重写(override)该方法的实现。在C#中,虚方法(virtual method)是面向对象编程中的一个重要概念,它允许子类重写父类中的方法。当子类对象调用这个方法时,将执行子类中的重写版本,而不是父类中的原始版本.虚方法的主要目的是实现多态性,即允许基类的对象根据其实际类型(而不是其声明类型)来执行不同的行为。
下面是一个简单的例子来说明虚方法的使用:
// 基类
public class Animal
{
//普通方法
public void Walk()
{
Console.WriteLine("该动物在走路");
}
// 虚方法
public virtual void MakeSound()
{
Console.WriteLine("The animal makes a sound");
}
}
// 派生类
public class Dog : Animal
{
public void Walk()
{
Console.WriteLine("小狗在走路");
}
// 重写虚方法
public override void MakeSound()
{
Console.WriteLine("The dog barks");
}
}
// 派生类
public class Cat : Animal
{
//普通方法
public new void Walk() //虽然名字与基类的方法一致,但该方法与基类没有关系
{
Console.WriteLine("小猫在走路");
}
// 重写虚方法
//public override void MakeSound()
//{
// Console.WriteLine("The cat meows");
//}
}
// 主程序
class Program
{
static void Main(string[] args)
{
Animal animal1 = new Dog(); // Dog对象,但引用类型为Animal
Animal animal2 = new Cat(); // Cat对象,但引用类型为Animal
animal1.MakeSound(); // 输出 "The dog barks"
animal2.MakeSound(); // 输出 "The cat meows"
}
}
解析:
基类 Animal:
-
普通方法
Walk()
: 这是一个非虚(non-virtual)方法,直接定义了动物走路的行为,输出“该动物在走路”。 -
虚方法
MakeSound()
: 这是一个虚方法(marked with thevirtual
keyword),它提供了动物发出声音的基本行为,默认输出“ The animal makes a sound”。虚方法允许派生类对其进行重写(override),提供特定于派生类的声音表现。
派生类 Dog:
-
重写
Walk()
方法: 在Dog
类中,Walk()
方法被重定义,并使用override
关键字明确指出它正在覆盖基类Animal
中的同名虚方法。因此,当对Dog
类型的对象调用Walk()
时,将执行派生类中的实现,输出“小狗在走路”。 -
重写
MakeSound()
方法: 同样地,Dog
类重写了MakeSound()
虚方法,提供狗特有的叫声表现,输出“ The dog barks”。
派生类 Cat:
-
隐藏
Walk()
方法:Cat
类也重新定义了Walk()
方法,但这里使用的是new
关键字而非override
。这意味着尽管方法名称与基类中的相同,但这个新方法与基类的Walk()
没有继承关系,而是创建了一个新的独立方法,称为隐藏(hiding)。当对Cat
类型的对象调用Walk()
时,会执行派生类中的实现,输出“小猫在走路”。然而,如果通过一个Animal
类型的引用(实际指向Cat
对象)调用Walk()
,由于没有重写基类方法,仍将执行基类Animal
的Walk()
实现。 -
注释掉的
MakeSound()
方法: 在提供的代码中,Cat
类的MakeSound()
方法被注释掉了。若取消注释,则它会按照Dog
类的方式,重写Animal
中的MakeSound()
虚方法,提供猫特有的叫声表现(“The cat meows”)。由于当前注释状态,Cat
类并未提供自己的MakeSound()
实现,所以默认情况下会继承并使用基类Animal
中的MakeSound()
方法。
总结一下:
Dog
类通过override
重写了基类Animal
的两个方法:Walk()
和MakeSound()
,提供了狗特有的行为表现。Cat
类使用new
关键字隐藏了基类的Walk()
方法,提供了猫特有的走路行为。但未重写MakeSound()
方法,故仍使用基类的实现。
注意,对于方法的重写(override
)和隐藏(使用 new
关键字),两者在多态性和继承行为上有所不同:
- 重写(Override):保持了多态性,即通过父类引用调用子类对象的方法时,会调用子类的重写实现。
- 隐藏(New):破坏了多态性,通过父类引用调用子类对象的方法时,调用的是父类的方法。只有通过子类本身的引用调用时,才会执行隐藏的新方法。
注意:
- 如果一个方法在基类中被声明为
virtual
,那么任何派生类都可以使用override
关键字来重写该方法。 - 如果一个方法在基类中被声明为
override
,那么在派生类中不能再次重写它。但是,你可以在派生类中调用基类的实现(使用base.MethodName()
)。 - 如果一个方法没有被声明为
virtual
,那么它就是非虚方法,派生类不能重写它。尝试这样做会导致编译错误。 - 虚方法可以有访问修饰符(如
public
、protected
或private
),以及其他的修饰符(如static
、abstract
或sealed
)。但是,一个方法不能同时是virtual
和static
,也不能同时是virtual
和abstract
(尽管abstract
方法隐式地是虚的)。
英语
单词 | 音标 | 解释 | 例句 | 难点单词 | 拓展 |
---|---|---|---|---|---|
virtual | /ˈvɜːtʃuəl/ | adj. (通过计算机软件,如在互联网上)模拟的,虚拟的;几乎…的;实际上的;事实上的;实质上的;很接近的 | 1) The country was sliding into a state of virtual civil war. 2) players can compete in a virtual world of role playing… | ||
retrieve | /rɪˈtriːv/ | vt. 检索;取回;检索数据;找回;挽回;索回;扭转颓势 n. 恢复 记忆 re- 重新 + -trieve 找 | She bent to retrieve her comb from the floor. | ||
derive | /dɪˈraɪv/ | v. 得到;获得;(使)产生;取得;(使)起源 记忆 de- 离开,向下 + riv- 河流,流动 + -e | 1) Anna’s strength is derived from her parents and her sisters. 2) He derived great pleasure from painting. |