关于父类C#中的虚方法

时间:2014-04-07 16:35:24

标签: c# .net oop polymorphism

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

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

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

5 个答案:

答案 0 :(得分: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

答案 1 :(得分:0)

只能覆盖标记为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,并不知道MyMethod类中OtherChild的实现,并且调用它所知道的那个:Parent

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

Polymorphism (computer science)

答案 2 :(得分:0)

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

答案 3 :(得分:0)

有很大的不同。我建议你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");
    }
}

答案 4 :(得分:0)

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

Parent p = new Parent();
Parent c = new Child();

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

如果你保持unvirtual,两行都会打印hello parent

有点现实世界的例子是:

Vehicle p = new Vehicle();
Vehicle c = new Car();

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