关于父类C#中的虚拟方法

本文关键字:虚拟 方法 于父类 父类 | 更新日期: 2023-09-27 17:57:25

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

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

那么,在父方法中,虚拟和非虚拟有什么不同呢???

关于父类C#中的虚拟方法

在C#中,虚拟方法通过使用virtual和override关键字的组合来支持多态性。基类方法上有virtual关键字,派生类中的方法上有override关键字,这两个方法都被认为是虚拟的。

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

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

当对对象调用非虚拟方法时,将使用对象的编译时类型来确定要使用该方法的哪个实现。

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

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

文本取自此处

阅读有关何时使用覆盖和新关键字的更多信息

有很大的区别。我建议你仔细阅读这些例子。

总之,您要处理的是方法重写和方法隐藏之间的区别。

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

方法隐藏失去了方法重写所提供的多态性好处,因为派生类的方法将使用隐藏方法的"新"行为,但基类将继续使用基类版本的方法。方法隐藏的结果可能看起来很不直观,通常在OOP中效果是不可取的,但它确实有自己的位置。例如,我最喜欢使用方法隐藏的一个用途是允许更容易地对受保护的方法进行单元测试。

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

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

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

只有标记为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,它不知道OtherChild类中MyMethod的实现,而是调用它知道的Parent

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

多态性(计算机科学)

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

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

如果你保持它不真实,两行都会打印你好家长

现实世界中的一个例子是:

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