new和override的区别

想知道以下两者之间的区别:

案例1:基类

public void DoIt();

案例1:继承类

public new void DoIt();

案例2:基类

public virtual void DoIt();

案例2:继承类

public override void DoIt();

根据我运行的测试,情况1和2似乎具有相同的效果。有区别吗,或者有更好的方式吗?

110828 次浏览

请尝试以下操作:(case1)

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

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

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

覆盖修饰符可以用于 虚方法和必须在上使用 抽象方法。这表明 编译器使用最后定义的 方法的实现。即使 的引用调用该方法 类的基类

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

新的修饰符指示 编译器来使用您的子类实现 而不是父类 实现。任何不是这样的代码 引用你的类而不是父类 类将使用父类 实现。< / p >

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。它们实际上是两个完全独立的方法,只是碰巧有相同的名称,而不是派生方法重写基方法。

来源:微软的博客

虚拟:表示方法可以被继承程序覆盖

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

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

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

这两种情况的区别在于,在情况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。

在情况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();
}

如果关键字override在派生类中使用,则它将重写父方法。

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

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

BaseClass bc = new BaseClass();


bc.DoIt();


DerivedClass dc = new DerivedClass();


dc.ShowIt();

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

为了看到区别,你必须这样做:

BaseClass obj = new DerivedClass();


obj.DoIt();

你会看到,如果你运行测试,在情况1(正如你定义的那样)中,BaseClass中的DoIt()被调用,在情况2(正如你定义的那样)中,DerivedClass中的DoIt()被调用。

我也有同样的问题,真的很困惑, 你应该考虑覆盖关键字只适用于基类类型的对象和派生类的值。在这种情况下,只有你会看到override和new的效果: 因此,如果你有class ABB继承自A,那么你可以这样实例化一个对象:

A a = new B();

现在调用方法将考虑它的状态。 覆盖:表示它扩展了方法的函数,然后在派生类中使用该方法,而告诉编译器将该方法隐藏在派生类中,而在基类中使用该方法。 下面是一个非常好的主题:

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

  • new表示尊重你的引用类型(=的左边),从而运行引用类型的方法。如果重定义的方法没有new关键字,它的行为就像它有一样。此外,它也被称为< / em > < em > non-polymorphic继承。也就是说, 我在派生类中创建了一个全新的方法 与基库中同名的任何方法完全无关 类。-由Whitaker说
  • override,必须在其基类中与virtual关键字一起使用,意味着尊重你的OBJECT类型(=的右边),因此 无论引用类型如何,在中重写的运行方法。此外,它也被称为< em > < / em >多态继承.

我的方法是记住这两个关键字,它们是彼此相反的。

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

new:如果关键字被一个方法使用,与override关键字不同,引用类型很重要。如果它是用派生类实例化的,并且引用类型是基类,则运行基类的方法。如果它是用派生类实例化的,并且引用类型是派生类,则运行派生类的方法。也就是说,它是override关键字的对比。顺便说一下,如果你忘记或忽略向方法添加new关键字,编译器默认行为为使用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();
}

下面的文章是在vb.net,但我认为关于新的vs重写的解释是很容易理解的。

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

在文章的某个地方,出现了这样一句话:

通常,Shadows假定与类型相关联的函数为 调用,而override假设对象实现为 执行。< / p >

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

在所有这些中,是最令人困惑的。通过实验,new关键字就像给开发人员提供了一个选项,通过显式定义类型,用基类实现覆盖继承的类实现。这就像反过来思考一样。

在下例中,结果将返回"Derived result",直到类型显式定义为BaseClass test,才会返回"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";
}
}

enter image description here

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