C#类继承中构造函数的执行序列
不知道大家在使用继承的过程中有木有遇到过调用构造函数时没有按照我们预期的那样执行呢?一般情况下,出现这样的问题往往是因为类继承结构中的某个基类没有被正确实例化,或者没有正确给基类构造函数提供信息,如果理解在对象生命周期的这个阶段发生的事情,将更利于解决此类问题。
为了实例化派生的类,必须先实例化它的基类。而要实例化这个基类。又必须要实例化这个基类的基类,这样一直到实例化System.Object(所有类的跟)为止,结果无论使用什么构造函数实例化一个类,总是首先调用System.Object.Object().
下面一个示例演示执行顺序:
基类:
public class MyBaseClass
{
public MyBaseClass()
{
Console.WriteLine("I am MyBaseClass()");
}
public MyBaseClass(int i)
{
Console.WriteLine("I am MyBaseClass(int i)");
}
}
派生类:
public MyDerivedClass()
{
Console.WriteLine("I am MyDerivedCalss()");
}
public MyDerivedClass(int i)
{
Console.WriteLine("I am MyDerivedClass(int i)");
}
public MyDerivedClass(int i,int j)
{
Console.WriteLine("I am MyDerivedClass(int i,int j)");
}
接下来我们在Main函数中以不带参数的构造函数实例化MyDerivedClass:
MyDerivedClass myObj = new MyDerivedClass();
运行程序,控制台输出如下:

从结果可以看出,执行顺序先是基类构造的函数,接下来才是派生类的构造函数,即
1.执行System.Object.Object()构造函数(Object比较特殊,所有类的基类,一般可以不考虑,但是得知道它也是被执行了的)
2.执行MyBaseClass.MyBaseClass()构造函数
3.执行MyDerivedClass.MyDerivedClass()构造函数
如果我们以带一个参数的构造函数实例化MyDerivedClass:
MyDerivedClass myObj = new MyDerivedClass();
运行程序,控制台输出如下:

可以看出执行顺序如下:
1.执行System.Object.Object()构造函数
2.执行MyBaseClass.MyBaseClass()构造函数
3.执行MyDerivedClass.MyDerivedClass(int i)构造函数
同理如果我们以带两个参数的构造函数实例化MyDerivedClass
MyDerivedClass myObj = new MyDerivedClass(,);
运行程序,控制台输出如下:

可以看出执行顺序如下:
1.执行System.Object.Object()构造函数
2.执行MyBaseClass.MyBaseClass()构造函数
3.执行MyDerivedClass.MyDerivedClass(int i,int j)构造函数
大多数情况下这个都能正常工作,但是有时我们需要对发生的事件进行更多的控制。比如我们想得到如下所示的执行顺序:
1.执行System.Object.Object()构造函数
2.执行MyBaseClass.MyBaseClass(int i)构造函数
3.执行MyDerivedClass.MyDerivedClass(int i,int j)构造函数
使用这个顺序,可以把使用int i参数的代码放到MyBaseClass(int i)中,MyDerivedClass(int i,int j)只需要处理int j(假设int i参数在MyBaseClass和 MyDerivedClass里含义是一样的)
为此,只需要使用构造函数初始化器,把代码放到方法定义的冒号后面,如在派生类的构造函数中指定所使用的基类的构造函数,如下所示:
public MyDerivedClass(int i,int j) : base(i)
{
Console.WriteLine("I am MyDerivedClass(int i,int j)");
}
其中,base关键字指定在实例化过程中使用具有指定参数的构造函数。这里使用了int参数,其值通过i传递给MyDerivedClass构造函数,所以将使用MyBaseClass(int i),这样就不会调用MyBaseClass()了,我们重新执行下前面两个参数的实例化代码,就可以看出执行结果确实如此:

除了base关键字,还可以使用this关键字用作构造函数初始化器,这个关键字指定在调用指定的构造函数前,实例化过程对当前类使用非默认的构造函数。例如:
public MyDerivedClass():this(,)
{
Console.WriteLine("I am MyDerivedCalss()");
}
使用MyDerivedCalss()构造函数实例化,执行顺序是:

1.执行System.Object.Object()构造函数
2.执行MyBaseClass.MyBaseClass(int i)构造函数
3.执行MyDerivedClass.MyDerivedClass(int i,int j)构造函数
4.执行MyDerivedClass.MyDerivedClass()构造函数
总之呢,无论派生类上使用什么样的构造函数(默认的or不是默认的),除非明确指定(如使用base关键字),否则就先调用用基类的默认构造函数。
C#类继承中构造函数的执行序列的更多相关文章
- C++类继承中的构造函数和析构函数 调用顺序
思想: 在C++的类继承中,构造函数不能被继承(C11中可以被继承,但仅仅是写起来方便,不是真正的继承) 建立对象时,首先调用基类的构造函数,然后在调用下一个派生类的构造函数,依次类推: 析构对象时, ...
- (C++)C++类继承中的构造函数和析构函数
思想: 在C++的类继承中, 建立对象时,首先调用基类的构造函数,然后在调用下一个派生类的构造函数,依次类推: 析构对象时,其顺序正好与构造相反: 例子: #include <iostream& ...
- C# 类继承中的私有字段都去了哪里?
最近在看 C++ 类继承中的字段内存布局,我就很好奇 C# 中的继承链那些 private 字段都哪里去了? 在内存中是如何布局的,毕竟在子类中是无法访问的. 一:举例说明 为了方便讲述,先上一个例子 ...
- C++ 类的继承五(类继承中的static关键字)
//类继承中的static关键字 #include<iostream> using namespace std; /* 派生类中的静态成员 基类定义的静态成员,将被所有派生类共享 根据静态 ...
- C++ 类的继承四(类继承中的重名成员)
//类继承中的重名成员 #include<iostream> using namespace std; /* 自己猜想: 对于子类中的与父类重名的成员,c++编译器会单独为子类的这个成员变 ...
- C++类的继承中构造函数和析构函数调用顺序例子
/*当建立一个对象时,首先调用基类的构造函数,然后调用下一个派生类的构造函数,依次类推,直至到达派生类次数最多的派生次数最多的类的构造函数为止.简而言之,对象是由“底层向上”开始构造的.因为,构造函数 ...
- C++类继承中,基类/当前对象属性/当前对象的构造顺序
[1]中提到,规范的派生类构造函数三个要点: 首先创建基类对象 应通过成员初始化列表,创建基类对象 应该初始化本派生类新增的成员变量 那在构造派生类实例的过程中,其基类(以及多继承的时候多个基类)/当 ...
- C# 类型运算符重载在类继承中的调用测试
这是一篇晦涩难懂的片面的研究 一,简单的继承层次 class CA { } class CB : CA{ } class CC : CB{ } } void Test(CA oa){//CATest ...
- C++基础——类继承中方法重载
一.前言 在上一篇C++基础博文中讨论了C++最基本的代码重用特性——类继承,派生类可以在继承基类元素的同时,添加新的成员和方法.但是没有考虑一种情况:派生类继承下来的方法的实现细节并不一定适合派生类 ...
随机推荐
- 吴恩达机器学习笔记58-协同过滤算法(Collaborative Filtering Algorithm)
在之前的基于内容的推荐系统中,对于每一部电影,我们都掌握了可用的特征,使用这些特征训练出了每一个用户的参数.相反地,如果我们拥有用户的参数,我们可以学习得出电影的特征. 但是如果我们既没有用户的参数, ...
- Struts第一个案例搭建
1.引入依赖 <dependency> <groupId>javaee</groupId> <artifactId>javaee-api</art ...
- 【Linux篇】--sed的用法
一.前述 Sed是一种流编辑器,它是文本处理中非常中的工具,能够完美的配合正则表达式使用,功能不同凡响.处理时,把当前处理的行存储在临时缓冲区中,称为“模式空间”(pattern space),接着用 ...
- Python爬虫入门教程 45-100 Charles抓取兔儿故事-下载小猪佩奇故事-手机APP爬虫部分
1. Charles抓取兔儿故事背景介绍 之前已经安装了Charles,接下来我将用两篇博客简单写一下关于Charles的使用,今天抓取一下兔儿故事里面关于小猪佩奇的故事. 爬虫编写起来核心的重点是分 ...
- 『集群』003 Slithice 最简分布式(多个客户端,一个独立服务端)
Slithice 最简分布式(多个客户端,一个独立服务端) 案例Demo 展示: 我们搭建一个 可以 独立运行 的 服务端:然后 多个客户端 并发链接 这个 服务端 完成 分布式逻辑: 服务器 独立运 ...
- vue项目首屏加载优化实战
问题 单页面应用的一个问题就是首页加载东西过多,加载时间过长.特别在移动端,单页面应用的首屏加载优化更是绕不开的话题.下面我会写出我在项目中做的一些优化,希望大家能够相互讨论,共同进步. 我的项目vu ...
- Windows Server 2012 R2安装SqlServer 2016
1.系统安装 微软操作系统 Windows Server 2012 R2 官方原版镜像 Windows Server 2012 R2 是由微软公司(Microsoft)设计开发的新一代的服务器专属操作 ...
- Python使用Ctypes与C/C++ DLL文件通信过程介绍及实例分析
项目中可能会经常用到第三方库,主要是出于程序效率考虑和节约开发时间避免重复造轮子.无论第三方库开源与否,编程语言是否与当前项目一致,我们最终的目的是在当前编程环境中调用库中的方法并得到结果或者借助库中 ...
- H5 可堆叠的圆环进度条,支持任意数量子进度条
by Conmajia SN: S22-W1M 由来 看到一篇帖子<vue实用组件--圆环百分比进度条>,让我想起了很多年前我在WinForm下仿制过的Chrome进度条. ▲ 原版进度条 ...
- 【转载】SQL语句中Union和Union All的区别
在使用到SQL语句进行数据库查询的过程中,如果需要求两个数据集合的并集,一般会使用到联合查询关键字Union或者Union All,其实Union和Union All两者的使用有一定差别,查出来的数据 ...