【问题标题】:About virtual method in parent class C# [duplicate]关于父类C#中的虚方法[重复]
【发布时间】:2014-04-07 16:35:23
【问题描述】:

我认为子类可以覆盖非虚拟的父方法

class Parent {
    public  void hello() {
        Console.WriteLine("Hello Parent");
    }
}
class Child:Parent{
    public void hello() {
        Console.WriteLine("Hello Child");
    }
    static void Main() {
        Parent p = new Child();
        Child c = new Child();
        p.hello();  // Hello Parent
        c.hello();  // Hello Child
    }
}

那么在父方法中 virtual 和 not virtual 有什么区别???

【问题讨论】:

标签: c# .net oop polymorphism


【解决方案1】:

在 C# 中,virtual methods support polymorphism,通过使用 virtual 和 override 关键字的组合。使用基类方法上的 virtual 关键字和派生类方法上的 override 关键字,这两种方法都称为虚拟方法。

没有 virtual 或 override 关键字,或者没有 new 关键字的方法被称为非虚拟的。

在对象上调用虚拟方法时,对象的运行时类型用于确定要使用的方法的实现。

在对象上调用非虚拟方法时,使用对象的编译时类型来确定要使用的方法的实现。

在这种情况下,您可以使用new 关键字

public new void hello()
{
    Console.WriteLine("Hello Child");
}

文字取自here

Read more about when to use override and new keyword

【讨论】:

    【解决方案2】:

    有很大的不同。我建议你read this and carefully go through the examples

    总而言之,您要处理的是方法覆盖与方法隐藏之间的区别。

    方法覆盖允许基类型访问派生类型的覆盖功能的行为。这就是您在派生类型的方法上使用 override 关键字时所做的事情,其中​​基类型的方法用 virtual 关键字标记。另一方面,在基类型的方法未标记为virtual 的更派生的方法上使用相同的方法签名就是所谓的方法隐藏。您实际上可以在不使用 new 关键字的情况下执行此操作,但您会收到编译器警告。

    方法隐藏失去了方法覆盖提供的多态优势,派生类的方法将使用隐藏方法的“新”行为,但基类将继续使用基类的方法版本。方法隐藏的结果可能看起来非常不直观,并且通常这些效果在 OOP 中是不受欢迎的,但它确实有它的位置。例如,我最喜欢的方法隐藏用途之一是 allow for easier unit testing of protected methods

    以下代码示例直接取自第一个链接,并简洁地说明了方法覆盖与方法隐藏的不同之处:

    class Program
    {
        static void Main(string[] args)
        {
            BaseClass bc = new BaseClass();
            DerivedClass dc = new DerivedClass();
            BaseClass bcdc = new DerivedClass();
    
            // The following two calls do what you would expect. They call
            // the methods that are defined in BaseClass.
            bc.Method1();
            bc.Method2();
            // Output:
            // Base - Method1
            // Base - Method2
    
    
            // The following two calls do what you would expect. They call
            // the methods that are defined in DerivedClass.
            dc.Method1();
            dc.Method2();
            // Output:
            // Derived - Method1
            // Derived - Method2
    
    
            // The following two calls produce different results, depending 
            // on whether override (Method1) or new (Method2) is used.
            bcdc.Method1();
            bcdc.Method2();
            // Output:
            // Derived - Method1
            // Base - Method2
        }
    }
    
    class BaseClass
    {
        public virtual void Method1()
        {
            Console.WriteLine("Base - Method1");
        }
    
        public virtual void Method2()
        {
            Console.WriteLine("Base - Method2");
        }
    }
    
    class DerivedClass : BaseClass
    {
        public override void Method1()
        {
            Console.WriteLine("Derived - Method1");
        }
    
        public new void Method2()
        {
            Console.WriteLine("Derived - Method2");
        }
    }
    

    【讨论】:

    • 谢谢:D 不同的情况:Parent p = new Child(); p.hello();
    【解决方案3】:

    子类中的方法 hello() 不会覆盖父类中的 hello 方法。子方法只是将实现隐藏在父类中

    【讨论】:

      【解决方案4】:

      只有标记为virtual 的方法可以被覆盖。其他可以隐藏(使用new 关键字),这根本不是一回事。

      class Parent
      {
          public virtual int MyMethod()
          {
              return 1;
          }
      }
      
      class Child : Parent
      {
          public override int MyMethod()
          {
              return 2;
          }
      }
      
      class OtherChild : Parent
      {
          public new int MyMethod()
          {
              return 3;
          }
      }
      // ...
      
      Parent p = new Parent();
      Parent c = new Child();
      Parent oc = new OtherChild();
      
      int result;
      
      result = p.MyMethod(); // will return 1
      result = c.MyMethod(); // will return 2
      result = oc.MyMethod(); // will return 1
      

      请注意,在上面的示例中,每个变量都声明为Parent。在第一个调用 MyMethod 将简单地返回基本实现。在第二个调用它调用在Child 类中找到的覆盖。然而,第三个声明为Parent,不知道MyMethodOtherChild 类中的实现,而是调用它知道的那个:在Parent 中。

      如果你想了解更多关于多态的知识,我建议你看看维基百科上的这篇文章:

      Polymorphism (computer science)

      【讨论】:

        【解决方案5】:

        问题在于您的测试代码,虚拟的力量是这样来的(如果您将方法设置为虚拟):

        Parent p = new Parent();
        Parent c = new Child();
        
        Console.WriteLine(p.hello()); //Prints Hello Parent
        Console.WriteLine(c.hello()); //Prints Hello Child
        

        如果你保持非虚拟,两行都会打印 hello parent

        有点现实世界的例子是这样的:

        Vehicle p = new Vehicle();
        Vehicle c = new Car();
        
        Console.WriteLine(p.Drive()); //Prints "Default Vehicle"
        Console.WriteLine(c.Drive()); //Prints "Car"
        

        【讨论】:

          猜你喜欢
          • 2018-06-12
          • 1970-01-01
          • 1970-01-01
          • 2016-04-12
          • 1970-01-01
          • 1970-01-01
          • 2018-06-02
          • 2016-10-22
          • 2018-11-05
          相关资源
          最近更新 更多