C#虚方法
若一个实例方法声明前带有virtual关键字,那么这个方法就是虚方法。
虚方法与非虚方法的最大不同是,虚方法的实现可以由派生类所取代,这种取代是通过方法的重写实现的(以后再讲)
虚方法的特点:
虚方法前不允许有static,abstract,或override修饰符
虚方法不能是私有的,因此不能使用private修饰符
虚方法的执行:
我们知道一般函数在编译时就静态地编译到了执行文件中,其相对地址在程序运行期间是不发生变化的,
而虚函数在编译期间是不被静态编译的,它的相对地址是不确定的,它会根据运行时期对象实例来动态判断要调用的函数,
其中那个申明时定义的类叫申明类,那个执行时实例化的类叫实例类。
如:A a =new B(); 其中A是申明类,B是实例类。
1.当调用一个对象的函数时,系统会直接去检查这个对象申明定义的类,即申明类,看所调用的函数是否为虚函数;
2.如果不是虚函数,那么它就直接执行该函数。而如果是一个虚函数,那么这个时候它就不会立刻执行该函数了,而是开始检查对象的实例类。
3.在这个实例类里,他会检查这个实例类的定义中是否有实现该虚函数或者重新实现该虚函数(通过override关键字)的方法,
如果有,它就不会再找了,而是马上执行该实例类中实现的虚函数的方法。而如果没有的话,系统就会不停地往上找实例类的父类,
并对父类重复刚才在实例类里的检查,直到找到第一个重载了该虚函数的父类为止,然后执行该父类里重载后的函数。
例1:
class A
{
public virtual void Sum()
{
Console.WriteLine("I am A Class,I am virtual sum().");
}
}
class Program
{
static void Main(string[] args)
{
A a=new A(); // 定义一个a这个A类的对象.这个A就是a的申明类,实例化a对象,A是a的实例类
a.Sum();
Console.Read();
}
}
执行a.Sum:
1.先检查申明类A 2.检查到是sum是虚拟方法 3.转去检查实例类A,结果是题本身
4.执行实例类A中实现Sum的方法 5.输出结果 I am A Class,I am virtual sum().
例2:
class A
{
public virtual void Sum()
{
Console.WriteLine("I am A Class,I am virtual sum().");
}
}
class B : A
{
public override void Sum() // 重新实现了虚函数
{
Console.WriteLine("I am B Class,I am override sum().");
} }
class Program
{
static void Main(string[] args)
{
A a=new B(); // 定义一个a这个A类的对象.这个A就是a的申明类,实例化a对象,B是a的实例类
a.Sum();
Console.Read();
}
}
执行a.Sum:
1.先检查申明类A 2.检查到是虚拟方法 3.转去检查实例类B,有重写的方法 4.执行实例类B中的方法 5.输出结果 I am B Class,I am override sum().
例3:
class A
{
public virtual void Sum()
{
Console.WriteLine("I am A Class,I am virtual sum().");
}
}
class B : A
{
public override void Sum() // 重新实现了虚函数
{
Console.WriteLine("I am B Class,I am override sum().");
} }
class C : B
{ }
class Program
{
static void Main(string[] args)
{
A a=new C();// 定义一个a这个A类的对象.这个A就是a的申明类,实例化a对象,C是a的实例类
a.Sum();
Console.Read();
}
}
执行a.Sum:
1.先检查申明类A 2.检查到是虚拟方法 3.转去检查实例类C,无重写的方法 4.转去检查类C的父类B,有重写的方法
5.执行父类B中的Sum方法 6.输出结果 I am B Class,I am override sum().
例4:
class A
{
public virtual void Sum()
{
Console.WriteLine("I am A Class,I am virtual sum().");
}
}
class B : A
{
public new void Sum() //覆盖父类里的同名函数,而不是重新实现
{
Console.WriteLine("I am B Class,I am new sum().");
} }
class Program
{
static void Main(string[] args)
{
A a=new B();
a.Sum();
Console.Read();
}
}
执行a.Sum:
1.先检查申明类A 2.检查到是虚拟方法 3.转去检查实例类B,无重写的(这个地方要注意了,虽然B里有实现Sum(),但没有使用override关键字,所以不会被认为是重写) 4.转去检查类B的父类A,就为本身 5.执行父类A中的Sum方法 6.输出结果 I am A Class,I am virtual sum().
那么如果在例4里,申明的是类B呢?
class A
{
public virtual void Sum()
{
Console.WriteLine("I am A Class,I am virtual sum().");
}
}
class B : A
{
public new void Sum() //覆盖父类里的同名函数,而不是重新实现
{
Console.WriteLine("I am B Class,I am new sum().");
} }
class Program
{
static void Main(string[] args)
{
B b=new B();
b.Sum();
Console.Read();
}
}
执行B类里的Sum(),输出结果I am B Class,I am new sum().
可以使用抽象函数重写基类中的虚函数吗?
答案是可以的。
class A
{
public virtual void PrintFriends()
{
Console.WriteLine("A.PrintFriends()");
}
}
abstract class B : A
{
public abstract override void PrintFriends(); //使用override 修饰符,表示抽象重写了基类中该函数的实现
}
abstract class C : A
{
public abstract new void PrintFriends(); //使用 new 修饰符显式声明,表示隐藏了基类中该函数的实现
}
密封类可以有虚函数吗?
可以,基类中的虚函数将隐式的转化为非虚函数,但密封类本身不能再增加新的虚函数
class A
{
public virtual void Fun()
{
Console.WriteLine("I am A.");
}
}
sealed class Program:A
{
public override void Fun()
{
Console.WriteLine("I am B.");
}
static void Main(string[] args)
{
Program p = new Program();
p.Fun();
Console.Read();
}
}
C#虚方法的更多相关文章
- C# 工厂模式+虚方法(接口、抽象方法)实现多态
面向对象语言的三大特征之一就是多态,听起来多态比较抽象,简而言之就是同一行为针对不同对象得到不同的结果,同一对象,在不同的环境下得到不同的状态. 实例说明: 业务需求:实现一个打开文件的控制台程序的d ...
- 重写ValidateEntity虚方法实现可控的上下文验证和自定义验证
上篇文章介绍了ValidationAttribute和IValidatableObject.Validate验证,但是这种验证还是稍微简单了,对于复杂的实体,例如:继承过来的实体.实现某接口的实体等等 ...
- Delphi之静态方法,虚方法virtual,动态dynamic,抽象abstract,消息
Delphi之静态方法,虚方法virtual,动态dynamic,抽象abstract,消息 http://www.cnblogs.com/zhwx/archive/2012/08/28/266055 ...
- 《转》 浅谈C# 多态的魅力(虚方法,抽象,接口实现)
前言:我们都知道面向对象的三大特性:封装,继承,多态.封装和继承对于初学者而言比较好理解,但要理解多态,尤其是深入理解,初学者往往存在有很多困惑,为什么这样就可以?有时候感觉很不可思议,由此,面向对象 ...
- C#属性-索引器-里氏替换-多态-虚方法-抽象-接口-泛型-
1.属性 //属性的2种写法 public class person { private string _name; public string Name { get { return _name; ...
- 为何JAVA虚函数(虚方法)会造成父类可以"访问"子类的假象?
首先,来看一个简单的JAVA类,Base. 1 public class Base { 2 String str = "Base string"; 3 protected vo ...
- C++虚方法(虚函数)随笔
本文不讨论虚函数的原理,只简单总结下虚函数的常用事项. 虚函数(虚方法)是C++动态联编 实现多态的重要手段,在函数声明时使用关键字virtual即可,如: virtual void func(voi ...
- 【jq】c#零基础学习之路(3)继承和虚方法
c#只能继承一个基类和多个接口(0+) 父类:Human: class Human { public virtual Move() { Console.WriteLine("Human的虚方 ...
- C#类和接口、虚方法和抽象方法及值类型和引用类型的区别
1.C#类和接口的区别接口是负责功能的定义,项目中通过接口来规范类,操作类以及抽象类的概念!而类是负责功能的具体实现!在类中也有抽象类的定义,抽象类与接口的区别在于:抽象类是一个不完全的类,类里面有抽 ...
- [C#解惑] #1 在构造函数内调用虚方法
谜题 在C#中,用virtual关键字修饰的方法(属性.事件)称为虚方法(属性.事件),表示该方法可以由派生类重写(override).虚方法是.NET中的重要概念,可以说在某种程度上,虚方法使得多态 ...
随机推荐
- PHP输出当前进程所有变量 / 常量 / 模块 / 函数 / 类
<?php /* 不知道怎么打印某个函数的参数和相关分类类型的所有函数 以下函数如果没有参数,返回的都是一个数组get_defined_functions() 获取所有已经定义的函数get_de ...
- jQuery源代码阅读之二——jQuery静态属性和方法
一.jQuery.extend/jQuery.fn.extend //可接受的参数类型如下:jQuery.extend([deep],target,object1,[objectN]) jQuery. ...
- oracle生成主键
SELECT 'ZTO'||TO_CHAR(SYSDATE,'yymmdd')||TO_CHAR(SEQ_COMMON_ORDER.NEXTVAL,'FM00000000') AS orderCode ...
- 献给初学者:谈谈如何学习Linux操作系统
本文出自 “技术成就梦想” 博客,请务必保留此出处http://ixdba.blog.51cto.com/2895551/569329. 为了能把这篇不错的文章分享给大家.所以请允许我暂时用原创的形式 ...
- 旋转toast 自定义toast方向,支持多个方向的显示,自定义View
package com.example.canvasdemo; import java.security.InvalidAlgorithmParameterException; import andr ...
- jQuery全选/反选checkbox
<!doctype html> <html lang="en"> <head> <meta charset="UTF-8&quo ...
- HTML5 属性 认知
HTML5中 不支持 Html4.01的属性: <acronym> <applet> <basefont> <big> <center> ...
- 初试“七牛云”--零基础运用七牛云配合UEditor实现图片的上传和浏览(.NET篇)
(注册和建立存储空间就不介绍了,网上一把一把的资料,自己试着点点也能明白) 作为一个成熟的菜鸟,如果遇到一个新问题,第一步当然是先百度一下... 看了N个关于七牛云的使用的帖子,表示还是蒙圈的,看懂了 ...
- JuQueen(线段树 lazy)
JuQueen Time Limit: 5 Sec Memory Limit: 512 MB Description Input Output Sample Input 10 10 5 state ...
- 学DIV+CSS技术,如何入门?(2)
http://www.zhangbin.in/a/jishuziliao/CSSjishu/2014/0730/13267_2.html