想知道以下两者之间的区别:
情况1:基类
public void DoIt();
情况1:继承类
public new void DoIt();
情况2:基类
public virtual void DoIt();
情况2:继承类
public override void DoIt();
根据我运行的测试,情况1和情况2似乎具有相同的效果。是否存在区别或首选方法?
想知道以下两者之间的区别:
情况1:基类
public void DoIt();
情况1:继承类
public new void DoIt();
情况2:基类
public virtual void DoIt();
情况2:继承类
public override void DoIt();
根据我运行的测试,情况1和情况2似乎具有相同的效果。是否存在区别或首选方法?
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
覆盖了Base.DoIt
,那么会调用Derived.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
。它们实际上是两个完全独立的方法,只是恰好具有相同的名称,并不是派生方法覆盖了基本方法。
来源:Microsoft 博客
base.DoIt()
,会发生什么? - Joe Phillipsvirtual: 表示一个方法可以被继承者覆盖重写。
override: 覆盖基类中一个虚拟方法的功能,提供不同的功能。
new: 隐藏原始方法(不必是虚拟的),提供不同的功能。这应该只在绝对必要的情况下使用。
当您隐藏一个方法时,仍然可以通过向上转换到基类访问原始方法。这在某些情况下很有用,但也很危险。
virtual
关键字的情况下使用 override
和/或 new
吗? - Aaron Franke
new
表示尊重你的引用类型(赋值语句左侧),从而运行引用类型的方法。如果重新定义的方法没有new
关键字,则会被视为有该关键字。此外,它也被称为非多态继承。也就是说,“我正在派生类中创建一个全新的方法,与基类中任何同名方法都没有任何关系。” - 威特克(Whitaker)所说。override
必须与其基类中的virtual
关键字一起使用,表示尊重你的对象类型(赋值语句右侧),从而无论引用类型如何,都会运行被覆盖的方法。此外,它也被称为多态继承。
我记住这两个关键字的方式是将它们视为相反的。
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();
}
((BaseClass)(new InheritedClass())).DoIt()
编辑:virtual+override在运行时解决(所以override确实覆盖虚拟方法),而new只是创建一个同名的新方法,并隐藏旧方法,它在编译时解决 ->您的编译器将调用它“看到”的方法
如果您在将类型声明为基类时调用继承类的DoIt()方法,则即使如此,您也将看到基类的操作。
在情况1中。/* 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();
}
这两种情况的区别在于,在第一种情况中,基本的DoIt
方法没有被覆盖,只是被隐藏了。这意味着根据变量类型的不同,调用哪个方法也会不同。例如:
BaseClass instance1 = new SubClass();
instance1.DoIt(); // Calls base class DoIt method
SubClass instance2 = new SubClass();
instance2.DoIt(); // Calls sub class DoIt method
这可能会让人感到困惑,并导致非预期的行为,如果可能的话,应该避免使用这种方式。所以,首选的方法是第二种情况。
我曾经有同样的问题,这真的很令人困惑。你应该考虑到override
和new
关键字只适用于基类对象和派生类值的情况。只有在这种情况下,你才会看到override
和new
的效果:
所以如果你有A
和B
两个类,B
继承自A
,那么你可以像这样实例化一个对象:
A a = new B();