C#中的虚函数及继承关系
转载:http://blog.csdn.net/suncherrydream/article/details/8423991
若一个实例方法声明前带有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++中继承中的虚函数
c++继承中的虚函数 c++是一种面向对象的编程语言的一个很明显的体现就是对继承机制的支持,c++中继承分很多种,按不同的分类有不同分类方法,比如可以按照基类的个数分为多继承和单继承,可以按照访问 ...
- C++中的虚函数(表)实现机制以及用C语言对其进行的模拟实现
tfref 前言 C++对象的内存布局 只有数据成员的对象 没有虚函数的对象 拥有仅一个虚函数的对象 拥有多个虚函数的对象 单继承且本身不存在虚函数的继承类的内存布局 本身不存在虚函数(不严谨)但存在 ...
- 关于在C#中构造函数中调用虚函数的问题
在C#中如果存在类的继承关系,应避免在构造函数中调用虚函数.这是由于C#的运行机制造成的,原因如下: 新建一个类实例时,C#会先初始化该类(对类变量赋值,并将函数记在函数表中),然后再初始化父类.构造 ...
- 【整理】C++虚函数及其继承、虚继承类大小
参考文章: http://blog.chinaunix.net/uid-25132162-id-1564955.html http://blog.csdn.net/haoel/article/deta ...
- C++中的虚函数解析[The explanation for virtual function of CPlusPlus]
1.什么是虚函数? ...
- 【C++】C++中的虚函数与纯虚函数
C++中的虚函数 先来看一下实际的场景,就很容易明白为什么要引入虚函数的概念.假设我们有一个基类Base,Base中有一个方法eat:有一个派生类Derived从基类继承来,并且覆盖(Override ...
- cc38b_demo_C++_异常_(2)txwtech在异常中使用虚函数-多态
//cc38b_demo,21days_C++_异常_(2)txwtech20200121在异常中使用虚函数-多态 //--异常层次结构//*异常的类-创建自己的异常类//*异常派生-就是继承//*异 ...
- C++中的虚函数总结
一.什么是虚函数.纯虚函数.抽象基类 虚函数:在某基类中声明为 virtual 并在一个或多个派生类中被重新定 义的成员函数. 纯虚函数:是一种特殊的虚函数,使用virtual关键字,并且在其后面加上 ...
- C++箴言:避免构造或析构函数中调用虚函数
如果你已经从另外一种语言如C#或者Java转向了C++,你会觉得,避免在类的构造函数或者析构函数中调用虚函数这一原则有点违背直觉.但是在C++中,违反这个原则会给你带来难以预料的后果和无尽的烦恼. 正 ...
随机推荐
- JS_正则表达式_获取指定字符之后指定字符之前的字符串
一个常见的场景,获取:标签背景图片链接: 如字符串:var bgImg = "url(\"https://img30.360buyimg.com/sku/jfs/t26203/26 ...
- JSON字符串反序列化成对象_部分属性值反序列化失败
简介:本人在开发webapi接口时遇到了:一个复杂的Json字符串在反序列化为对象时报,无法发序列化其中的一个属性对象? 使用方法: InternalRecommendRequestFormModel ...
- 36.QT-解决无边框界面拖动卡屏问题(附带源码)
1.简介 看到很多才学QT的人都会问为啥无边框拖动为啥会花屏? 那是因为你每次拖动的过程中都一直在调用move()函数让QT重新绘制界面,如果资源过大,就会导致当前图形还未绘制完,便又重新改变坐标了, ...
- Java开发笔记(五十九)Java8之后的扩展接口
前面介绍了接口的基本用法,有心的朋友可能注意到这么一句话“在Java8以前,接口内部的所有方法都必须是抽象方法”,如此说来,在Java8之后,接口的内部方法也可能不是抽象方法了吗?之所以Java8对接 ...
- Java高阶语法---final
背景:听说final Java高阶语法是挺进BAT必经之路. final: final关键字顾名思义就是最终不可改变的. 1.含义:final可以声明成员变量.方法.类和本地变量:一旦将引用声明为fi ...
- C# 消息队列-MSMQ
MQ是一种消息中间件技术,所以它能够支持多种类型的语言开发,同时也是跨平台的通信机制,也就是说MQ支持将信息转化为XML或者JSon等类型的数据存储到消息队列中,然后可以使用不同的语言来处理消息队列中 ...
- Sublime 无法安装插件的解决办法
1,打开命令面板 Ctrl + Shift + P 输入:pi 回车 按回车后,出现异常如下图: 解决办法: 1,点击Preferences----Brows Packages ---会到安装目录 ...
- jsp内置对象的作用范围
内置对象的作用范围是指每个内置对象的某个实例在多长时间和多大的范围中有效,即在什么样的范围内可以有效地访问同一个对象实例. 在javax.servlet.jsp.PageContext的类中定义了4个 ...
- bootstrap思考一
bootstrap是一种热门的Web前端流行框架,如果要兼容PC端.手机端和响应式布局,那他一定是我的首选.bootstrap内容很多,功能强大,其中最好入门也是很重要的就是他的栅格系统.他有四个典型 ...
- Jquery 使用和Jquery选择器
jQuery中的顶级对象($) jQuery 中最常用的对象即 $ 对象,要想使用 jQuery 的方法必须通过 $ 对象.只有将普通的 Dom 对象封装成 jQuery 对象,然后才能调用 jQue ...