6

我了解到虚拟方法的使用为方法/函数提供了默认行为。我的疑问是,当我们可以在派生类中使用“new”实现同名的方法(如在基类中)并且可以由对象分别调用它时,那么虚拟方法的用途是什么。例如;

class A
{
      public void F()
      {
         //default behavior
      }

      public virtual void G()
      {
         //default behavior
      }
}

class B:A
{
    new public void F()
     {
       //new behavior from that of class A
     }
    public override void G()
     {
      //new behavior from that of class A
     }
}

class Test
{
   public static void Main(string[] args)
     {
       //For calling A's method use same compile time and run time object
       A obj1 = new A();

       //For calling B's method use compile time object of A and run time of B
       A obj2 = new B();

       obj1.F(); //O/P is A's method result
       obj2.F(); //O/P is A's method result
       obj1.G(); //O/P is A's method result
       obj2.G(); //O/P is B's method result
}

我的问题是,当我们可以通过使用 A 类和 B 类的相同编译时对象和运行时对象来提供默认行为和派生行为时,为什么需要类 A 中的虚拟 G(),如下所示:

A obj1 = new A(); //for calling A's methods
B obj2 = new B(); //for calling B's methods
A obj3 = new B(); //for having default behavior of class A using B's run time object.

我得到的只是在虚拟的情况下,我们不需要再制作一个具有相同编译和运行时类型的对象。它可以通过一个对象来实现,即类型 A 的编译时间和类型 B 的运行时间。

4

2 回答 2

7

我的问题是,当我们可以通过使用相同的编译时和运行时对象以及通过使用 A 的编译时对象和 B 的运行时来提供默认行为和派生行为时,为什么需要类 A 中的虚拟 G()。

因为那时你只能使用已经知道的代码B。多态性的一半是允许您编写不关心它实际使用哪个子类的代码。

例如,我可以编写一个方法来将一个流的内容复制到另一个流,Stream.ReadStream.Write正是因为它们是虚拟或抽象方法。传入哪些实现并不重要。

您应该很少使用new方法修饰符 - 如果您真的想为非虚拟方法提供不同的行为,如果您创建一个完全不同的方法名称会更清楚,这样任何阅读代码的人都会明白这是一个非常独立的方法从基类中声明的那个。

于 2012-10-12T06:20:36.240 回答
0

Jon 指出另一个原因是,如果您隐藏使用 new 的实现,则对基类中方法的任何引用都是对基本实现的引用,而如果您覆盖任何调用,即使在基类中也使用覆盖方法

 protected virtual void Foo(){
 }

 private void Bar() {
     //do generic stuff
     Foo();
 }

如果一个类覆盖了 foo 那么这将改变调用 bar 的效果。这是某些设计模式的基础,例如 AbstractTemplate

于 2012-10-12T06:42:45.520 回答