250

想知道以下之间有什么区别:

案例 1:基类

public void DoIt();

案例一:继承类

public new void DoIt();

案例 2:基类

public virtual void DoIt();

案例2:继承类

public override void DoIt();

根据我运行的测试,案例 1 和 2 似乎具有相同的效果。有区别还是首选方式?

4

14 回答 14

323

override 修饰符可以用在虚方法上,而且必须用在抽象方法上。这表明编译器使用方法的最后定义实现。即使在对基类的引用上调用该方法,它也会使用覆盖它的实现。

public class Base
{
    public virtual void DoIt()
    {
    }
}

public class Derived : Base
{
    public override void DoIt()
    {
    }
}

Base b = new Derived();
b.DoIt();                      // Calls Derived.DoIt

Derived.DoIt如果覆盖将调用Base.DoIt

new 修饰符指示编译器使用您的子类实现而不是父类实现。任何不引用您的类但父类的代码都将使用父类实现。

public class Base
{
    public virtual void DoIt()
    {
    }
}

public class Derived : Base
{
    public new void DoIt()
    {
    }
}

Base b = new Derived();
Derived d = new Derived();

b.DoIt();                      // Calls Base.DoIt
d.DoIt();                      // Calls Derived.DoIt

会先打电话Base.DoIt,然后Derived.DoIt。它们实际上是两个完全独立的方法,它们恰好具有相同的名称,而不是覆盖基本方法的派生方法。

来源:微软博客

于 2009-09-09T11:35:14.520 回答
194

virtual:表示方法可以被继承者覆盖

override:覆盖基类中虚方法的功能,提供不同的功能。

new隐藏原始方法(不必是虚拟的),提供不同的功能。这应该只在绝对必要的情况下使用。

当你隐藏一个方法时,你仍然可以通过向上转换到基类来访问原始方法。这在某些情况下很有用,但很危险。

于 2009-09-09T11:36:10.387 回答
21

在第一种情况下,您将定义隐藏在父类中。这意味着只有当您将对象作为子类处理时才会调用它。如果将类转换为其父类型,则会调用父方法。在第二个实例中,该方法被重写,并且无论对象被转换为子类还是父类都将被调用。

于 2009-09-09T11:35:04.693 回答
11
  • new意味着尊重您的 REFERENCE 类型(左侧=),从而运行引用类型的方法。如果重新定义的方法没有new关键字,它的行为与它一样。此外,它也被称为非多态继承。也就是说,“我正在派生类中创建一个全新的方法,它与基类中的任何同名方法完全无关。” ——惠特克说
  • override,必须virtual在其基类中与关键字一起使用,表示尊重您的 OBJECT 类型(的右侧=),因此无论引用类型如何,都可以运行覆盖的方法。此外,它也被称为多态继承

我要记住这两个关键字是相反的。

override:virtual必须定义关键字以覆盖该方法。使用override关键字的方法,无论引用类型(基类的引用还是派生类的引用),如果用基类实例化,则基类的方法运行。否则,派生类的方法运行。

new:如果关键字被方法使用,与override关键字不同,引用类型很重要。如果它是用派生类实例化的,并且引用类型是基类,则运行基类的方法。如果它是用派生类实例化的,并且引用类型是派生类,则派生类的方法运行。即,是override关键词的对比。顺便说一句,如果您忘记或忽略向方法添加新关键字,编译器默认行为为new使用关键字。

class A 
{
    public string Foo() 
    {
        return "A";
    }

    public virtual string Test()
    {
        return "base test";
    }
}

class B: A
{
    public new string Foo() 
    {
        return "B";
    }
}

class C: B 
{
    public string Foo() 
    {
        return "C";
    }

    public override string Test() {
        return "derived test";
    }
}

主要调用:

A AClass = new B();
Console.WriteLine(AClass.Foo());
B BClass = new B();
Console.WriteLine(BClass.Foo());
B BClassWithC = new C();
Console.WriteLine(BClassWithC.Foo());

Console.WriteLine(AClass.Test());
Console.WriteLine(BClassWithC.Test());

输出:

A
B
B
base test
derived test

新代码示例,

通过一个一个注释来玩代码。

class X
{
    protected internal /*virtual*/ void Method()
    {
        WriteLine("X");
    }
}
class Y : X
{
    protected internal /*override*/ void Method()
    {
        base.Method();
        WriteLine("Y");
    }
}
class Z : Y
{
    protected internal /*override*/ void Method()
    {
        base.Method();
        WriteLine("Z");
    }
}

class Programxyz
{
    private static void Main(string[] args)
    {
        X v = new Z();
        //Y v = new Z();
        //Z v = new Z();
        v.Method();
}
于 2016-09-14T12:20:15.760 回答
8

尝试以下:(案例1)

((BaseClass)(new InheritedClass())).DoIt()

编辑:virtual+override 在运行时解析(所以 override 确实覆盖了虚拟方法),而 new 只是创建具有相同名称的新方法,并隐藏旧方法,它在编译时解析 -> 你的编译器将调用它'看到'

于 2009-09-09T11:34:38.453 回答
4

两种情况的区别在于,在情况 1 中,基本DoIt方法不会被覆盖,只是被隐藏了。这意味着取决于变量的类型取决于将调用哪个方法。例如:

BaseClass instance1 = new SubClass();
instance1.DoIt(); // Calls base class DoIt method

SubClass instance2 = new SubClass();
instance2.DoIt(); // Calls sub class DoIt method

这可能会非常令人困惑并导致非预期行为,应尽可能避免。所以首选的方法是案例2。

于 2009-09-09T11:38:03.017 回答
4

在案例 1 中,如果在类型被声明为基类时调用继承类的 DoIt() 方法,您甚至会看到基类的操作。

/* Results
Class1
Base1
Class2
Class2
*/
public abstract class Base1
{
    public void DoIt() { Console.WriteLine("Base1"); }
}
public  class Class1 : Base1 
{
    public new void DoIt() { Console.WriteLine("Class1"); }
}
public abstract class Base2
{
    public virtual void DoIt() { Console.WriteLine("Base2"); }
}
public class Class2 : Base2
{
    public override void DoIt() { Console.WriteLine("Class2"); }
}
static void Main(string[] args)
{
    var c1 = new Class1();
    c1.DoIt();
    ((Base1)c1).DoIt();

    var c2 = new Class2();
    c2.DoIt();
    ((Base2)c2).DoIt();
    Console.Read();
}
于 2009-09-09T11:41:39.717 回答
3

我有同样的问题,这真的很令人困惑,您应该考虑overridenew关键字仅适用于基类类型的对象和派生类的值。在这种情况下,只有你会看到 override 和 new 的效果:所以如果你有class Aand BB继承自A,那么你实例化一个像这样的对象:

A a = new B();

现在在调用方法时将考虑其状态。 Override:表示它扩展了方法的功能,然后它使用派生类中的方法,而new告诉编译器隐藏派生类中的方法并使用基类中的方法。这是该主题的一个很好的景象:

https://msdn.microsoft.com/EN-US/library/ms173153%28v=VS.140,d=hv.2%29.aspx?f=255&MSPPError=-2147217396

于 2016-04-14T09:03:21.803 回答
3

下面的文章在 vb.net 中,但我认为关于 new vs overrides 的解释很容易掌握。

https://www.codeproject.com/articles/17477/the-dark-shadow-of-overrides

在文章的某个地方,有这样一句话:

一般来说,Shadows 假设调用了与类型关联的函数,而 Overrides 假设执行了对象实现。

这个问题的公认答案是完美的,但我认为这篇文章提供了很好的例子,可以更好地说明这两个关键字之间的差异。

于 2017-04-11T12:52:43.107 回答
2

在此处输入图像描述

none、virtual、override、new 和 abstract 的所有组合:

于 2020-02-06T23:45:10.257 回答
1

如果在派生类中使用关键字override,则它会覆盖父方法。

如果在派生类中使用关键字new,则派生方法被父方法隐藏。

于 2013-03-01T12:06:37.470 回答
1

在所有这些中,new是最令人困惑的。通过实验,new 关键字就像是让开发人员可以选择通过显式定义类型来使用基类实现覆盖继承类实现。这就像反过来思考。

在下面的示例中,结果将返回“Derived result”,直到类型明确定义为 BaseClass 测试,然后才会返回“Base result”。

class Program
{
    static void Main(string[] args)
    {
        var test = new DerivedClass();
        var result = test.DoSomething();
    }
}

class BaseClass
{
    public virtual string DoSomething()
    {
        return "Base result";
    }
}

class DerivedClass : BaseClass
{
    public new string DoSomething()
    {
        return "Derived result";
    }
}
于 2017-08-22T15:55:25.403 回答
0

这些测试中不会显示功能差异:

BaseClass bc = new BaseClass();

bc.DoIt();

DerivedClass dc = new DerivedClass();

dc.ShowIt();

在这个例子中,被调用的 Doit 就是你期望被调用的那个。

为了看到差异,您必须这样做:

BaseClass obj = new DerivedClass();

obj.DoIt();

如果您运行该测试,您将看到在案例 1(如您定义的那样)DoIt()BaseClass调用 in,在案例 2(如您所定义的那样)DoIt()中调用 in DerivedClass

于 2016-02-23T15:28:41.887 回答
-1

在第一种情况下,它将调用派生类 DoIt() 方法,因为 new 关键字隐藏了基类 DoIt() 方法。

在第二种情况下,它将调用覆盖的 DoIt()

  public class A
{
    public virtual void DoIt()
    {
        Console.WriteLine("A::DoIt()");
    }
}

public class B : A
{
    new public void DoIt()
    {
        Console.WriteLine("B::DoIt()");
    }
}

public class C : A
{
    public override void DoIt()
    {
        Console.WriteLine("C::DoIt()");
    }
}

让我们创建这些类的实例

   A instanceA = new A();

    B instanceB = new B();
    C instanceC = new C();

    instanceA.DoIt(); //A::DoIt()
    instanceB.DoIt(); //B::DoIt()
    instanceC.DoIt(); //B::DoIt()

一切都在上面。让 instanceB 和 instanceC 设置为 instanceA 并调用 DoIt() 方法并检查结果。

    instanceA = instanceB;
    instanceA.DoIt(); //A::DoIt() calls DoIt method in class A

    instanceA = instanceC;
    instanceA.DoIt();//C::DoIt() calls DoIt method in class C because it was overriden in class C
于 2018-02-22T07:20:23.580 回答