C# 方法 虚方法的调用浅谈 引用kdalan的博文
我们在面试中经常碰到有关多态的问题,之前我也一直被此类问题所困扰,闹不清到底执行哪个方法。
先给出一道简单的面试题,大家猜猜看,输出是?

{
public void MethodF()
{
Console.WriteLine("A.F");
}
public virtual void MethodG()
{
Console.WriteLine("A.G");
}
}
public class B : A
{
new public void MethodF()
{
Console.WriteLine("B.F");
}
public override void MethodG()
{
Console.WriteLine("B.G");
}
}
class Test
{
static void Main()
{
B b;
b = new B();
A a = b;
a.MethodF();
b.MethodF();
a.MethodG();
b.MethodG();
}

首先看一下虚方法的定义(MSDN):
若一个实例方法的声明中含有 virtual 修饰符,则称该方法为虚拟方法。若其中没有 virtual 修饰符,则称该方法为非虚拟方法。
以上面题目Test类Main中代码为例,简单说一下CLR创建对象的过程都做了什么事情
1) 首先,声明一个引用类型变量 b,它仅是一个引用,保存在线程的栈上,用于将来存放B对象的有效地址。此时 b 未指向任何有效的实例,值为null,相关代码为:
B b;
2) 接下来,通过new执行对象的创建,即:
b = new B();
对象的实例保存在托管堆上,CLR在创建一个新对象的同时,还会创建它的类型对象(如果类型对象不存在)。
对象实例在堆中的内存包括实例字段、类型对象指针、同步索引块,类型对象指针指向类型对象。
类型对象在堆中分配的内存包括类型对象指针、同步索引块、静态字段、方法表。
3) A a = b; 这行代码首先声明一个类型为A的引用类型变量a,并将其实际地址指向b所指向的对象实例。
4) 之后就是方法的调用,下面详细说一下C#中方法的调用:
a.MethodF();
当调用一个对象的方法时,会直接检查这个对象变量(a)的类型 ,找到堆中的类型对象,查看是否有该方法,没有则通过类型对象的类型对象指针向上回溯查找,直至找到,然后检查该方法是否为虚方法,如果非虚,直接调用,由于MethodF 方法是非虚的,因此直接调用输出A.F。
a.MethodG();
如果该方法为虚方法,即有virtual 关键字,则根据对象变量(a),去找到对象的实例类B,查找该类型对象中是否重新实现过该虚方法(override 关键字),如果有,OK执行,如果没有,向上检查其父类,直至找到然后执行,MethodG为虚方法,则会查找实例B,由于B中重写了MethodG,因此此处输出B.G。
通过上面的描述,开始的那道面试题,我们应该轻松可以得出输出,此处就不啰嗦了。
一般考多态的面试题中 virtual new override 几个关键字经常出现,new 关键字实现一个新的方法,同时隐藏基类的同名方法。
C# 方法 虚方法的调用浅谈 引用kdalan的博文的更多相关文章
- 【Java-Method】读《重构》有感_Java方法到底是传值调用还是传引用调用(传钥匙调用)
今天读<重构>P279, Separate Query from Modifier,将查询函数和修改函数分离. 问题的产生 突然想到 Java 的传对象作为参数的方法到底是 传引用调用,还 ...
- C#类和接口、虚方法和抽象方法及值类型和引用类型的区别
1.C#类和接口的区别接口是负责功能的定义,项目中通过接口来规范类,操作类以及抽象类的概念!而类是负责功能的具体实现!在类中也有抽象类的定义,抽象类与接口的区别在于:抽象类是一个不完全的类,类里面有抽 ...
- 转载总结 C# 多态(虚方法,抽象,接口实现)
前言:我们都知道面向对象的三大特性:封装,继承,多态.封装和继承对于初学者而言比较好理解,但要理解多态,尤其是深入理解,初学者往往存在有很多困惑,为什么这样就可以?有时候感觉很不可思议,由此,面向对象 ...
- 关于C#中的抽象类、抽象方法和虚方法的探究
2016年的第一篇文章,容我先喷喷新年的情怀,..........,好了,喷的差不多了. 在面向对象中,我们需要对类进行横向和纵向的认识,不同的类有不同特色的成员,同时在不同类的继承中,子类获得父类的 ...
- C#中的虚方法和抽象方法(Thirteenth Day)
今天在云和学院学了很多,我这次只能先总结一下C#中的虚方法和抽象的运用. 理论: 虚方法: •用virtual修饰的方法叫做虚方法 •虚方法可以在子类中通过override关键字来重写 •常见的虚方法 ...
- C#中的抽象方法,虚方法,接口之间的对比
1.首先来看一看抽象类 抽象类是特殊的类,不能够被实例化:具有类的其他特性:抽象方法只能声明于抽象类中,且不包含任何实现 (就是不能有方法体),派生类也就是子类必须对其进行重写.另外,抽象类可以派生自 ...
- 抽象类和虚方法、base关键字
微软官方文档:https://docs.microsoft.com/zh-cn/dotnet/csharp/programming-guide/classes-and-structs/abstract ...
- c# 多态实现_虚方法
实现方法: 虚方法, 抽象类, 接口 1.虚方法 将父类的方法标记为虚方法,使用关键字virtual,这个方法可以被子类重新写一遍. 在父类的方法前面加上一个virtual,在子类的方法前面加上一个o ...
- 浅谈线程池(中):独立线程池的作用及IO线程池
原文地址:http://blog.zhaojie.me/2009/07/thread-pool-2-dedicate-pool-and-io-pool.html 在上一篇文章中,我们简单讨论了线程池的 ...
随机推荐
- NYOJ110 剑客决斗
剑客决斗 来源:Polish Olympiad in Informatics(波兰信息学奥林匹克竞赛) 时间限制:5000 ms | 内存限制:65535 KB 难度:5 描述 在路易十三和红 ...
- 剑指Offer面试题11(Java版):数值的整数次方
题目:实现函数double Power(double base,int exponent),求base的exponent次方.不得使用库函数,同一时候不须要考虑大数问题 1.自以为非常easy的解法: ...
- mac下Android Studio干净卸载
1.卸载Android Studio,在终端(terminal)执行以下命令: rm -Rf /Applications/Android\ Studio.app rm -Rf ~/Library/Pr ...
- 并不对劲的bzoj1853:[SCOI2010]幸运数字
传送门-> 据说本题的正确读法是[shìng运数字]. 听上去本题很适合暴力,于是并不对劲的人就去写了.其实这题就是一个很普(有)通(趣)暴力+神奇的优化. 首先,会发现幸运数字很少,那么就先搜 ...
- KMP算法在字符串中的应用
KMP算法是处理字符串匹配的一种高效算法 它首先用O(m)的时间对模板进行预处理,然后用O(n)的时间完成匹配.从渐进的意义上说,这样时间复杂度已经是最好的了,需要O(m+n)时间.对KMP的学习可以 ...
- [Usaco2017 Feb]Why Did the Cow Cross the RoadII
[题目链接] https://www.lydsy.com/JudgeOnline/problem.php?id=4993 [算法] 动态规划 转移类似于求LCS [代码] #include<bi ...
- hdu3092
题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=3092 题目描述:将一个数拆分成几个数之和,问这几个数能得到的最大的最小公倍数模上给定的一个数是多少? ...
- Jquery 之deferred
一.概述 在jquery中有种对象称之为延时对象,可以由 http请求方法$.get(), $.ajax(), $.post() 产生, 内置方法如下 也可以有jquery的延时方法 $.when( ...
- python 闭包 Closure 函数作为返回值
一.函数作为返回值 高阶函数除了可以接受函数作为参数外,还可以把函数作为结果值返回. >>> def lazy_sum(*args): ... def sum(): ... ax = ...
- [App Store Connect帮助]八、维护您的 App(2)将 App 从 App Store 中移除
如果您不想继续向顾客提供您的 App,您可以将其从 App Store 中移除,这样会移除该 App 的所有版本.拥有该 App 先前版本的用户将无法更新 App,但只要您的合约有效,用户便仍可下载最 ...