惯性聚合 高效追踪和阅读你感兴趣的博客、新闻、科技资讯
阅读原文 在惯性聚合中打开

推荐订阅源

V
Visual Studio Blog
博客园 - 司徒正美
博客园_首页
Jina AI
Jina AI
奇客Solidot–传递最新科技情报
奇客Solidot–传递最新科技情报
月光博客
月光博客
I
InfoQ
M
MIT News - Artificial intelligence
T
Tailwind CSS Blog
L
LangChain Blog
Last Week in AI
Last Week in AI
A
About on SuperTechFans
B
Blog
博客园 - 叶小钗
雷峰网
雷峰网
H
Help Net Security
WordPress大学
WordPress大学
大猫的无限游戏
大猫的无限游戏
博客园 - 【当耐特】
云风的 BLOG
云风的 BLOG
Microsoft Azure Blog
Microsoft Azure Blog
小众软件
小众软件
aimingoo的专栏
aimingoo的专栏
OSCHINA 社区最新新闻
OSCHINA 社区最新新闻

博客园 - 书生

乐在其中设计模式(C#)系列文章索引 C#事件(event)解析 C#之委托的个人理解 NUnit2.0使用简单教程 如何将自己的代码自动添加版权信息的及其扩展 - 书生 - 博客园 浅谈.NET中的数据绑定表达式(二) - 书生 - 博客园 经典SQL语句集锦(收藏版) 获得字符串长度(中文字符占2) - 书生 - 博客园 Community Server的HttpHandler .NET继承本质论 如何将自己的代码自动添加版权信息 VS中常见的扩展名,看看你知道几个? 关于数据绑定表达式 读写xml节点的数据总结 Asp.net(C#)实现验证码功能 自定义编码解析函数示例 常用正则表达式,已封装为静态方法, 将自定义对象序列化为XML字符串 设置或者得到CheckBoxList选中了的值
谈谈C#中的三个关键词new , virtual , override
书生 · 2008-03-26 · via 博客园 - 书生

荒废了一段时间之后.还是觉得写写博客能充实一些,而且也可以更好的记录自己的点滴,鞭策自己的学习,积累都是从一点一滴做起来的,所以,还是从小事做起.

这几天在网上,看到有兄弟讨论

new , virtual , override 这三个关键词的区别,本身自己基础学的就不咋的,也趁这机会一点点的加强下.想起一句话,积累都是从平时做起的.

费话少说,先看一下MSDN上对于这三个关键字的定义使用 new 修饰符显式隐藏从基类继承的成员。若要隐藏继承的成员,请使用相同名称在派生类中声明该成员,并用 new 修饰符修饰它。


(按我的理解,就是一个基类.如果派生类中有和基类同名的方法时,要用new隐式声明,不然的话,是会有错误的.)
        
virtual 关键字用于修改方法或属性的声明,在这种情况下,方法或属性被称作虚拟成员。虚拟成员的实现可由派生类中的重写成员更改。

调用虚方法时,将为重写成员检查该对象的运行时类型。将调用大部分派生类中的该重写成员,如果没有派生类重写该成员,则它可能是原始成员。默认情况下,方法是非虚拟的。不能重写非虚方法。

不能将 virtual 修饰符与以下修饰符一起使用:

static      abstract      override

        使用 override 修饰符来修改方法、属性、索引器或事件。重写方法提供从基类继承的成员的新实现。由重写声明重写的方法称为重写基方法。重写基方法必须与重写方法具有相同的签名。

不能重写非虚方法或静态方法。重写基方法必须是虚拟的、抽象的或重写的。

重写声明不能更改虚方法的可访问性。重写方法和虚方法必须具有相同的访问级修饰符。

不能使用下列修饰符修改重写方法:

new     static      virtual     abstract

重写属性声明必须指定与继承属性完全相同的

看了之后有点晕,不要紧,借助于代码理解一下.

BaseClass.cs

using System;
using System.Collections.Generic;
using System.Text;

namespace newvirtualoverride
{
    
public class BaseClass
    
{

    
public BaseClass() { }

    
public   void Print()    

    
{     
    Console.WriteLine(
"BaseClassPrint");     
    }

    
    }

}


InheritClass.cs

using System;
using System.Collections.Generic;
using System.Text;

namespace newvirtualoverride
{
    
class InheritClass : BaseClass
    
{

        
public InheritClass() : base() { }   
  
       
public new virtual void Print() 
        

            Console.WriteLine(
"InheritClassPrint"); 
        }

    }

}

注意在派生类的同名Print方法的声明中,是用public new virtual void print()来声明的,如果这里写成public void print(),就会出错.上面有说到.

最后是主程序Program:

namespace NewVirtualOverride

{

    class Program

      {

        static void Main(string[] args)

          {

            BaseClass baseclass = new BaseClass();

              baseclass.Print();

            InheritClass inheritClass = new InheritClass();

              inheritClass.Print();

            Console.ReadLine();

          }

      }

}

运行这个程序会得到如下的结果:

BaseClassPrint

InheritClassPrint

下面我们看看virtual 和 override的搭配使用方法。

把BaseClass.cs改变如下:public virtual void Print();

把InheritClass.cs改变如下:public override void Print();

运行程序,结果如下:

BaseClassPrint

InheritClassPrint

     虽然结果与用new修饰符差不多,,但是其中的含意可不同,new是继承类对基类方法的重写而在继承类中产生新的方法,这时基类方法和继承方法之间没有任何的关系了,可是override就不同了,它也是对基类中方法的重写,但此时只是继承类重写了一次基类的方法。可以参考下面的例子来加深理解。

将Program.cs改变如下:

BaseClass baseclass = new BaseClass();

baseclass.Print();

InheritClass inheritClass = new InheritClass();

inheritClass.Print();

BaseClass bc = new InheritClass();

bc.Print();

分别运行用new修饰和用virtual/override修饰的程序,其结果如下:

new修饰的结果

BaseClassPrint

InheritClassPrint

BaseClassPrint

virtual/override修饰的结果:

BaseClassPrint

InheritClassPrint

InheritClassPrint

从上面的结果可以看出,在用new修饰的情况下,虽然bc是用InheritClass创建的实例,但是bc.Print()打印的还是BaseClassPrint,因为此时BaseClass和InheritClass中的Print已经是互不相同没有关系的两个方法了,而在virtual/override修饰的情况下,bc调用的Print方法已经被其子类override了,所以就打印了InheritClassPrint。

    最后我们再说说关键词之间的搭配关系,上面已经给出了virtual和override不兼容的几个关键词,这里就不重复了。我要说的是new和virtual在声明函数时,其实可以一块使用。因为这个函数是新的,故与其它任何new函数一样,隐藏了具有相同原型的继承来的函数。因为这个函数也是虚拟的,所以可以在派生类中进一步复位义,这样就为这个虚拟函数建立了一个新的基级别。最后用GrandsonClass类来看看。

GrandsonClass.cs修改如下:

namespace NewVirtualOverride

{

    class GrandsonClass : InheritClass

      {

        public GrandsonClass():base()

          {

          }

        public override void Print()

          {

            Console.WriteLine("GrandsonClassPrint");

          }

      }

}

InheritClass.cs修改如下:

namespace NewVirtualOverride

{

    class InheritClass : BaseClass

      {

        public InheritClass():base()

          {

          }

        new public virtual void Print()

          {

            Console.WriteLine("InheritClassPrint");

          }

      }

}

BaseClass.cs修改如下:

namespace NewVirtualOverride

{

    class BaseClass

      {

        public BaseClass()

          {

          }

        public virtual void Print()

          {

            Console.WriteLine("BaseClassPrint");

          }

      }

}

Program.cs修改如下:

namespace NewVirtualOverride

{

    class Program

      {

        static void Main(string[] args)

          {

            BaseClass baseclass = new BaseClass();

              baseclass.Print();

            InheritClass inheritClass = new InheritClass();

              inheritClass.Print();

            BaseClass grandsonClass = new GrandsonClass();

              grandsonClass.Print();

            Console.ReadLine();

          }

      }

}

运行结果为:

BaseClassPrint

InheritClassPrint

BaseClassPrint

注意第三个结果为BaseClassPrint,因为GrandsonClass类是派生于inheritClass,又因为inheritClass声明的为        new public virtual void Print(),所以这个方法和基类BaseClass是两个独立的,互相不影响的.所以会调用BaseClass的Print方法.

如果还不清楚,再看一下如果改为下面,结果会如何.
 Console.Out.WriteLine("***************************");
            BaseClass bc1 = new InheritClass();
            bc1.Print();

            BaseClass bc2 = new GrandsonClass();
            bc2.Print();


如果InheritClass和GrandsonClass都声明为new virtual的话.这时候都输出BaseClassPrint,道理同上如果InheritClass设为override,GrandsonClass声明为new virtual的话.这时候都输出InheritClassPrint.(第一个很好理解,因为InheritClass重写了基类,所以这里输出InheritClassPrint.第二个GrandsonClass这里声明为new virtual,我的理解是这样的.当 BaseClass bc2 = new GrandsonClass();
bc2.Print();因为GrandsonClass这里声明为new virtual所以它相对于InheritClassPrint的print方法,在这里是一个独立的方法,也就是和基类的方法是互相不影响的,所以会去调用它的基类,也就是InheritClassPrint中的print方法.)

如果InheritClass和GrandsonClass都声明为override,.这时候都输出InheritClassPrint,GrandsonClassPrint

如果InheritClass声明为new virtual,GrandsonClass声明为override,.这时候都输出BaseClassPrint,BaseClassPrint

c#是单继承,我的理解就是比如
        BaseClass bc2 = new GrandsonClass();
        bc2.Print();
        如果InheritClass为override,GrandsonClass为virtual,那么输出的为InheritClass

        如果InheritClass为virtual,GrandsonClass为override,那么输出的BaseClassPrint

先说这么多吧:)有什么不正确的地方,请大家指出.