什么是继承
- 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
- 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
- 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。
1.2 什么是继承
本节将介绍以下内容:
—什么是继承?
—继承的实现本质
—继承的分类与规则
—继承与聚合
—继承的局限
1.2.1 引言
继承,一个熟悉而容易产生误解的话题。这是大部分人对继承最直观的感受。说它熟悉,是因为作为面向对象的三大要素之一的继承,每个技术研究者都会在职业生涯中不断地重复关于继承的话题;说它容易产生误解,是因为它总是和封装、多态交织在一起,形成复杂的局面。以继承为例,如何理清多层继承的机制,如何了解实现继承与接口继承的异同,如何体会继承与多态的关系,似乎都不是件简单的事情。
本节希望将继承中最为头疼,最为复杂的问题统统拿出来晒一晒,以防时间久了,不知不觉在使用者那里发霉生虫。
本节不会花太多笔墨做系统性的论述,如有需要请参考其他技术专著上更详细的分析。我们将从关于继承的热点出发,逐个击破,最后总结规律,期望用这种方式实现对继承全面的了解,让你掌握什么才是继承。
1.2.2 基础为上
正如引言所述,继承是个容易产生误解的技术话题。那么,对于继承,就应该着手从这些容易误解与引起争论的话题来寻找关于全面认识和了解继承的答
案。一点一滴摆出来,最后再对分析的要点做归纳,形成一种系统化认识。这是一种探索问题的方式,用于剖析继承这一话题真是再恰当不过了。
不过,解密之前,我们还是按照技术分析的惯例,从基本出发,以简洁的方式来快速了解关于继承最基本的概念。首先,认识一张比较简单的动物分类图(图1-1),以便引入我们对继承概念的介绍。
图1-1 继承关系图
从图1-1中,我们可以获得的信息包括:
—动物继承关系是以一定的分类规则进行的,将相同属性和特征的动物及其类别抽
象为一类,类别与类别之间的关系反映为对相似或者对不相似的某种抽象关系,
例如鸟类一般都能飞,而鱼类一般都生活在水中。
—位于继承图下层的类别继承了上层所有类别的特性,形成一种IS-A的关系,例
如我们可以说,人类IS-A哺乳类、人类IS-A脊椎类。但是这种关系是单向的,
所以我们不能说鸟类IS-A鸡。
—动物继承图自上而下是一种逐层具体化过程,而自下而上是一种逐层抽象化过
程,这种抽象化关系反映为上下层之间的继承关系。例如,最高层的动物具有最
普遍的特征,而最低层的人则具有较具体的特征。
—下层类型只能从上层类型中的某一个类别继承,例如鲸类的上层只能是哺乳类一
种,因此是一种单继承形式。
—这种继承关系中,层与层的特性是向下传递的,例如鸟类具有脊椎类的特征,鹤
类也具有脊椎类的特征,而所有的类都具有动物的特征,因此说动物是这个层次
关系的根。
我们将这种现实世界的对象抽象化,就形成了面向对象世界的继承机制。因此,关于继承,我们可以定义为:
继承,就是面向对象中类与类之间的一种关系。继承的类称为子类、派生类,而被继承类称为父类、基类或超类。通过继承,使
得子类具有父类的属性和方法,同时子类也可以通过加入新的属性
和方法或者修改父类的属性和方法建立新的类层次。
继承机制体现了面向对象技术中的复用性、扩展性和安全性。为面向对象软件开发与模块化软件架构提供了最基本的技术基础。
在.NET中,继承按照其实现方式的不同,一般分类如下。
—实现继承:派生类继承了基类的所有属性和方法,并且只能有一个基类,在.NE
T中System.Object是所有类型的最终基类,这种继承方式称为实现继承。
—接口继承:派生类继承了接口的方法签名。不同于实现继承的是,接口继承允许
多继承,同时派生类只继承了方法签名而没有方法实现,具体的实现必须在派生
类中完成。因此,确切地说,这种继承方式应该称为接口实现。
CLR支持实现单继承和接口多继承。本节重点关注对象的实现继承,关于接口继承,我们将在1.5节“玩转接口”中做详细论述。另外,值得关注的是继承
的可见性问题,.NET通过访问权限来实现不同的控制规则,这些访问修饰符主要包括:public、protected、internal和private。
下面,我们就以动物继承情况为例,实现一个最简单的继承实例,如图1-2所示。
图1-2 动物系统UML
在这个继承体系中,我们实现了一个简单的三层继承层次,Animal类是所有类型的基类,在此将其构造为抽象类,抽象了所有类型的普遍特征行为:Eat方法和ShowType方法,其中ShowType方法为虚函数,其具体实现在子类Chicken 和Eagle中给出。这种在子类中实现虚函数的方式,称为方法的动态绑定,是实现面向对象另一特性:多态的基本机制。另外,Eagle类实现了接口继承,使得Eagle实例可以实现Fly这一特性,接口继承的优点是显而易见的:通过IFlya
ble接口,实现了对象与行为的分离,这样我们无需担心因为继承不当而使Chi cken有Fly的能力,保护了系统的完整性。
从图1-2所示的UML图中可知,通过继承我们轻而易举地实现了代码的复用和扩展,同时通过重载(overload)、覆写(override)、接口实现等方式实现了封装变化,隐藏私有信息等面向对象的基本规则。通过继承,轻易地实现了子类对父类共性的继承,例如,Animal类中实现了方法Eat(),那么它的所有子类就都具有了Eat()特性。同时,子类也可以实现对基类的扩展和改写,主要有两种方式:一是通过在子类中添加新方法,例如Bird类中就添加了新方法ShowCo lor用于现实鸟类的毛色;二是通过对父类方法的重新改写,在.NET中称为覆写,例如Eagle类中的ShowColor()方法。
1.2.3 继承本质论
了解了关于继承的基本概念,我们回归本质,从编译器运行的角度来揭示.N ET继承中的运行本源,来发现子类对象如何实现对父类成员与方法的继承,以简单的示例揭示继承的实质,来阐述继承机制是如何被执行的。
public abstract class Animal
{
public abstract void ShowType();
public void Eat()
{
Console.WriteLine("Animal always eat.");
}
}
public class Bird: Animal
{
private string type = "Bird";