今日内容
6.1 继承的基本概念及使用
6.2 继承类的创建过程 类的单根性 传递性 超级基类Object
6.3 子类覆盖父类成员 new关键字 虚方法
6.4 多态的基本概念 里氏替换原则
一个类如果没有显示继承任何类将会继承?
子类构造函数优先于父类构造函数调用是否正确,为什么?
C#中一个类最多可以有几个基类?
new 关键字有几个作用?
在子类中重写父类的虚方法使用___ 关键字?
里氏替换原则的作用是什么?
6.1 继承的基本概念及使用
继承的基本概念
继承是面向对象程序设计中最重要的概念之一。继承允许我们根据一个类来定义另一个类,这使得创建和维护应用程序变得更容易。同时也有利于重用代码和节省开发时间。
当创建一个类时,程序员不需要完全重新编写新的数据成员和成员函数,只需要设计一个新的类,继承了已有的类的成员即可。这个已有的类被称为的基类,这个新的类被称为派生类。
继承的思想实现了 属于(IS-A) 关系。例如,哺乳动物 属于(IS-A) 动物,狗 属于(IS-A) 哺乳动物,因此狗 属于(IS-A) 动物。
基类和派生类
派生类只能有一个直接基类,但一个基类可以有多个直接派生类。继承是可以传递的。定义要从其他类派生的类时,派生类会隐式获得基类的所有成员(除了其构造函数和终结器)。派生类因而可以重用基类中的代码,而无需重新实现。在派生类中,可以添加更多成员。通过这种方法,派生类可扩展基类的功能。
1.定义
如果A类继承自B类,则A类拥有B类的全部成员,B类叫做父类(基类),A类叫做B类的派生类。
2.注意
C#中的对象仅能直接派生于一个基类,但是基类可以有自己的基类。
3.特性--访问控制
①派生类和外部代码都不能访问基类的私有成员,可以访问公有成员。
②只有派生类能访问基类的protected 成员,外部代码不能访问private 和protected 成员。
③基类的成员是虚拟的,如果派生类重写了实现代码,则实现代码不会删除原来的代码,仍可在类中访问原来的代码,但外部成员不能访问它们;
如果没有提供其他实现方式,通过派生类使用成员的外部代码就自动访问基类中成员的实现代码。
C#面向对象编程的基本概念 接口 继承和多态
继承的应用场景
要理解继承怎么用,先要搞清楚继承有什么用。
初学者不能理解继承是因为他没有这个需要,因为他一个人编写一个程序,那么这个程序所有的代码都是为他最终的那个程序服务的。
我们假设你不是一个人独立写一个程序,而是和别的开发者合作,一起实现最终的程序,你编写的代码不能随意让别的开发者修改,甚至都不必让他们拥有你的代码。如果你没有这样的经验,你必须努力设想这个场景。
一旦你想明白这一点,马上你就有这样一种需求:因为你的代码需要被调用或者调用人家的代码,而它不能被修改,所以它必须是一个黑盒,它要尽可能通用,这种通用不是指你在编写代码的时候考虑到所有可能的情形,这往往不现实,你希望的是,它能够适应未知的场景。为了达到这一点,你的代码必须留出一些“空白”,这些地方的代码由调用它的人来“填空”。
比如说,你编写了一个媒体播放器,你专注的是,它拥有美丽的外观,可以方便地组织播放列表,可以设置循环播放,等等……但是你希望它能播放的媒体文件的类型不仅限于你所听说过的那几种,甚至是程序写好的时候还没有发明的格式。这种情况下,媒体文件的读取解析的代码就不能直接在程序中写好,必须由第三方写好了,你来调用,你的程序如何调用你开发的时候甚至都不存在的代码呢?
这个时候你可以用到继承,你定义一个基类,规定播放一个文件需要调用什么方法,需要什么参数,但是你并不直接实现它。而第三方的开发者只要继承这个类,重写你定义的方法,在里面具体给出实现的代码。而你的程序通过一种机制(我们一般用反射)在运行时根据配置文件创建第三方开发者开发的这个继承类的对象,这样你的程序就可以借助继承,调用到这些代码,仿佛这些代码是一个整体。
这就是继承的作用。
C#的继承和多态
6.2 继承类的创建过程 类的单根性 传递性 超级基类Object
上帝类Object简介
Object这个类型,是CLR定义的最基础的类型,俗称"上帝类"。CLR(运行时)要求所有类型,不管是系统定义的类型还是自定义的类型,都必须从Object派生,因为CLR会要求所有的类型都派生自Object,所以自定义类就算没有显示继承Object类,CLR还是会让自定义类默认继承Object类,由于所有的类型都从System.Object类型派生,所以每个类型的每个对象(实例)都会有一组最基本的方法。
C# 终极基类Object简介
C# 继承类的创建过程
一.类的创建
1.基本语法:访问修饰符 class 类名{}
2.实例:创建一个二维下的点类
public class Point //基类
{
public int x, y;
public Point(int x, int y)
{
this.x = x;
this.y = y;
}
}
二.类的继承(又名派生,C#只支持单继承)
1.基本语法:访问修饰符 class 子类名:父类名
2.实例:创建一个三维下的点类,继承于二维的点,给它加上一个第三维的坐标。
public class Point3D : Point//继承
{
public int z;
public Point3D(int x, int y, int z) :
base(x, y)
{
this.z = z;
}
}
C#的类的创建简单继承
继承 单根性 传递性 名词解释
继承是C#中面向对象的特性之一。
1.继承,简单一句话就是建立类之间的关系,实现代码的重用性,方便系统扩展。继承的两大特性是单根性和传递性。
2.继承的单根性:是指子类只能继承一个父类,不能同时继承多个父类。就好比儿子只能有一个父亲(亲生),派生类只能从一个类中继承,继承不支持多重继承。避免代码结构的复杂性。
3.继承的传递性:派生类是从基类那里继承特性,派生类也可以作为其他类的基类。从一个基类派生出多层类,这样就形成类层次结构。就是a继承b。a可以调用b的方法和属性,但是b又继承了c~所有a也可以调用c的方法和属性。
继承的两个特性单根性 传递性 是什么意思求解释
6.3 子类覆盖父类成员 new关键字 虚方法
在子类中用override重写父类中用virtual申明的虚方法时,实例化父类调用该方法,执行时调用的是子类中重写的方法;
如果子类中用new覆盖父类中用virtual申明的虚方法时,实例化父类调用该方法,执行时调用的是父类中的虚方法;
举例说明
假设中国人(子类) 继承自 人(基类)
人(基类)定义了一个函数叫“吃晚饭”(可以定义为用手抓饭)
如果这个函数不是virtual的话
那么 下列代码
Person p = new Chinese();
p.EatDinner();
调用的是 人(基类)的“吃晚饭” 而不是中国人的吃饭习惯
而 如果这个函数是virtual的话
那么 中国人(子类)可以用override 覆盖写这个virtual 代码
那么 下列调用
p.EatDinner();
调用的是 中国人的“吃晚饭”函数 也就是用筷子吃面等等
具体的内部实现呢 是基类有一个虚函数表
记录所有的virtual函数
这样 如果子类把基类的virtual函数给实现了(有自己的一套吃饭办法)
那么 虚函数表里的这个函数就指向子类的那个函数
否则 就指向基类
这就是“晚绑定”——不在编译期间 而是运行期绑定子类已经覆盖的函数
注意override 只适用与 virtual
如果要覆盖不是virtual的函数 则必须用new
C#中子类对父类中虚方法的处理有重写(override)和覆盖(new),他们有什么区别?
C#中继承实现父类方法、重写、重载
c#到的virtual 为父类的方法,在子类中用override来覆盖怎么没错的?
6.4 多态的基本概念 里氏替换原则
多态性意味着有多重形式。在面向对象编程范式中,多态性往往表现为"一个接口,多个功能"。
多态性可以是静态的或动态的。在静态多态性中,函数的响应是在编译时发生的。在动态多态性中,函数的响应是在运行时发生的。
C#多态性
里氏替换原则详解--七大面向对象设计原则(2)
C#中易混淆概念:解析里氏替换原则,虚方法
一个类如果没有显示继承任何类将会继承?
Object
子类构造函数优先于父类构造函数调用是否正确,为什么?
正确
①调用子类的构造函数
②调用父类的构造函数
③执行父类的构造函数
④执行子类的构造函数
在派生类中,如果不用base关键字来显示调用基类构造函数,则隐式调用默认构造函数。
C#中一个类最多可以有几个基类?
只能有一个基类,但一个基类可以有多个派生类。
new 关键字有几个作用?
1.new 运算符 用于创建对象和调用构造函数。
2.new 修饰符 用于隐藏基类成员的继承成员。
3.new 约束 用于在泛型声明中约束可能用作类型参数的参数的类型。
在子类中重写父类的虚方法使用___ 关键字?
virtual override
问题一:什么是重写?
“重写”父类方法就是修改它的实现方式或者说在子类中对它进行重新编写。
问题二:为什么要重写父类的方法 通常,子类继承父类的方法,在调用对象继承方法的时候,调用和执行的是父类的实现。但是,有时候需要
对子类中的继承方法有不同的实现方式。例如,假设动物存在“跑”的方法,从中继承有狗类和马类两个子
问题三:如何重写
a.重写父类的方法要用到override关键字(具有override关键字修饰的方法是对父类中同名方法的新实现)
b.要重写父类的方法,前提是父类中该要被重写的方法必须声明为virtual或者是abstract类型。给父类中
要被重写的方法添加virtual关键字表示可以在子类中重写它的实现。(注意:C#中的方法默认并不是
virtual类型的,因此要添加virtual关键字才能够被重写)
C.virtual关键字用于将方法定义为支持多态,有virtual关键字修饰的方法称为“虚拟方法”
[访问修饰符] virtual [返回类型] 方法名(参数列表)
{
//虚拟方法的实现,该方法可以被子类重写
}
里氏替换原则的作用是什么?
里氏替换原则为良好的继承定义了一个规范,它包含了4层定义:
子类必须完全实现父类的方法。
1.子类可以有自己的个性。
2.覆盖或实现父类的方法时输入参数可以被放大。
3.覆写或实现父类的方法时输出结果可以被缩小。
4.采用里氏替换原则的目的就是增强程序的健壮性,版本升级时也可以保持非常好的兼容性。即使增加子类,原有的子类还可以继续运行。在实际项目中,每个子类对应不同的业务含义,使用父类作为参数,传递不同的子类完成不同的业务逻辑,非常完美。
关于里氏替换原则与多态概念纠正
设计原则(二)里氏替换原则(LSP)