今天仔细学习了一下C#中virtual, override, new关键字,参考了网上的很多资料,现整理一下。

Virtual:

virtual 关键字用于修饰方法、属性、索引器或事件声明,并使它们可以在派生类中被重写。默认情况下,方法是非虚拟的。不能重写非虚方法。virtual 修饰符不能与 static、abstract, private 或 override 修饰符一起使用。

Override:

override 方法提供从基类继承的成员的新实现。由 override 声明重写的方法称为重写基方法。重写的基方法必须与 override 方法具有相同的签名。重写的基方法必须是vitural,override,abstract类型的 ,不能重写非虚方法或是静态方法,所以override不能与vitural,new,static同时使用

override 属性必须指定与继承属性完全相同的访问修饰符、类型和名称,并且被重写的属性必须是 virtual、abstract 或 override 的。

New:

new 修饰符显式隐藏从基类继承的成员(即隐藏父类同签名方法)。 不标识时虽会出现编译警告,不影响使用

---------------------

函数调用实际流程:

虚拟函数从C#的程序编译的角度来看,它和其它一般的函数有什么区别呢?一般函数在编译时就静态地编译到了执行文件中,其相对地址在程序运行期间是 不发生变化的,也就是写死了的!而虚函数在编译期间是不被静态编译的,它的相对地址是不确定的,它会根据运行时期对象实例来动态判断要调用的函数,其中那 个申明时定义的类叫申明类,那个执行时实例化的类叫实例类。

如:飞禽 bird = new 麻雀();
那么飞禽就是申明类,麻雀是实例类。

具体的检查的流程如下

1、当调用一个对象的函数时,系统会直接去检查这个对象申明定义的类,即申明类,看所调用的函数是否为虚函数;

2、如果不是虚函数,那么它就直接执行该函数。而如果有virtual关键字,也就是一个虚函数,那么这个时候它就不会立刻执行该函数了,而是转去检查对象的实例类。

3、在这个实例类里,他会检查这个实例类的定义中是否有重新实现该虚函数(通过override关键字),如
果是有,那么OK,它就不会再找了,而马上执行该实例类中的这个重新实现的函数。而如果没有的话,系统就会不停地往上找实例类的父类,并对父类重复刚才在
实例类里的检查,直到找到第一个重载了该虚函数的父类为止,然后执行该父类里重载后的函数。

知道这点,就可以理解下面代码的运行结果了:

 using System;
namespace Smz.Test
{
class A
{
public virtual void Func() // 注意virtual,表明这是一个虚拟函数
{
Console.WriteLine("Func In A");
}
}
class B : A // 注意B是从A类继承,所以A是父类,B是子类
{
public override void Func() // 注意override ,表明重新实现了虚函数
{
Console.WriteLine("Func In B");
}
}
class C : B // 注意C是从A类继承,所以B是父类,C是子类
{
}
class D : A // 注意B是从A类继承,所以A是父类,D是子类
{
public new void Func() // 注意new ,表明覆盖父类里的同名类,而不是重新实现。注意这里如果不用new,此时D的func就与父类A的func重名了,会出现一个警告,虽然程序仍然会调用A中的func,所以new能消除警告。
{
Console.WriteLine("Func In D");
}
}
class program
{
static void Main()
{
A a; // 定义一个a这个A类的对象.这个A就是a的申明类
A b; // 定义一个b这个A类的对象.这个A就是b的申明类
A c; // 定义一个c这个A类的对象.这个A就是b的申明类
A d; // 定义一个d这个A类的对象.这个A就是b的申明类
a = new A(); // 实例化a对象,A是a的实例类
b = new B(); // 实例化b对象,B是b的实例类
c = new C(); // 实例化b对象,C是b的实例类
d = new D(); // 实例化b对象,D是b的实例类
a.Func(); // 执行a.Func:1.先检查申明类A 2.检查到是虚拟方法 3.转去检查实例类A,就为本身 4.执行实例类A中的方法 5.输出结果 Func In A
b.Func(); // 执行b.Func:1.先检查申明类A 2.检查到是虚拟方法 3.转去检查实例类B,有重载的 4.执行实例类B中的方法 5.输出结果 Func In B
c.Func(); // 执行c.Func:1.先检查申明类A 2.检查到是虚拟方法 3.转去检查实例类C,无重载的 4.转去检查类C的父类B,有重载的 5.执行父类B中的Func方法 5.输出结果 Func In B
d.Func(); // 执行d.Func:1.先检查申明类A 2.检查到是虚拟方法 3.转去检查实例类D,无重载的(这个地方要注意了,虽然D里有实现Func(),但没有使用override关键字,所以不会被认为是重载) 4.转去检查类D的父类A,就为本身 5.执行父类A中的Func方法 5.输出结果 Func In A .
D d1 = new D();
d1.Func(); // 执行D类里的Func(),输出结果 Func In D
Console.ReadLine();
}
}
}

以上是我对virtual, override, new的整理。

C# virtual,override,new 整理的更多相关文章

  1. C# virtual override 和 new 的区别

    一直以来我都对 virtual  override 和 new 之间的区别感到疑惑不解. 特别笔试的时候特别容易考到,真的很容易弄错啊,畜生! 光看理论永远记不住,那不如写几行代码就懂了. 首先看看v ...

  2. C#关于private protected sealed Virtual/Override

    Public:公开权限 Private:修饰类时类为程序集或者包含此类的类内部权限:修饰变量时只能类内部使用: Protected:修饰变量,只能继承类可以使用,对外(包括继承类的实例)无权限: Ab ...

  3. knowing abstract,virtual,override,new

    If a class has at least one member which modified by "abstract",this class is an abstract ...

  4. Modifiers: virtual, override, new, abstract, sealed, internal

    internal 声明类.类成员.接口或接口成员具有内部可见性. internal 修饰符使类.接口或成员仅在当前包中可见. 当前包之外的代码不能访问 internal 成员.只有在同一程序集的文件中 ...

  5. C#中的virtual & override

    很奇怪的设计,需要靠着两个Keyword共同作用,才能完成多态——而不是类似Java那样的默认多态.所谓共同作用,即基类使用virtual 标示函数,子类使用override显示重写. 有点奇怪,MS ...

  6. C# abstract virtual override new finally java final finalize

    virtual:声明虚方法.可以被其派生类所重写的.重写方法需要使用override或者new关键字. override:覆盖原方法.可对重写virtual.override.abstract进行重写 ...

  7. c#中的 virtual override 和abstract 以及sealed

    1.如果父类方法没有加virtual关键字,即不是一个虚方法,则在子类中只能隐藏基类方法,而不能覆盖. 2.如果父类方法加了virtual关键字,即它是一个虚方法,在子类中一样可以隐藏. 3.如果子类 ...

  8. C# [method Modifiers] abstract virtual override new

    abstract :表示方法是抽象方法,在子类中必须重写.抽象方法所在的类必须是抽象类,即用abstract modifiers:virtual:表示此方法是virtual方法,除了在子类中可以重写外 ...

  9. abstract,virtual,override个人

    1.abstract 可以修饰类和方法,修饰方法时只声明不实现: 2.继承实现abstract类必须通过override实现abstract声明的方法,而virtual方法可选择override(重写 ...

随机推荐

  1. springMVC笔记:jsp页面获取后台数据记录列表

    1.读取数据库中的记录List<HashMap<String,String>> attributes; 2.Controller构造Model如下: @RequestMappi ...

  2. Big5

    在以下各表中定义了 Big5 语言环境的代码范围: 平面 代码范围 描述 1 A140H - A3E0H 符号和中文控制代码 1 A440H - C67EH 常用字符 2 C940H - F9D5H ...

  3. luogu 2509. 森林大礼包

    2509. 森林大礼包 ★   输入文件:three_squirrels.in   输出文件:three_squirrels.out   简单对比时间限制:1 s   内存限制:256 MB [题目描 ...

  4. Java Socket编程详细解说

    Java Socket编程 JavaSocketServerSocket乱码超时 Java Socket编程 对于Java Socket编程而言,有两个概念,一个是ServerSocket,一个是So ...

  5. "library not found for - "解决办法

    在我们编译的时候有时候会报这个错误 "library not found for - " 由于是我们在项目中使用了一些第三方的库,就比如我再使用百度的静态库文件的时候,报出的这个错 ...

  6. 分布式协调服务Zookeeper

    ZooKeeper是一个分布式的,开放源码的分布式应用程序协调服务,是Google的Chubby一个开源的实现,是Hadoop和Hbase的重要组件.它是一个为分布式应用提供一致性服务的软件,提供的功 ...

  7. Linux查看某个进程的磁盘IO读写情况

    说明: 1.Linux下没有原生的查看IO的软件,只能额外装. 2.如果使用vmstat或者cat /proc/$PID/io,这些看的都太复杂了. 下面是安装的比较直观的软件: 1.iostat 这 ...

  8. UBIFS - UBI File-System

    参考:http://www.linux-mtd.infradead.org/doc/ubifs.html#L_raw_vs_ftl UBIFS - UBI File-System Table of c ...

  9. Linux下安装Eclipse的PHP插件(PHPEclipse)

    下载: Eclipse: http://www.eclipse.org/downloads/       (本人用的Ubuntu,直接在SoftWare Center中下载的) (选择适合你系统的相应 ...

  10. Angular 学习笔记——自定义标签

    <!DOCTYPE HTML> <html ng-app="myApp"> <head> <meta http-equiv="C ...