为什么我们使用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();
}
}
编译器是否在编译时自动添加虚拟和覆盖?
如果有人向我解释使用虚拟和覆盖的原因,我会很高兴。
答案 0 :(得分:21)
(注意,我正在悄悄忽略编译错误)
现在做:
BaseClass obj = new DerivedClass();
Console.WriteLine(obj.call());
如果没有virtual
,那么当A
实际应该写DerivedClass
时,会打印B
。这是因为它只是调用BaseClass
实现(因为obj
被输入为BaseClass
,并且没有定义多态)。
答案 1 :(得分:5)
Virtual和override是面向对象编程中继承的基本机制。 当您在C#或Java等语言中使用类时,这可能是最重要的事情。
http://en.wikipedia.org/wiki/Inheritance_(object-oriented_programming)
继承允许您重用代码,添加新字段,属性和方法或替换先前定义的类的方法和属性。
虚拟和覆盖允许您替换方法的内容,当我说替换时,我说替换。
我会给你一个很好的例子。
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();
}
如果省略虚拟和覆盖,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());
}
答案 2 :(得分:0)
最好的例子我可以想到它在哪里有用的是当你创建自己的对象(类)时,你必须将该对象的列表添加到组合框中。
将对象添加到组合框时,您希望能够控制每个项目显示的文本。 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;
}
}
答案 3 :(得分:0)
方法覆盖:
在父类中定义或实现虚方法,然后在后代类中替换它。
当您决定将方法声明为虚拟时,您将授予派生类以使用自己的实现扩展和覆盖该方法。您也可以让扩展方法调用父方法的代码。
在大多数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和override修饰符具有不同的含义。 new修饰符创建具有相同名称,签名和可见性的新成员,并隐藏原始成员。 override修饰符扩展了继承成员的实现,并允许您实现基于继承的多态。
避免引入新成员:有时有明确的理由引入具有相同名称,签名和父方法可见性的新方法。在那些明显的案例中,引入新成员是一个强大的功能。但是,如果您没有明确的理由,那么通过将新方法命名为唯一且恰当的方法,避免引入新版本的方法。
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");
}
}