构造函数的调用顺序是先调用System.Object,再按照层次结构由上向下(基类=》派生类)进行,直到到达编译器要实例化的类为止。在此过程中,每个构造函数都初始化自己类中的字段。编译器先自下而上查找构造函数,然后再自上而下地执行。

以下通过示例说明派生类的构造函数是如何执行的。

1.基类和派生类都未显示定义构造函数

执行GenericCustomer customer = new Nevermore60Customer();语句时,编译器首先找到试图实例化的类的构造函数即Nevermore60Customer 类的默认构造函数,默认Nevermore60Customer 构造函数首先要做的是为其直接基类GenericCustomer运行默认构造函数,然后GenericCustomer构造函数为其直接基类System.Object运行默认构造函数。而System.Object没有任何基类,所以它的默认构造函数直接执行;接着执行GenericCustomer的默认构造函数,将name字段初始化为null;最后执行Nevermore60Customer的默认构造函数,将highCostMinutesUsed字段初始化未0,并退出。

    abstract class GenericCustomer
{
private string name;
} class Nevermore60Customer : GenericCustomer
{
private uint highCostMinutesUsed;
}

2.基类定义了一个无参构造函数

执行GenericCustomer customer = new Nevermore60Customer();语句,构造函数执行顺序:System.Object类的默认构造函数=》GenericCustomer类的显示无参构造函数(将name字段初始化为“<no name>”)=》Nevermore60Customer类的默认无参构造函数(将highCostMinutesUsed字段初始化为0)。

    abstract class GenericCustomer
{
private string name; public GenericCustomer()
:base() //base,调用基类的构造函数(本例中调用System.Object中的构造函数,与默认情况相同,可省略)
{
name = "<no name>";
}
} class Nevermore60Customer : GenericCustomer
{
private uint highCostMinutesUsed;
}

注意:若把GenericCustomer类中的构造函数声明为private,则类Nevermore60Customer会产生一个编译错误。因为编译器试图为Nevermore60Customer类生成默认构造函数时,需要调用类GenericCustomer的无参构造函数,但是这个函数是类GenericCustomer所私有的,其他类无法调用。

3.基类和派生类都定义了有参构造函数

执行GenericCustomer customer = new Nevermore60Customer("LiSi");语句时,构造函数执行顺序:System.Object类的默认构造函数=》GenericCustomer类的有参构造函数(将name字段初始化为“LiSi”)=》Nevermore60Customer类的有参构造函数(什么也不做)。

    abstract class GenericCustomer
{
private string name; public GenericCustomer(string name)
{
this.name = name;
}
} class Nevermore60Customer : GenericCustomer
{
private uint highCostMinutesUsed; public Nevermore60Customer(string name)
:base(name)
{ }
}

注意:若类Nevermore60Customer未定义上面的有参构造函数,则类Nevermore60Customer会产生一个编译错误。因为类Nevermore60Customer生成的默认构造函数会试图调用GenericCustomer类中的无参构造函数,但它并没有这样的函数。

4.派生类中有多个构造函数

执行GenericCustomer customer = new Nevermore60Customer("LiSi");语句时,构造函数执行顺序:System.Object类的默认构造函数=》GenericCustomer类的有参构造函数(将name字段初始化为“LiSi”)=》Nevermore60Customer类中有两个参数的构造函数(将referrerName字段初始化为“None”)=》Nevermore60Customer类中有一个参数的构造函数(什么也不做)

    abstract class GenericCustomer
{
private string name; public GenericCustomer(string name)
{
this.name = name;
}
} class Nevermore60Customer : GenericCustomer
{
private uint highCostMinutesUsed; private string referrerName; public Nevermore60Customer(string name, string referrerName)
: base(name)
{
this.referrerName = referrerName;
} public Nevermore60Customer(string name)
: this(name, "<None>")
{ }
}

参考来源:《C#高级编程(第9版)》

C#派生类的构造函数的更多相关文章

  1. 不可或缺 Windows Native (21) - C++: 继承, 组合, 派生类的构造函数和析构函数, 基类与派生类的转换, 子对象的实例化, 基类成员的隐藏(派生类成员覆盖基类成员)

    [源码下载] 不可或缺 Windows Native (21) - C++: 继承, 组合, 派生类的构造函数和析构函数, 基类与派生类的转换, 子对象的实例化, 基类成员的隐藏(派生类成员覆盖基类成 ...

  2. C++学习17派生类的构造函数

    基类的构造函数不能被继承,在声明派生类时,对继承过来的成员变量的初始化工作也要由派生类的构造函数来完成.所以在设计派生类的构造函数时,不仅要考虑派生类新增的成员变量,还要考虑基类的成员变量,要让它们都 ...

  3. C++:派生类的构造函数和析构函数

    4.2 派生类的构造函数和析构函数4.2.1 派生类构造函数和析构函数的执行顺序 通常情况下,当创建派生类对象时,首先执行基类的构造函数,随后再执行派生类的构造函数:当撤销派生类对象时,则先执行派生类 ...

  4. 【C++学习之路】派生类的构造函数(三)

    三.多层继承的派生类 1.多层继承的派生类只需在构造函数的初始化列表中写出直接基类的构造函数即可 class student { public: student(int n, string nam) ...

  5. 【C++学习之路】派生类的构造函数(一)

    一.简单派生类的构造函数 1.所谓简单派生类,就是指派生类中不包含基类的内嵌对象的派生类. 2.一般来说,这样的派生类的构造函数的形式是: student( int i, string nam, in ...

  6. 【C++继承与派生之二】有子对象的派生类的构造函数

    这是我今天看书刚刚看到的,觉着以前对这一块内容了解不多,所以整理一下分享给大家.首先要介绍一下子对象的概念.类的数据成员不仅可以是int.char这样的基本类型,也可以是类对象,如可以包含这样的数据成 ...

  7. c++, 派生类的构造函数和析构函数 , [ 以及operator=不能被继承 or Not的探讨]

    说明:文章中关于operator=实现的示例,从语法上是对的,但逻辑和习惯上都是错误的. 参见另一篇专门探究operator=的文章:<c++,operator=>http://www.c ...

  8. C++学习之路—继承与派生(二):派生类的构造函数与析构函数

    (根据<C++程序设计>(谭浩强)整理,整理者:华科小涛,@http://www.cnblogs.com/hust-ghtao转载请注明) 由于基类的构造函数和析构函数是不能被继承的,所以 ...

  9. 【C++ Primer 第15章】定义派生类拷贝构造函数、赋值运算符

    学习资料 • 派生类的赋值运算符/赋值构造函数也必须处理它的基类成员的赋值 • C++ 基类构造函数带参数的继承方式及派生类的初始化 定义拷贝构造函数 [注意]对派生类进行拷贝构造时,如果想让基类的成 ...

  10. C++:派生类的构造函数和析构函数的调用顺序

    一.派生类 在C++编程中,我们在编写一个基类的派生类时,大致可以分为四步: • 吸收基类的成员:不论是数据成员还是函数成员,派生类吸收除基类的构造函数和析构函数之外的全部成员. • 改造基类函数:在 ...

随机推荐

  1. C++入门经典-例8.5-多重继承

    1:C++允许子类从多个父类继承公有的和受保护的成员,这称为多重继承. 2:多重继承的定义.多重继承有多个基类名称标识符,其声明形式如下: class 派生类名标识符:[继承方式] 基类名标识符1,. ...

  2. IDEA2019 JFormDesigner-6.0.6.2-intellij-idea破解版

    IDEA2019 JFormDesigner-6.0.6.2-intellij-idea破解版 下载链接:百度云 提取码:10ox 下载完后通过idea的本地磁盘安装即可

  3. 软工第04组 Alpha冲刺(1/6)

    队名:new game 组长博客:戳 作业博客:戳 组员情况 鲍子涵(队长) 过去一段时间对项目的精度和分工进行了更加细致的划分,并初步进行了GamePlay逻辑部分的框架设计 GitHub签入记录: ...

  4. Spring核心内容-认识bean

  5. ModuleNotFoundError: No module named '_sqlite3'的解决办法:pipenv的用法

    export PIPENV_VENV_IN_PROJECT=1pipenv --venvpipenv --where pipenv install -r requirements.txtpipenv ...

  6. golang 性能剖析pprof

    作为一个golang coder,使用golang编写代码是基本的要求. 能够写出代码,并能够熟悉程序执行过程中各方面的性能指标,则是更上一层楼. 如果在程序出现性能问题的时候,可以快速定位和解决问题 ...

  7. [svc]linux中的文件描述符(file descriptor)和文件

    linux中的文件描述符(file descriptor)和文件 linux为了实现一切皆文件的设计哲学,不仅将数据抽象成了文件,也将一切操作和资源抽象成了文件,比如说硬件设备,socket,磁盘,进 ...

  8. Cortex-M3 R0~R15寄存器组 & 特殊功能寄存器组

    [R0~R15寄存器组] Cortex-M3处理器拥有R0~R15的寄存器组,如: [R0~R12通用寄存器]R0~R12都是32位通用寄存器,用于数据操作.其中: R0~R7为低组寄存器,所有的指令 ...

  9. java 斐波那契数列

    package feibo; public class Feibo { static int ss = 50; public static void main(String[] args) { // ...

  10. 六十九:flask上下文之线程隔离的g对象的使用

    保存全局对象的g对象g对象是在整个flask应用运行期间都是可以使用的,并且也是和request一样,是线程隔离的,这个对象是专门用来存放开发者自己定义的一些数据,方便在整个flask程序中都可以使用 ...