新的和覆盖之间的区别

Shi*_*iji 179 c# inheritance overriding new-operator

想知道以下几点之间的区别:

案例1:基类

public void DoIt();
Run Code Online (Sandbox Code Playgroud)

案例1:继承的类

public new void DoIt();
Run Code Online (Sandbox Code Playgroud)

案例2:基类

public virtual void DoIt();
Run Code Online (Sandbox Code Playgroud)

案例2:继承的类

public override void DoIt();
Run Code Online (Sandbox Code Playgroud)

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

rah*_*hul 246

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
Run Code Online (Sandbox Code Playgroud)

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
Run Code Online (Sandbox Code Playgroud)

Base.DoIt那么先打电话Derived.DoIt.它们实际上是两个完全独立的方法,它们碰巧具有相同的名称,而不是覆盖基本方法的派生方法.

来源:微软博客

  • 从具体类开始,检查它是否具有感兴趣的方法的实现.如果确实如此,那就完成了.如果没有,请在继承层次结构中向上一步,即检查超类是否具有感兴趣的方法.继续,直到找到感兴趣的方法. (5认同)
  • `这表示编译器使用方法的最后定义的实现.怎么能找到最后定义的方法实现? (4认同)
  • 还要注意,只有在基类将方法定义为“虚拟”时,您才能“覆盖”方法。“ virtual”一词是基类,它说:“嘿,当我调用此方法时,它实际上可以被派生的实现所替代,因此我事先并不真正知道我在运行时实际上在调用哪种方法。因此,`virtual`表示方法的占位符,这意味着未标记为`virtual`的方法不能被覆盖,但是您可以使用修饰符`new` _replace_派生类中的任何非虚拟方法。在派生级别可访问。 (2认同)
  • 如果您在派生类中逐字调用“base.DoIt()”会怎样? (2认同)

Jon*_*n B 168

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

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

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

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

  • @Mark - 调用者可能不知道实现,导致意外滥用. (3认同)
  • 为什么强制转换隐藏基本方法的方法很危险?或者,您是暗示总体上进行铸造很危险? (2认同)

tva*_*son 15

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


Vic*_*rov 14

在此输入图像描述

无、虚拟、覆盖、新和抽象的所有组合:

  • 这张桌子值得更多的喜爱。作为提醒,它比涵盖该主题的许多页官方文档更有帮助。 (5认同)

snr*_*snr 9

  • new意味着尊重您的 REFERENCE type(left-hand side of =) ,从而运行引用类型的方法。如果重新定义的方法没有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";
    }
}
Run Code Online (Sandbox Code Playgroud)

调用主:

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());
Run Code Online (Sandbox Code Playgroud)

输出:

A
B
B
base test
derived test
Run Code Online (Sandbox Code Playgroud)

新的代码示例,

通过一一注释来玩代码。

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();
}
Run Code Online (Sandbox Code Playgroud)


not*_*row 7

尝试以下:(case1)

((BaseClass)(new InheritedClass())).DoIt()
Run Code Online (Sandbox Code Playgroud)

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