2012-12-13 57 views
5

我有java的知识,并且在过去的几天里一直在学习c#。现在我遇到了“虚拟”关键字,如this link所建议的,用于允许在子类中覆盖相应的方法,属性等。现在我想我们可以重写方法,即使不使用“虚拟”关键字。那为什么有必要?c中的虚拟关键字#

+4

“现在我想我们可以重写方法,即使不使用'虚拟'关键字。”您认为? – BoltClock

+2

@BoltClock当然。基类中的'abstract'和派生类中的'override'就足够了。不需要'虚拟':P – CodesInChaos

+1

是的,虚拟的意思是“我提供了一个实现,但是你可能会多态地覆盖它”,而抽象的意思是“我定义了一些你必须提供的实现,它将以多态的方式运行”。与阴影(通常被认为是次优的)不同,函数签名必须匹配。 –

回答

11

如果您确实想在子类中使用override方法,则需要使用virtual关键字。否则,基础实现将被新实现隐藏,就像您使用关键字new声明了一样。

通过“覆盖”它们来隐藏方法,而不声明基方法virtual让您没有多态性,这意味着:如果您向“基本”版本“投射”特定版本并调用方法,则始终基类将会使用实现而不是重写的版本 - 这不是你所期望的。

实施例:

class A 
{ 
    public void Show() { Console.WriteLine("A"); } 
} 

class B : A 
{ 
    public void Show() { Console.WriteLine("B"); } 
} 

A a = new A(); 
B b = new B(); 

a.Show(); // "A" 
b.Show(); // "B" 

A a1 = b; 
a1.Show(); // "A"!!! 
2

现在我想我们可以重写方法,即使不使用“虚拟”关键字。

不,你不能。与Java相反,C#成员默认密码为,除非您使用关键字virtual标记它们,否则不能覆盖它们。

7

virtual是一种定义方法具有默认实现的方式,但该实现可能会在子类中被重写。除了使用虚拟外,不能使用new关键字直接覆盖方法(这通常是不好的做法)。

执行virtual的一个很好的例子是ToString()方法。 C#中的每个对象都能保证能够调用ToString(),因为每个对象都继承自基类System.Object类,其中包含虚拟方法ToString()。然而,派生类可以覆盖这个,并提供它们自己的实现,这可能对对象的用户更有用。

更新:我最近写了一篇博客文章,深入到这个主题。 Check it out here

1

在这个例子中请看:

void Main() 
    { 
     var o1 = new S(); 
     Console.WriteLine(((B)o1).m1());  
    } 

    public class B 
    { 
     public virtual string m1() { 
      return "m1"; 
     } 
    } 

    public class S : B 
    { 
     override public string m1() { 
      return "overridden m1"; 
     } 
    } 

在这个例子中的子类S被实例化并分配给对象变量o1。 在Console.WriteLine语句的参数中,它被投入到基类B中,然后调用方法m1。 因为我们已经在子类S使用virtual在基类Boverride,我们正在

重写M1

作为输出。如果您在子类中删除Svirtualm1方法声明中Boverride然后你得到

M1

作为输出,这意味着,中投也有效果的使用基类B中方法m1的原始声明。

N.B.如果您使用的子类Snew关键字,如

  new public string m1() { 
      return "overridden m1"; 
     } 

假设在基类Bvirtual关键字不存在,你得到的输出

M1

。如果您不会将其转换为B,则将使用新方法。这叫做遮蔽(或隐藏)一种方法(原始方法的基类)。

摘要:

  • 要覆盖的方法,如果你投的基类,它也应该是有效的,使用在基类的virtual关键字和override在子类。

  • 如果您打算重写只应在子类中激活的方法,请在子类方法声明中使用new关键字。正如你所看到的,它在没有它的情况下也能正常工作,但如果它在那里会更好,所以大家都知道这是该方法的新版本。