用例子来彻底搞明白Virtual 和 非 virtual(C#)

本文深入解析C#中Virtual关键字的使用方法及注意事项,包括不同情况下Virtual与非Virtual方法的行为差异,以及如何通过Override实现多态。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

对于Virtual的使用,有时候总有些犹豫,特别是最近学的东西太杂,今天化了点时间,把C#里面的Virtual彻底搞明白了。

virtual出问题主要是由于声明对象的类和对象实际所属的类不是一个类,一般都是父类和子类的关系。比如:
ClassParent obj = new ClassSub(),这是根源。

virtual和非virtual关键是在运行时候,而不是在编译时候。

1, 如果方法不是virtual的,编译器就使用声明的类对应的类型,也就是说,不是virtual的,在编译时候,就定了。比如下面的例子:子类的方法都没有执行,执行的全部都是父类的方法。运行的结果是
father
boy
girl


using System;


public class ClassFather

{

public string s1;

// virtual public void VirFun()

public void VirFun()

{ Console.WriteLine( s1 );}

}


public class ClassBoy : ClassFather

{

public new void VirFun()

{ base.VirFun();}

}


public class ClassGirl : ClassFather

{

public new void VirFun()

{

base.VirFun();

Console.WriteLine( s1 );

}

}


public class Test

{

public static void Main()

{

ClassFather a = new ClassFather();

a.s1 = "father";

a.VirFun();


ClassFather b = new ClassBoy();

b.s1 = "boy";

b.VirFun();


ClassFather c = new ClassGirl();

c.s1 = "girl";

c.VirFun();

}

}

2, 如果方法是Virtual的,然后子类使用了override, 编译器就生产代码。然后,在运行的时候,进行检测,看对象属于哪个类,然后调用这个类的方法。 这个是最常用的方法,基本上所有书上说的就是这个,我就不多此一举了。

3,如果一个父类的方法是virtual,子类不是用override,而是用new来覆盖了,那么运行子类的时候,还是执行声明的类的方法。比如下面的例子中,girl类对象就是。
using System;


public class ClassFather

{

public string s1;

virtual public void VirFun()

{ Console.WriteLine( s1 );}

}


public class ClassBoy : ClassFather

{

public override void VirFun()

{ base.VirFun();}

}


public class ClassGirl : ClassFather

{

public new void VirFun()

{

base.VirFun();

Console.WriteLine( s1 );

}

}


public class Test

{

public static void Main()

{

ClassFather a = new ClassFather();

a.s1 = "father";

a.VirFun();


ClassFather b = new ClassBoy();

b.s1 = "boy";

b.VirFun();


ClassFather c = new ClassGirl();

c.s1 = "girl";

c.VirFun();

}

}
 

### C# 中 `virtual` 关键字的用法与含义 在 C# 中,`virtual` 关键字用于指定一个方法、属性、索引器或事件可以在派生类中被重写。当一个成员被标记为 `virtual` 时,它表示该成员提供了一个默认实现,但允许派生类根据需要替换此实现[^2]。 #### 方法重写的机制 如果一个方法被声明为 `virtual`,那么在其派生类中可以使用 `override` 关键字来重写该方法的行为。重写意味着派生类提供了该方法的一个新实现,而不是直接使用基类中的实现。这种行为是通过运行时的动态绑定实现的,即调用哪个版本的方法取决于对象的实际类型,而不是引用的类型。 ```csharp public class Base { public virtual void printType() { Console.WriteLine("Base Class"); } } public class Derived : Base { public override void printType() { Console.WriteLine("Derived Class"); } } class Program { static void Main(string[] args) { Base b = new Derived(); b.printType(); // 输出 "Derived Class" } } ``` 在上述代码中,`printType` 方法被声明为 `virtual`,并在 `Derived` 类中通过 `override` 进行了重写。当通过基类类型的引用调用 `printType` 方法时,实际执行的是派生类中的实现,这是因为运行时解析了虚方法表[^2]。 #### 虚方法的行为 如果方法不是 `virtual` 的,则它是虚方法(non-virtual)。在这种情况下,方法调用是在编译时确定的,这意味着即使对象的实际类型是派生类,调用的仍然是基类中的方法实现[^2]。 ```csharp public class Base { public void printType() { Console.WriteLine("Base Class"); } } public class Derived : Base { public new void printType() { Console.WriteLine("Derived Class"); } } class Program { static void Main(string[] args) { Base b = new Derived(); b.printType(); // 输出 "Base Class" } } ``` 在上面的例子中,`printType` 方法是虚的,因此即使 `b` 引用的是 `Derived` 类型的对象,调用的仍然是基类中的实现[^2]。 #### 虚方法的作用 `virtual` 方法的主要作用是支持多态性。通过将方法声明为 `virtual`,可以确保在运行时根据对象的实际类型选择正确的方法实现。这使得程序能够以更加灵活动态的方式处理继承层次中的对象。 #### 注意事项 - 如果一个方法被声明为 `virtual`,则其派生类可以选择是否重写该方法。 - 使用 `virtual` 关键字时,必须确保该方法具有默认实现,否则会导致编译错误。 - 派生类中的方法必须使用 `override` 关键字来明确表示它正在重写基类中的虚方法。 ### 示例代码 以下是一个完整的示例,展示了如何使用 `virtual` `override`: ```csharp public class Animal { public virtual void Speak() { Console.WriteLine("Animal speaks"); } } public class Dog : Animal { public override void Speak() { Console.WriteLine("Dog barks"); } } public class Cat : Animal { public override void Speak() { Console.WriteLine("Cat meows"); } } class Program { static void Main(string[] args) { Animal myDog = new Dog(); Animal myCat = new Cat(); myDog.Speak(); // 输出 "Dog barks" myCat.Speak(); // 输出 "Cat meows" } } ``` 在上述代码中,`Speak` 方法被声明为 `virtual`,并且在 `Dog` `Cat` 类中被重写。运行时会根据对象的实际类型调用相应的实现。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值