避免在构造函数中调用虚方法(Do not call overridable methods in constructors)
CLR中说道,不要在构造函数中调用虚方法,原因是假如被实例化的类型重写了虚方法,就会执行派生类型对虚方法的实现。但在这个时候,尚未完成对继承层次结构中所有字段的初始化。所以,调用虚方法会导致不可预测的行为。归根结底,这是由于调虚方法时,直到运行时之前,都不会选择执行该方法的实际类型。
在MSDN中,也给我我们详细的提示和范例。
https://msdn.microsoft.com/en-us/library/ms182331.aspx
那我们就亲手来测试一下,新建两个类,Perople类,Chinese类,先不要看结果,看到下面这两个类,想想在实例化Chinese的时候,会是什么输出结果呢?
public class People
{
public People()
{
PeopleSayHello();
} public virtual void PeopleSayHello()
{
Console.WriteLine("hello");
}
}
public class Chinese : People
{
private bool HaveAbility { get; set; } public Chinese()
{
HaveAbility = true;
} public override void PeopleSayHello()
{ Console.WriteLine((HaveAbility?"有":"没有")+"能力说你好");
}
}
接下来来看调用和输出结果吧:
是不是和你在脑海里运行的结果相同?
其实原因在第一句话中已经说的比较清晰了,更通俗的说就是在派生类实例化的时候,如果没有显式调用基的任意一个构造函数,那么默认选择基类的无参构造。所以在本例中,实例化Chinese的时候,首先执行了基类的无参构造。
和实例构造器初始化的顺序也相关,在创建实例的时候,首先为数据字段分配内存,然后初始化对象附加字段,包括类型对象的指针引用,最后才调用类型的构造函数设置对象的初始状态。
避免在构造函数中调用虚方法(Do not call overridable methods in constructors)的更多相关文章
- C# 构造函数中调用虚方法的问题
请看下面代码: using System; public class A{ public A(){ M1(); } public virtual void M1(){} } public class ...
- [C#解惑] #1 在构造函数内调用虚方法
谜题 在C#中,用virtual关键字修饰的方法(属性.事件)称为虚方法(属性.事件),表示该方法可以由派生类重写(override).虚方法是.NET中的重要概念,可以说在某种程度上,虚方法使得多态 ...
- 关于在C#中构造函数中调用虚函数的问题
在C#中如果存在类的继承关系,应避免在构造函数中调用虚函数.这是由于C#的运行机制造成的,原因如下: 新建一个类实例时,C#会先初始化该类(对类变量赋值,并将函数记在函数表中),然后再初始化父类.构造 ...
- C++ 构造函数中调用虚函数
我们知道:C++中的多态使得可以根据对象的真实类型(动态类型)调用不同的虚函数.这种调用都是对象已经构建完成的情况.那如果在构造函数中调用虚函数,会怎么样呢? 有这么一段代码: class A { p ...
- 【校招面试 之 C/C++】第10题 C++不在构造函数和析构函数中调用虚函数
1.不要在构造函数中调用虚函数的原因 在概念上,构造函数的工作是为对象进行初始化.在构造函数完成之前,被构造的对象被认为“未完全生成”.当创建某个派生类的对象时,如果在它的基类的构造函数中调用虚函数, ...
- C++中构造函数能调用虚函数吗?(答案是语法可以,输出错误),但Java里居然可以
环境:XPSP3 VS2005 今天黑总给应聘者出了一个在C++的构造函数中调用虚函数的问题,具体的题目要比标题复杂,大体情况可以看如下的代码: class Base { public: Base() ...
- EC笔记,第二部分:9.不在构造、析构函数中调用虚函数
9.不在构造.析构函数中调用虚函数 1.在构造函数和析构函数中调用虚函数会产生什么结果呢? #; } 上述程序会产生什么样的输出呢? 你一定会以为会输出: cls2 make cls2 delete ...
- 编写高质量代码改善C#程序的157个建议——建议95:避免在构造方法中调用虚成员
建议95:避免在构造方法中调用虚成员 在构造方法中调用虚方法会带来一些意想不到的错误,虽然这种方法不常见,但还是需要注意这类陷阱. static void Main() { American amer ...
- 读书笔记 effective c++ Item 9 绝不要在构造函数或者析构函数中调用虚函数
关于构造函数的一个违反直觉的行为 我会以重复标题开始:你不应该在构造或者析构的过程中调用虚函数,因为这些调用的结果会和你想的不一样.如果你同时是一个java或者c#程序员,那么请着重注意这个条款,因为 ...
随机推荐
- String、StringBuffer、StringBulider
三者都实现了CharSequence接口,因此CharSequence可认为是一个字符串的协议接口 1.String类是不可变类,即一旦一个String对象被创建后,包含在这个对象中的字符序列是不可改 ...
- [转]delphi 有授权许可的字符串拷贝函数源码
一段看上去“貌不惊人”的Delphi插入汇编代码,却需要授权许可,但是与经典的同类型函数比较,确实“身手不凡”. 研究代码的目的在于借鉴,本文通过分析,并用C++重写代码进行比较,再次证明这段代码效率 ...
- 学习shader之前必须知道的东西之计算机图形学-渲染管线
引言 shader到底是干什么用的?shader的工作原理是什么? 其实当我们对这个问题还很懵懂的时候,就已经开始急不可耐的要四处搜寻有关shader的资料,恨不得立刻上手写一个出来.但看了一些资料甚 ...
- Miscellaneos:ISV
ylbtech-Miscellaneos:ISV ISV英文全称是Independent Software Vendors ,意为“独立软件开发商”,特指专门从事软件的开发.生产.销售和服务的企业,如 ...
- Fibratus:一款功能强大的Windows内核漏洞利用和跟踪工具
今天给大家介绍的是一款名叫Fibratus的开源工具,广大研究人员可以使用这款功能强大的工具来进行Windows内核漏洞利用.挖掘与跟踪. Fibratus这款工具能够捕捉到绝大多数的Windows内 ...
- 使用nvm进行node多版本管理
nvm与Python的virtualenv和Ruby的rvm类似.NVM (Node Version Manager,Node多版本管理器)是一个通用的叫法,它目前有许多不同的实现.通常我们说的 nv ...
- Springboot打包支持第三方jar
有时候我们需要的jar在maven里不存在,需要手动引入.比如,钉钉sdk <dependency> <groupId>com.aliyun</groupId> & ...
- (转)Render Path
Render Path定义Render Path,就是采取的光照流程. Render Path设置可以在Edit-> Project Settings->Player 里设定,见下图.也可 ...
- ionic build - 修改gradle路径提升速度和成功率
ionic build 不成功很多时候是因为下载gradle太慢, 我们可以下载好gradle然后修改配置文件, 从而省去这个烦人的下载过程 1. 下载报错时的gradle zip文件, 或者直接查看 ...
- [BetterExplained]为什么你应该(从现在开始就)写博客
(一)为什么你应该(从现在开始就)写博客 用一句话来说就是,写一个博客有很多好处,却没有任何明显的坏处.(阿灵顿的情况属于例外,而非常态,就像不能拿抽烟活到一百岁的英国老太太的个例来反驳抽烟对健康的极 ...