C# 图解教程 第5版 —— 第8章 类和继承

news2025/1/13 10:31:00

文章目录

    • 8.1 类继承
    • 8.2 访问继承的成员(*)
    • 8.3 所有类都派生自 object 类
    • 8.4 屏蔽基类的成员
    • 8.5 基类访问
    • 8.6 使用基类的引用
      • 8.6.1 虚方法和覆写方法
      • 8.6.2 覆写标记为 override 的方法
      • 8.6.3 覆盖其他类型成员(*)
    • 8.7 构造函数的执行
      • 8.7.1 构造函数初始化语句
      • 8.7.2 类访问修饰符
    • 8.8 程序集间的继承
    • 8.9 成员访问修饰符
      • 8.9.1 访问成员的区域
      • 8.9.2 公有成员的可访问性
      • 8.9.3 私有成员的可访问性
      • 8.9.4 受保护成员的可访问性
      • 8.9.5 内部成员的可访问性
      • 8.9.6 受保护内部成员的可访问性
      • 8.9.7 成员访问修饰符小结
    • 8.10 抽象成员
    • 8.11 抽象类
      • 8.11.1 抽象类和抽象方法的示例(*)
      • 8.11.2 抽象类的另一个例子(*)
    • 8.12 密封类
    • 8.13 静态类
    • 8.14 扩展方法
    • 8.15 命名约定

8.1 类继承

  • 要派生一个类,需要在类名后面加入 基类规格说明,由冒号和基类名称组成。
  • 派生类不能删除继承的成员。
image-20231026111011929
图8.1 基类规格说明
image-20231026111117403
图8.2 基类和派生类

8.2 访问继承的成员(*)

8.3 所有类都派生自 object 类

​ object 类是唯一的非派生类,是继承层次结构的基础。

image-20231026111341681
图8.3 类层次结构

8.4 屏蔽基类的成员

​ 虽然派生类不能删除继承的成员,但可以声明相同名称的成员来进行屏蔽(覆盖)。屏蔽基类成员的要点如下:

  • 声明一个相同类型、相同名称的成员。
    • 如果屏蔽函数成员,则签名需要相同(签名不包括返回类型)。
  • 使用 new 修饰符告诉编译器在故意屏蔽,否则编译器会发出警告。
  • 也可以屏蔽静态成员。
image-20231026112022389 image-20231026112036517
图8.4 屏蔽基类成员

8.5 基类访问

​ 基类访问表达式由关键字 base 后面跟着一个点和成员的名称组成:

image-20231026112139703
图8.5 基类访问

​ 下面的代码中,使用基类访问表达式访问了被隐藏的 Field1:

image-20231026112253307
图8.5 访问被隐藏的 Field1

​ 一般来说,能够有更优雅的设计避免这种情况,但是实在没办法的时候也可以使用这个特性。

8.6 使用基类的引用

​ 使用类型转换运算符可以将派生类对象的引用转换为基类对象的引用,转换后的引用只能访问基类的成员。

  • 基类的引用“看不到”派生类的其余部分,因为它通过基类类型的引用“看”这个对象。
image-20231026112751219 image-20231026112759875
图8.6 派生类的引用可以看到完整的 MyDerivedClass 对象,而 mybc 只能看到对象的 MyBaseClass 部分

8.6.1 虚方法和覆写方法

​ 上述介绍的内容:使用基类引用访问派生类对象时,得到的是基类成员。

虚方法 可以使基类的引用访问“升至”派生类内。使用基类引用调用派生类的方法条件如下:

  • 派生类方法和基类方法有相同的签名和返回类型。
  • 基类的方法使用 virtual 标注。
  • 派生类的方法使用 override 标注。
image-20231026113203563 image-20231026113217159 image-20231026113259442
图8.7 虚方法和覆写方法

​ 关于 virtual 和 override 的重要信息如下:

  • 覆写和被覆写的方法必须有相同的可访问性。
  • 不能覆写 static 方法或非虚方法。
  • 方法、属性、索引器、事件都可以被声明为 virtual 和 override。

8.6.2 覆写标记为 override 的方法

​ 覆写方法可以在继承的任何层次出现。使用基类部分的引用调用一个被覆写的方法时:

  1. 方法调用沿派生层次上溯执行,直到标记为 override 方法的最高派生版本。
  2. 如果有更高派生级别的方法但没有标记为 override,则不会被调用。
image-20231026113814694
图8.8 具有派生层次的三个类

情况1:使用 override 声明 Print

image-20231026113958997 image-20231026114009930
图8.9 override 声明 Print 及输出结果

​ 结果说明:无论是通过派生类还是通过基类引用调用,都会调用最高派生类中的方法。

image-20231026114037205
图8.10 执行被传递到多层覆写链的顶端

情况2:使用 new 声明 Print

image-20231026114350210 image-20231026114414493
图8.11 new 声明 Print 及输出结果

​ 结果说明:方法调用只向上传递了一级,因为最高层的方法没有被声明为 override。

image-20231026114426173
图8.12 隐藏覆写的方法

8.6.3 覆盖其他类型成员(*)

8.7 构造函数的执行

  • 要创建对象的基类部分,需要隐式调用基类的某个构造函数。
  • 继承层次链中的每个类在执行自己的构造函数体之前执行它的基类构造函数。
class MyDerivedClass : MyBaseClass
{
    MyDerivedClass() { // 构造函数调用基类构造函数 MyBaseClass()
        ...
    }
}
image-20231026114936221
图8.13 对象构造的顺序

​ 强烈反对在构造函数中调用虚方法。

8.7.1 构造函数初始化语句

  • 第一种形式:使用关键字 base 指明使用哪一个基类构造函数。
image-20231026115315583
图8.14 第一种形式初始化语句

​ 当声明一个不带构造函数初始化语句的构造函数时,实际上是带有 base() 构造函数初始化语句的简写形式:

image-20231026115451437
图8.15 等价的构造函数形式
  • 第二种形式:使用关键字 this 指明使用当前类的哪一个构造函数。
image-20231026115557173
图8.16 第二种形式初始化语句

​ 当类需要多个构造函数时:

  • 推荐做法:提取公共代码至一个构造函数内,其他构造函数使用该公共构造函数进行初始化。

  • 不推荐做法:提取公共代码至一个方法内,让所有构造函数调用这个方法。

    原因:

    • 编译器对构造函数能有一些特殊优化。
    • 有些事情必须在构造函数中进行,例如初始化 readonly 字段。

8.7.2 类访问修饰符

​ 类的可访问性只有两个级别:

  1. public:能够被系统内任何程序集中的代码访问。

  2. internal:只能被自己所在程序集(不是程序,也不是 DLL)中的类看到。

​ 默认访问级别是 internal。

image-20231026120324534
图8.17 其他程序集中的类可以访问公有类但不能访问内部类

8.8 程序集间的继承

​ C# 允许在不同的程序集之间进行继承。要从其他程序集中的基类派生类,句许具备如下条件:

  1. 基类被声明为 public 以供外部访问。
  2. 添加对程序集的引用以找到基类。
    • 增加对程序集的引用并不是使用 using 指令,而是告诉编译器所需的类型在哪里定义。
    • using 指令是允许引用其他的类而不必使用它们的完全限定名称。
image-20231026145046102
图8.18 Assembly1.cs
image-20231026145220559 image-20231026145157532
图8.19 Assembly2.cs
image-20231026145327305
图8.20 跨程序集继承

8.9 成员访问修饰符

  • 所有显示声明在类中的成员都是相互可见的,无论它们的访问性如何。即,同一类中的成员是相互透明的。
  • 继承的成员不在类中显示声明,因此对派生类不一定可见。
  • 成员的隐式访问级别为 private,一共有 5 中可访问级别:
    • public
    • private
    • protected
    • internal
    • protected internal
  • 成员的可访问性不能比类高。

8.9.1 访问成员的区域

​ 如下所示,MyClass 被声明为 public,因此所有程序集都可以访问该类,但其成员是否可访问依赖于成员的访问修饰符:

image-20231026150324683 image-20231026150313814
图8.21 访问性的区域划分

​ 另一个类能否访问 MyClass 的成员取决于该类的以下两个特征:

  1. 是否派生自 MyClass。
  2. 是否和 MyClass 在同一程序集。

​ 依据这两个特征可以划分出图 8.21 中的 4 个区域。

8.9.2 公有成员的可访问性

​ public 访问级别的限制是最少的(几乎没有的),所有类都可以自由访问该成员。

image-20231026150654828
图8.22 公有类的公有成员对同一程序集或其他程序集的所有类可见

8.9.3 私有成员的可访问性

​ private 访问级别的限制是最严格的,只有自己或嵌套在自己内部的类才能访问类成员,其他所有类都不行。

image-20231026150822749
图8.23 任何类的私有成员只对它自己的类(或嵌套类)的成员可见

8.9.4 受保护成员的可访问性

​ 比 private 限制稍宽松,在 private 的基础上还允许子类访问。

image-20231026151032794
图8.24 公有类的受保护成员对它自己的类成员或派生类的成员可见,派生类甚至可以在其他程序集中

8.9.5 内部成员的可访问性

​ internal 允许成员对程序集内部的所有类可见,对程序集外部的所有类不可见。

image-20231026151208350
图8.25 内部成员对同一程序集内部的任何类成员可见,但对程序集外部的类不可见

8.9.6 受保护内部成员的可访问性

​ protected internal 的访问性是 protected 和 internal 的 并集,不是交集。

image-20231026151405084
图8.26 公有类的受保护内部成员对相同程序集的类成员或继承该类的类成员可见,对其他程序集中且不继承该类的类不可见

8.9.7 成员访问修饰符小结

表8.1 成员访问修饰符
image-20231026151528212

​ 图 8.27 演示了成员访问修饰符的可访问级别。

image-20231026151630946
图8.27 各种成员访问修饰符的相对可访问性

​ 表 8.2 总结了以上所有情况。

表8.2 成员可访问性总结
image-20231026151738219

8.10 抽象成员

​ 抽象成员是待被覆写的函数成员,具有如下特征:

  • 必须是函数成员。
  • 必须用 abstract 修饰符标记。
  • 不能有实现代码块,而用分号代替。
image-20231026190311331
图8.28 抽象成员的声明

​ 以下类型的成员可以被声明为抽象成员:

  • 方法。
  • 属性。
  • 事件。
  • 索引器。

​ 其他重要事项如下:

  1. 不能将 virtual 修饰符附加到抽象成员上。
  2. 类似于虚成员,派生类中抽象成员的实现必须指定 override 修饰符。
表8.3 比较虚成员和抽象成员
image-20231026190544687

8.11 抽象类

​ 抽象类只能被用作其他类的基类。

  • 不能创建抽象类的实例。
  • 抽象类使用 abstract 修饰符声明。
  • 抽象类可以包含抽象成员或非抽象成员。
  • 抽象类自己可以派生自另一个抽象类。
  • 任何派生自抽象类的类必须使用 override 关键字实现该类所有的抽象成员,除非自己也是抽象类。
image-20231026190825211
图8.29 抽象类的声明

8.11.1 抽象类和抽象方法的示例(*)

8.11.2 抽象类的另一个例子(*)

8.12 密封类

  • 密封类只能被用作独立的类,不能被用作基类。
  • 使用 sealed 修饰符标注。
image-20231026191009984
图8.30 密封类的声明

8.13 静态类

​ 静态类的一个常见用途是创建一个包含一组数学方法和值的数学库。

  • 类本身必须标记为 static。
  • 所有成员必须是 static。
  • 可以有一个静态构造函数,但不能有实例构造函数。
  • 静态类隐式密封。
image-20231026191154082 image-20231026191206089
图8.31 静态类示例

​ C# 6.0后,可以使用 using static 指令访问静态类的成员,而不必使用类名。

8.14 扩展方法

​ 几乎整个 LINQ 库都是通过扩展方法来实现的。

  • 声明扩展方法的类必须声明为 static。
  • 扩展方法本身必须声明为 static。
  • 扩展方法必须包含关键字 this 作为第一个参数类型,后面跟着拓展类的名称。
image-20231026191619861 image-20231026191633334
图8.32 扩展方法的声明和结构

8.15 命名约定

表8.4 常用的标识符命名风格
image-20231026192028687

​ 说明:下划线不常出现在标识符的中间位置。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1137185.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

2011-2021年“第四期”数字普惠金融指数与上市公司匹配(根据省份匹配)/上市公司数字金融指数匹配

2011-2021年“第四期”数字普惠金融指数与上市公司匹配(根据省份匹配)/上市公司数字金融指数匹配 1、时间:2011-2021年 2、指标:股票代码、年份、行政区划代码、行业名称 、行业代码、所属省份、数字普惠金融指数、覆盖广度、使…

嵌入式学习5大误区,你中招了吗?

目录 误区1:错把自己当稚晖君 误区2:错误的学习方法 误区3:忽略时间成本 误区4:缺乏系统思维 误区5:追求完美主义 误区1:错把自己当稚晖君 稚晖君能够以一己之力创造一个个惊艳的产品,离不…

代码随想录算法训练营第三十四天 | LeetCode 860. 柠檬水找零、406. 根据身高重建队列、452. 用最少数量的箭引爆气球

代码随想录算法训练营第三十四天 | LeetCode 860. 柠檬水找零、406. 根据身高重建队列、452. 用最少数量的箭引爆气球 文章链接:柠檬水找零 根据身高重建队列 用最少数量的箭引爆气球 视频链接:柠檬水找零 根据身高重建队列 …

StarRocks 荣获 InfoWorld 2023 年最佳开源软件

近日,InfoWorld 公布了 2023 Bossie Awards 获奖名单,StarRocks 作为数据分析领域的明星项目,光荣入列。 InfoWorld 是一家具有全球影响力的信息技术媒体公司,每年都会根据软件对开源界的贡献,发布 Bossie Awards 榜单…

【Javascript】函数返回值的作用

目录 返回值 中断函数 只能写在函数体里面 返回值 function a(){var b3;return b3? 4:5;} console.log(a()); 创建一个函数,给b赋值3, return b3? 4:5; 判断b是不是等于3,如果是就返回4, 如果不是就返回5 中断函数…

JSON数据

一、JSON介绍 Android应用程序界面上的数据信息大部分都是通过网络请求从服务器上获取到的,获取到的数据类型常见的就是JSON。JSON是一种新的数据格式,这种格式的数据不可以直接显示到程序的界面上,需要将该数据解析为一个集合或对象的形式才…

Linux-安装docker-compose

前言:本文建立在服务器中已经存在docker环境的基础上,总结了安装docker-compose过程,以及安装过程中遇到的问题和解决方案。 一、下载docker-compose 在网上找了两种,一种是github官方的,一种是国内的镜像 gitbub官…

Python循环语句(二)

目录 二.for循环1.1for循环的基础语法1.2range语句1.3变量作用域2.for循环嵌套3.循环中断 二.for循环 1.1for循环的基础语法 while循环和for循环的区别 while循环的循环条件是自定义的,自行控制循环条件 for循环是一种轮询机制,是对一批内容进行逐个处…

多种方式计算当天与另一天的间隔天数 Java实现

这里不会记录纯原生写法,因为现在基本都是被工具类封装好的,所以会记录好用的工具类来简化开发,当然自己可以研究写一个年月日各自做减法的纯原生工具类。 踩坑处(System.currentTimeMillis) 这里指的是使用System.currentTimeMillis()方法。…

基于 Qt控制开发板 LED和C语言控制LED渐变亮度效果

## 资源简介 在STM32开发板,板载资源上有两个可自由控制的 LED。如下图原理 图其中我们以操作 LED1 为示例,LED1 为出厂系统的心跳指示灯。 ## 应用实例 想要控制这个 LED,首先出厂内核已经默认将这个 LED 注册成了 gpio-leds类型设备。所以我们可以直接在应用层接口直接…

如何通过内网穿透实现公网远程连接Redis数据库

公网远程连接Redis数据库【内网穿透】 文章目录 公网远程连接Redis数据库【内网穿透】前言1. Linux(centos8)安装redis数据库2. 配置redis数据库3. 内网穿透3.1 安装cpolar内网穿透3.2 创建隧道映射本地端口 4. 配置固定TCP端口地址4.1 保留一个固定tcp地址4.2 配置固定TCP地址…

国内主要的ERP软件有哪几种?谁家的ERP软件好用

不同的企业有不同的管理方式和侧重点,随着市场环境的变化,各行业竞争日趋激烈化,如何降低经营成本,提升产品质量,优化资源配置也成为各个企业努力的重点。 有些企业存在部门之间信息传递不及时、多组织协同效率低、不…

Java API访问HDFS

一、下载IDEA 下载地址:https://www.jetbrains.com/idea/download/?sectionwindows#sectionwindows 拉到下面使用免费的IC版本即可。 运行下载下来的exe文件,注意安装路径最好不要安装到C盘,可以改成其他盘,其他选项按需勾选即可…

2023年软件测试还能不能干,怎么干!听听这些肺腑之言!

“怎么办?我似乎连面试都过不了。” 小玲边喝着陪伴她度过无数熬夜的奶茶,边与朋友分享着自己在软件测试行业的求职之路。 被公司裁员后,小玲虽然通过自学掌握了一些基本的接口自动化和UI自动化测试技能,但面试时总还是遭遇到一些…

英伟达携手联发科打造CPU,威胁英特尔主导地位 | 百能云芯

据路透社报道,英伟达(NVIDIA)计划采用安谋(Arm)架构设计中央处理器(CPU),进军个人电脑(PC)市场。外界已指出,联发科是英伟达的合作伙伴&#xff0…

利用Nginx通过内网穿透实现Windows Web多站点远程访问

文章目录 1. 下载windows版Nginx2. 配置Nginx3. 测试局域网访问4. cpolar内网穿透5. 测试公网访问6. 配置固定二级子域名7. 测试访问公网固定二级子域名 1. 下载windows版Nginx 进入官方网站(http://nginx.org/en/download.html)下载windows版的nginx 下载好后解压进入nginx目…

Redis常用知识笔记(超全面!超详细!)收藏这一篇就够了

这里写目录标题 一、Key二、常见的数据类型1、string (字符串)1-1 常见命令1-2 案例 2、List(列表)2-1 常见命令2-2 案例 3、Hash(哈希)3-1 常见命令3-2 案例 4、Set(集合)元素唯一不重复4-1 常…

msigdbr hallmarks gsea broad研究所

使用msigdbr r包 #BiocManager::install("msigdb") #https://www.gsea-msigdb.org/gsea/msigdb #https://cran.r-project.org/web/packages/msigdbr/vignettes/msigdbr-intro.html #https://bioconductor.org/packages/release/data/experiment/vignettes/msigdb/ins…

vue3 setup语法糖 搜索

目录 前言 用法 1. 区域 前言 Vue.js 是一款流行的 JavaScript 框架,用于构建用户界面。它提供了一种简洁的方式来创建可维护和可测试的前端应用程序。Vue.js 的核心库只关注视图层,易于上手,同时与其他库或现有项目整合也非常方便。Vue…

解决Maven打包Nacos时插件报错

Maven打包指令:mvn clean install -Dmaven.test.skiptrue -Dcheckstyle.skiptrue 在执行时报错,报错信息如下: Failed to execute goal org.xolstice.maven.plugins:protobuf-maven-plugin:0.6.1:compile (default) on project nacos-consist…