C# 什么是虚拟方法?

C# 什么是虚拟方法?,c#,virtual,keyword,C#,Virtual,Keyword,为什么要将方法声明为“virtual” 使用virtual有什么好处?修饰符用于标记可以使用修饰符在派生类中修改方法\属性(ect) using System; class Father { Speak() { Console.Writeline("Father is speaking") } virtual Scream() { Console.Writeline("Father is sc

为什么要将方法声明为“virtual”

使用virtual有什么好处?

修饰符用于标记可以使用修饰符在派生类中修改方法\属性(ect)

using 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();
    }
}
例如:

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()
}

以便能够在继承类中重写它


检查关键字的列表。虚拟方法与基类中的抽象方法相似,只是它们在派生类上的实现是可选的。您还可以将逻辑放在虚方法中,并在派生类中重写这些逻辑。

virtual关键字用于修改 方法或属性声明,在 哪种情况是方法还是属性 被称为虚拟成员。这个 虚拟成员的实现可以 由中的重写成员更改 派生类

调用虚拟方法时 选中对象的运行时类型 对于重写成员。这个 在最派生的 类,它可能是 原始成员(如果没有派生类) 已覆盖该成员。(更多信息 有关运行时类型和most的信息 衍生实现,见10.5.3 虚拟方法。)

默认情况下,方法是非虚拟的。 您不能覆盖非虚拟对象 方法

不能使用虚拟修改器 使用以下修改器:

静态抽象覆盖

虚拟属性的行为类似于 抽象方法,但 声明和声明的差异 调用语法

  • 对静态属性使用虚拟修改器是错误的
  • 派生类中的虚拟继承属性可以由 包括一份财产声明 使用覆盖修改器

即使您不打算从该类派生,也可能需要将该方法标记为虚拟以模拟该类。一些模拟框架只允许模拟虚拟方法。注意,实现接口的方法是隐式虚拟的


我使用Rhinomock,它有这个限制,并且出于这个原因,默认情况下会将我的方法标记为虚拟。对我来说,这可能是使用虚拟方法的最大原因,因为继承起作用的情况要少得多。

不用说,当代码试图遵守

阅读更多关于开闭原则的内容,Bob叔叔最初的OCP白皮书


另外,请注意,与Java不同,C语言中的方法在默认情况下不是虚拟的。

虚拟方法是一种方法类型,其中实际的方法调用取决于底层对象的运行时类型


非虚拟方法是一种方法类型,其中实际调用的方法取决于方法调用点处对象的引用类型

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()方法


基本的答案是它给了类的继承者更多的灵活性。当然,你必须很好地设计你的课程,否则它可能会造成严重破坏。

一个简短的问题,一个简短的回答! 如果您认为将继承该方法所属类的名称,请将该方法限定为“virtual”


较长的回答:“虚拟使您能够重写,从而赋予派生类中方法的另一种含义。

虚拟函数是实际上不存在的函数。派生类可以通过重写来修改虚拟函数。虚拟函数是实现运行时多态性的方法之一

    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();
      }
    }

这里用示例清楚地解释了运行时是在编译时进行的。
当您将一个方法声明为虚拟时,在派生类中声明它需要您添加一个
重写
新建
修饰符。
我们可以看到,当
TrySpeak
传入child和father时,都会调用Speak of father,而
TryScream
会调用每个方法。
为了理解这一点,我们应该知道一些事情,在Child的实例中,有两个来自Child类或父类的
cream
方法。我们可以从Child类或父类调用
cream
。 因为
Virtaul
修饰符标记了该方法,所以它可以被派生类重写,这意味着即使是从父类调用
cream
,它也会被重写,如果使用新的修饰符,则会有所不同

using 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();
    }
}
在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();
 }
 }
}
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和new关键字混合方法隐藏和方法重写,因为派生类的方法可以同时是virtual和new。这是在我重写类C中的类B Test()方法时,当您希望进一步将派生类方法重写到下一级时所必需的,如下所示:

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();
 }
 }
}
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关键字用于将基类的虚拟/抽象方法、属性、索引器或事件扩展或修改为派生类

new关键字用于将基类的方法、属性、索引器或事件隐藏到派生类中

享受:-)

你说的“不存在”是什么意思?你能提供一个参考吗?这看起来不像C继承。在
class a
class B
之后的
public
访问修饰符会导致编译时错误。基类中成员的可访问性