为什么要将方法声明为“虚拟”。
使用虚拟有什么好处?
答案 0 :(得分:45)
Virtual修饰符用于标记可以使用override修饰符在派生类中修改方法\属性(ect)。
示例:
class A
{
public virtual void Foo()
//DoStuff For A
}
class B : A
{
public override void Foo()
//DoStuff For B
//now call the base to do the stuff for A and B
//if required
base.Foo()
}
答案 1 :(得分:39)
Virtual允许继承类替换基类随后使用的方法。
public class Thingy
{
public virtual void StepA()
{
Console.Out.WriteLine("Zing");
}
public void Action()
{
StepA();
Console.Out.WriteLine("A Thingy in Action.");
}
}
public class Widget : Thingy
{
public override void StepA()
{
Console.Out.WriteLine("Wiggy");
}
}
class Program
{
static void Main(string[] args)
{
Thingy thingy = new Thingy();
Widget widget = new Widget();
thingy.Action();
widget.Action();
Console.Out.WriteLine("Press any key to quit.");
Console.ReadKey();
}
}
运行程序时,输出将为:
Zing
A Thingy in Action.
Wiggy
A Thingy in Action.
注意尽管Widget调用Thingy级别定义的Action()方法,但内部Thingy称为Widget的StepA()方法。
基本答案是它为类的继承者提供了更大的灵活性。当然,你必须很好地设计你的课程,否则它可能会造成严重破坏。
答案 2 :(得分:18)
虚方法是一种方法,其中实际的方法调用取决于底层对象的运行时类型。
非虚方法是一种方法,其中调用的实际方法取决于方法调用时对象的引用类型。
答案 3 :(得分:13)
虚拟关键字用于修改 方法或财产声明,in 方法或财产的情况 被称为虚拟成员。该 虚拟成员的实现可以 由一个压倒一切的成员改变 派生类。
当调用虚方法时, 检查对象的运行时类型 对于一个压倒一切的成员。该 覆盖最多的成员 调用类,可能是 原始成员,如果没有派生类 已覆盖该成员。 (更多 关于运行时类型和大多数的信息 派生实现,见10.5.3 虚拟方法。)
默认情况下,方法是非虚拟的。 您无法覆盖非虚拟 方法
您无法使用虚拟修改器 使用以下修饰符:
静态 抽象 覆盖
虚拟属性的行为类似于 抽象方法,除了 声明和差异 调用语法。
- 在静态属性上使用虚拟修饰符是错误的。
- 可以在派生类中重写虚拟继承属性 包括财产声明 使用覆盖修饰符。
答案 4 :(得分:6)
即使您不打算从类派生,也可能需要将方法标记为虚拟以模拟该类。一些模拟框架只允许您模拟虚拟方法。请注意,实现接口的方法是隐式虚拟的。
我使用具有此限制的RhinoMocks,并且出于这个原因默认将我的方法标记为虚拟。对我来说,这可能是使用虚方法的最大原因,因为继承发挥作用的情况要少得多。
答案 5 :(得分:5)
虚方法与基类中的抽象方法类似,只不过它们在派生类上的实现是可选的。您也可以将逻辑放在虚方法中,并在派生类中重写它们。
答案 6 :(得分:3)
为了能够在继承类中覆盖它。
查看关键字的MSDN entry。这更深入地解释了它。
答案 7 :(得分:3)
简短的问题,简短的回答! 如果您认为您将继承其所属的类,则将您的方法限定为“虚拟”。
更长的答案:“虚拟使您能够覆盖,在派生类中赋予您方法的另一种含义。
答案 8 :(得分:1)
毋庸置疑,当您的代码尝试遵守Open Closed Principle
时,虚拟方法会派上用场阅读更多关于开放封闭原则here,鲍勃叔叔的原始OCP白皮书。
另请注意,与Java不同,默认情况下,C#中的方法不虚拟。
答案 9 :(得分:1)
虚函数是不存在的函数。派生类可以通过覆盖来修改虚函数。虚函数是实现运行时多态的方法之一
public class sample {
public virtual void fun(){
Console.WriteLine("base sample class \n");
}
}
public class A : sample{
public override void fun(){
Console.WriteLine("Class A \n");
}
}
public class B : sample{
public override void fun(){
Console.WriteLine("Class B \n");
}
}
class run{
public static void main(String[] args){
sample obj = new sample();
sample obj1 = new A();
sample obj2 = new B();
obj.fun();
obj1.fun();
obj2.fun();
}
}
答案 10 :(得分:1)
这里用示例C# Virtual Method
清楚地解释了这一点答案 11 :(得分:1)
运行时在编译时发生
将方法声明为虚拟时,在派生类中声明它需要添加override
或new
修饰符。
我们可以看到TrySpeak
时。传递给孩子和父亲,两个人都叫父亲的说话,而TryScream
,则称为每个方法
要了解这一点,我们应该知道一些事情,在Child的实例中,Child类或父类中有两个Scream
方法。我们可以从Child类或Father类调用Scream
。
因为Virtaul
修饰符标记了方法,所以它可以被派生类覆盖,这意味着即使从父类调用Scream
,它也会被覆盖,如果使用new修饰符则它将是不同的。
import system;
class Father
{
Speak()
{
Console.Writeline("Father is speaking")
}
virtual Scream()
{
Console.Writeline("Father is screaming")
}
}
class Child: father
{
Speak()
{
Console.Writeline("Child is speaking")
}
override Scream()
{
Console.Writeline("Child is screaming")
}
}
class APP
{
public static void Main()
{
// We new two instances here
Father father = new Father();
Child child = new Child();
// Here we call their scream or speak through TryScream or TrySpeak
TrySpeak(father);
TrySpeak(child);
//>>>"Father is speaking"
//>>>"Father is speaking"
TryScream(father);
TryScream(child);
//>>>"Father is screaming"
//>>>"Child is screaming"
}
// when your method take an Parameter who type is Father
// You can either pass in a Father instance or
// A instance of a derived Class from Father
// which could be Child
public static void TrySpeak(Father person)
{
person.Scream();
}
public static void TryScream(Father person)
{
person.Speak();
}
}
答案 12 :(得分:0)
此链接将通过非常简单的示例为您提供更好的理解 https://stackoverflow.com/a/2392656/3373865
答案 13 :(得分:0)
虚拟方法与非虚拟方法之间的区别。
我们有两个班级;一个是车辆类,另一个是购物车类。 “车辆”类是具有两种方法的基类。一个是虚拟方法“ Speed()”,另一个是非虚拟方法“ Average()”。因此,基类虚拟方法“ Speed()”在子类中被覆盖。我们还有一个类“ Program”(执行类),该类具有一个入口点,在该入口处我们创建子类“ Cart”的实例,并将该实例分配给基类“ Vehicle”类型。当我们通过两个类的实例调用虚拟方法和非虚拟方法时,则根据运行类型,实例虚拟方法实现被调用。换句话说,两个类的实例都调用子类重写方法,并且基于该类的实例确定所调用的非虚拟方法。
using System;
namespace VirtualExample
{
class Vehicle
{
public double distance=0.0;
public double hour =0.0;
public double fuel =0.0;
public Vehicle(double distance, double hour, double fuel)
{
this.distance = distance;
this.hour = hour;
this.fuel = fuel;
}
public void Average()
{
double average = 0.0;
average = distance / fuel;
Console.WriteLine("Vehicle Average is {0:0.00}", average);
}
public virtual void Speed()
{
double speed = 0.0;
speed = distance / hour;
Console.WriteLine("Vehicle Speed is {0:0.00}", speed);
}
}
class Car : Vehicle
{
public Car(double distance, double hour, double fuel)
: base(distance, hour, fuel)
{
}
public void Average()
{
double average = 0.0;
average = distance / fuel;
Console.WriteLine("Car Average is {0:0.00}", average);
}
public override void Speed()
{
double speed = 0.0;
speed = distance / hour;
Console.WriteLine("Car Speed is {0:0.00}", speed);
}
}
class Program
{
static void Main(string[] args)
{
double distance,hour,fuel=0.0;
Console.WriteLine("Enter the Distance");
distance = Double.Parse(Console.ReadLine());
Console.WriteLine("Enter the Hours");
hour = Double.Parse(Console.ReadLine());
Console.WriteLine("Enter the Fuel");
fuel = Double.Parse(Console.ReadLine());
Car objCar = new Car(distance,hour,fuel);
Vehicle objVeh = objCar;
objCar.Average();
objVeh.Average();
objCar.Speed();
objVeh.Speed();
Console.Read();
}
}
}
希望能提供帮助!
答案 14 :(得分:0)
在C#中,要覆盖派生类中的基类方法,必须将基类方法声明为虚拟,将派生类方法声明为重写,如下所示:
using System;
namespace Polymorphism
{
class A
{
public virtual void Test() { Console.WriteLine("A::Test()"); }
}
class B : A
{
public override void Test() { Console.WriteLine("B::Test()"); }
}
class C : B
{
public override void Test() { Console.WriteLine("C::Test()"); }
}
class Program
{
static void Main(string[] args)
{
A a = new A();
B b = new B();
C c = new C();
a.Test(); // output --> "A::Test()"
b.Test(); // output --> "B::Test()"
c.Test(); // output --> "C::Test()"
a = new B();
a.Test(); // output --> "B::Test()"
b = new C();
b.Test(); // output --> "C::Test()"
Console.ReadKey();
}
}
}
由于派生类的方法可以同时是虚拟的和新的,因此您还可以使用virtual和new关键字来混合方法隐藏和方法重写。当您要进一步将派生类方法重写到下一个级别时,这是必需的,因为我正在重写C类中的B类,Test()方法,如下所示:
using System;
namespace Polymorphism
{
class A
{
public void Test() { Console.WriteLine("A::Test()"); }
}
class B : A
{
public new virtual void Test() { Console.WriteLine("B::Test()"); }
}
class C : B
{
public override void Test() { Console.WriteLine("C::Test()"); }
}
class Program
{
static void Main(string[] args)
{
A a = new A();
B b = new B();
C c = new C();
a.Test(); // output --> "A::Test()"
b.Test(); // output --> "B::Test()"
c.Test(); // output --> "C::Test()"
a = new B();
a.Test(); // output --> "A::Test()"
b = new C();
b.Test(); // output --> "C::Test()"
Console.ReadKey();
}
}
}
金色字词: virtual关键字用于修改在基类中声明的方法,属性,索引器或事件,并允许其在派生类中被覆盖。
override关键字用于将虚拟/抽象方法,属性,索引器或基类的事件扩展或修改为派生类。
新关键字用于将基类的方法,属性,索引器或事件隐藏到派生类中。
享受:-)