为什么我们使用虚拟和覆盖?
为什么我们使用override和virtual如果它们在我们不使用override和virtual时会产生相同的效果?
例1:
class BaseClass { public virtual string call() { return "A"; } } class DerivedClass : BaseClass { public override string call() { return "B"; } }
输出:B
例2:
class BaseClass { public string call() { return "A"; } } class DerivedClass : BaseClass { public string call() { return "B"; } }
输出仍然是相同的:
输出:B
运行测试:
class Program { static void Main(string[] args) { DerivedClass dc = new DerivedClass(); Console.WriteLine(dc.call()); Console.ReadKey(); } }
编译器是否在编译时自动添加虚拟和覆盖?
如果有人向我解释使用虚拟和覆盖的原因,我会很高兴。
(注意,我正在悄悄忽略编译错误)
现在做:
BaseClass obj = new DerivedClass(); Console.WriteLine(obj.call());
没有virtual
,这将打印A
,实际上DerivedClass
应该写B
这是因为它简单地调用了BaseClass
实现(因为obj
被键入为BaseClass
,并且没有定义多态)。
Virtual和override是面向对象编程中inheritance的基本机制。 当您在C#或Java等语言中使用类时,这可能是最重要的事情。
http://en.wikipedia.org/wiki/Inheritance_(object-oriented_programming )
inheritance允许您重用代码,添加新字段,属性和方法或替换先前定义的类的方法和属性。
虚拟和覆盖允许您替换方法的内容,当我说替换时,我说替换。
我会建议你一个很好的例子。
public class MyClassEnglish { public virtual string SomethingToSay() { return "Hello!"; } public void WriteToConsole() { Console.WriteLine(this.SomethingToSay()); } } public class MyClassItalian : MyClassEnglish { public override string SomethingToSay() { return "Ciao!"; } } int main() { MyClassItalian it = new MyClassItalian(); it.WriteToConsole(); }
如果省略virtual和override,MyClassItalian将打印出“Hello!” 而不是“Ciao!”。
在您的示例中,您显示了一个阴影技术,但编译器应该给您一个警告。 如果要隐藏基类中的方法,则应添加“new”关键字。 隐藏方法并不是最重要的! 只是藏身。
我想到的一个可能用途是,例如,当您需要某种优化时,可以使用它。
public abstract class MySpecialListBase { public int Count() { return this.GetCount(); } protected abstract int GetCount(); } public sealed class MySpecialArrayList : MySpecialListBase { int count; public new int Count() { return this.count; } protected override int GetCount() { return this.count; } }
现在……您可以在所有代码中使用MySpecialListBase,当您调用Count()时,它将调用虚方法GetCount()。 但是如果你只使用MySpecialArrayList,它将调用非虚拟的优化Count()并返回一个字段,从而提高性能。
// This works with all kind of lists, but since it is a more general purpose method it will call the virtual method. public void MyMethod(MySpecialListBase list) { Console.WriteLine(list.Count()); } // This works only with MySpecialArrayList, and will use the optimized method. public void MyMethod(MySpecialArrayList list) { Console.WriteLine(list.Count()); }
最好的例子我可以想到它在哪里有用的是当你创建自己的对象(类)时,你必须将该对象的列表添加到combobox中。
将对象添加到combobox时,您希望能够控制每个项目显示的文本。 Object.toString是一个虚方法。 http://msdn.microsoft.com/en-us/library/system.object.tostring.aspx因此您可以覆盖该方法并设置.toString以通过覆盖它来显示有关对象的正确信息。
public MyClass() { private int ID; public override string ToString() { return "My Item:" + ID; } }
方法覆盖:
在父类中定义或实现虚方法然后在后代类中替换它的位置。
当您决定将方法声明为虚拟时,您将授予派生类以使用自己的实现扩展和覆盖该方法。 您也可以让扩展方法调用父方法的代码。
在大多数OO语言中,您还可以选择隐藏父方法。 当您使用相同的签名引入同一命名方法的新实现而不覆盖时,您将隐藏父方法。
C#重写在C#中,您在父类中使用virtual关键字指定虚方法,并使用override关键字在子类中扩展(或替换)它。
在descendant方法中使用base关键字来执行父方法中的代码,即base.SomeMethod()。
语法示例:
class Robot { public virtual void Speak() { } } class Cyborg:Robot { public override void Speak() { } }
覆盖详细信息您不能覆盖常规的非虚方法,也不能覆盖静态方法。 父方法的第一个版本必须是虚拟或抽象的。 您可以覆盖标记为virtual,abstract或override(已经被覆盖)的任何父方法。 方法必须具有相同的签名。 这些方法必须具有相同的可见性(相同的访问级别)。 使用base关键字引用父类,如base.SomeMethod()中所示。 C#覆盖示例以下代码片段演示如何使用virtual和override覆盖后代类中的父方法。
using System; class Dog { public virtual void Bark() { Console.WriteLine("RUFF!"); } } class GermanShepard:Dog { public override void Bark() { Console.WriteLine("Rrrrooouuff!!"); } } class Chiuaua:Dog { public override void Bark() { Console.WriteLine("ruff"); } } class InclusionExample { public static void Main() { Dog MyDog=new Dog(); MyDog=new GermanShepard(); MyDog.Bark(); // prints Rrrrooouuff!! MyDog=new Chiuaua(); MyDog.Bark(); // prints ruff; } }
使用New隐藏方法使用new关键字引入父方法的新实现(这会隐藏父方法)。 您可以在不使用new的情况下隐藏方法,但会收到编译器警告。 使用new将禁止警告。
new和override修饰符具有不同的含义。 new修饰符创建具有相同名称,签名和可见性的新成员,并隐藏原始成员。 override修饰符扩展了inheritance成员的实现,并允许您实现基于inheritance的多态。
避免引入新成员:有时有明确的理由引入具有相同名称,签名和父方法可见性的新方法。 在这些明显的案例中,引入新成员是一个强大的function。 但是,如果您没有明确的理由,那么通过将新方法命名为独特且适当的方法,避免引入新版本的方法。
class Robot : System.Object { public void Speak() { MessageBox.Show("Robot says hi"); } } class Cyborg : Robot { new public void Speak() { MessageBox.Show("hi"); } }
调用基类版本常见任务在OO中,首先执行父方法代码然后添加代码来扩展方法。 使用base关键字引用父类,如base.SomeMethod()中所示。
class Robot : System.Object { public virtual void Speak() { MessageBox.Show("Robot says hi"); } } class Cyborg : Robot { public override void Speak() { base.Speak(); MessageBox.Show("hi"); } }