虚拟关键字调用方法的大多数派生定义



我在读这篇文章覆盖与方法隐藏

我读到"..当在对象上调用虚拟方法时,该方法的最派生版本被称为"

但是当我执行以下代码时:

class A
{
    public virtual void print()
    {
        Console.WriteLine("A called");
        Console.Read();
    }
}
class B :A
{
    public override void print()
    {
        Console.WriteLine("B called");
        Console.Read();
    }
}
class C : B
{
    public override void print()
    {
        Console.WriteLine("C called");
        Console.Read();
    }
}
static void Main(string[] args)
{
    B b = new B();
    b.print(); it prints B?
}

它打印B。如果上面引用的说法是真的,它不应该是"C"吗?我错过了什么?在这种情况下,"最派生"是什么意思?

它将从调用它的实例的类型调用方法,您使用类B的实例来调用它,因此B的实现将被调用,如果您使用的是类C的实例,则C类的重写实现将被调用。

例如:

class B :A
{
    public override void print()
    {
        Console.WriteLine("B called");
        Console.Read();
    }
    public virtual void printfromB()
    {
        Console.WriteLine("printfromB in B called");
        Console.Read();
    }
}
class C : B
{
    public override void print()
    {
        Console.WriteLine("C called");
        Console.Read();
    }
    public override void printfromB()
    {
        Console.WriteLine("printfromB in C called");
        Console.Read();
    }
}

现在,如果你这样称呼它:

static void Main(string[] args)
{
    A a = new C();
    a.print(); // it prints C (most derived implementation called) 
    B b = new C();
    b.printfromB(); // it prints "printfromB in C called"
}
当实际类型为B时,不可能调用C

最初的"最派生"术语可以使用以下内容来理解:

A data = new C();
data.print();

即使编译器将data视为A,也会调用最派生的版本(不是A.printB.print,而是C.print)(这是因为方法是virtual)。

参见多态性

我认为你对答案中单词的技术性感到困惑。

这里有两件事,

  1. 在被实例化的派生类的上下文中方法的大多数派生版本

如果你这样做了,

A a = new B();
a. print(); // this will invoke the method on the class B,
                // since instance of class A has reference to instance of B.

如果您执行以下操作:

A a = new C();
a. print(); // Should call the method on class C, since base class has reference to to the instance of C.

同样,一种更直观的表达方式是:

A a = new A();
a.print(); // this will call the method print in class A irrespective of whether this method was overriden in one of the derived classes.

这是动态多态性的前提,其中,客户端可以对A的基类对象调用方法print()而不需要知道A是否引用了B或C。行为在客户端代码中动态变化。

  1. 或者,您也可以通过以下方式思考大多数派生版本:

假设方法print()在C中没有被覆盖,但在B中被覆盖,那么print()的最派生版本将在类B中。下面的snip应该会有所帮助。

class A
{
    public virtual void print()
    {
        Console.WriteLine("A called");
        Console.Read();
    }
}
class B :A
{
    public override void print()
    {
        Console.WriteLine("B called");
        Console.Read();
    }
}
class C : B
{
    public void somerandommethod()
    {
        // some random method not really relevant to this example.
    }
}
static void Main(string[] args)
{
    A a = new C();
    a.print(); // it will now print B (since B has the most derived implementation of print())
}

希望这个答案能有所帮助。

最好。

最新更新