c#简要概括面向对象的三大特征(二)

续上篇.
二、继承
1、什么是继承

继承是指这样一种能力:它可以使用现有类的所有功能,并在无需重新编写原来的类的情况下对这些功能进行扩展。继承可以扩展已存在的代码模块(类),它们的目的都是为了“代码重用”。
2、继承相关概念和术语
通过继承创建的新类称为“子类”或“派生类”;被继承的类称为“基类”、“父类”或“超类”。继承的过程,就是从一般到特殊的过程。要实现继承,可以通过“继承”(Inheritance)和“组合”(Composition)来实现。
在某些OOP语言(如c++等)中,一个子类可以继承多个基类。但是一般情况下,一个子类只能有一个基类,要实现多重继承,可以通过多级继承来实现。
3、继承分类
继承概念的实现方式有三类:实现继承、接口继承和可视继承。
(1)、实现继承是指使用基类的属性和方法而无需额外编码的能力;
(2)、接口继承是指仅使用属性和方法的名称、但是子类必须提供实现的能力;
(3)、可视继承是指子窗体(类)使用基窗体(类)的外观和实现代码的能力。
在考虑使用继承时,有一点需要注意,那就是两个类之间的关系应该是“属于”关系。
OO开发范式大致为:划分对象→抽象类→将类组织成为层次化结构(继承和合成) →用类与实例进行设计和实现几个阶段。
下面举例说明实现继承和接口继承。
4、c#继承相关术语和注意点
要声明一个类派生于另一个类,可以看下面的例子:

Code
注意:
<1>、继承中的virtual关键字
把一个基类方法声明为virtual(即标志为虚函数),该方法就可以在任意派生类中重写。
也可以把属性声明为virtual。对于虚属性或重写属性,语法与非虚属性是相同。但要在定义中加上关键字virtual。
Code
<2>、隐藏方法
如果签名相同的方法在基类和派生类中都进行了声明,但该方法没有声明为virtual和override,派生类方法就会隐藏基类方法,通过new关键字,可以隐藏基类方法:
Code
上一篇我们介绍了类的封装,其中抽象类也可以继承,看代码:
Code
要声明一个类派生于一个或多个接口,看下面代码:
Code
5、你必须知道的三点补充
<1>、C#中的修饰符
a、可见性修饰符
可见性修饰符              应用于                                 说明
public                      所有的类型或成员                    任何代码均可以访问该方法
protected                类型和内嵌类型的所有成员         只有派生类型能访问该方法
internal                   类型和内嵌类型的所有成员         只能在包含它的程序集中访问该方法
private                    所有的类型或成员                    只能在它所属的类型中访问该方法
protected internal    类型和内嵌类型的所有成员          只能在包含它的程序集和派生类型的代码中访问该方法
b、其他修饰符
修饰符               应用于                               说明
new                 函数成员                             成员用相同的签名隐藏继承的成员
static               所有的成员                          成员不在类的具体实例上执行
virtual              函数成员                             成员可以由派生类重写
abstract           仅类和函数成员                    仅定义成员的签名,但没有提供具体实现代码
override           仅函数成员                          成员重写了继承的虚拟或抽象成员
sealed             类或方法                             类不能被继承,修饰方法时,方法不能被重写    
extern             仅静态[DllImport]方法          成员在外部用另一种语言实现
  
<2>、C#类的初始化顺序
先看一下有趣的代码:
Code

 
程序动行的结果是:
继承类静态成员DriveB_b初始化
继承类实例变量DriveB_c初始化
基类静态成员初始化
基类实例变量BaseA_c初始化
基类构造方法被调用
继承类构造方法被调用
经过分析,我们得出c#类初始化的一般规律
a.先变量后构造函数。变量先被初始化,然后构造函数被执行
b.先静态化后实例化。当一个类被访问时,静态变量和构造函数最先被初始化.接着是对象的实例化变量和构造函数被初始化
c.先派生类后基类(实例构造函数除外)。对于变量和静态构造函数,派生对象在基对象之前被初始化.比如C类派生自B类,B类派生自A类,那么变量和静态构造函数被初始化次序是C-B-A.
d.对于实例构造函数,基类构造函数在派生类构造函数之前执行,实例构造函数被执行次序是A-B-C.

最后我们得出c#类初始化顺序结论: 
a、继承类静态成员变量初始化 
b、继承类实例变量初始化 
c、基类静态静态成员变量初始化 
d、基类实例变量初始化 
e、基类构造函数调用
 
f、继承类构造函数调用

<3>、抽象类和接口的异同

a、抽象类是特殊的类,不能被实例化;除此以外,具有类的其他特性;抽象类可以包括抽象方法,这是普通类所不具备的特点。抽象方法只能声明于抽象类中,且不包含任何实现,派生类必须覆盖它们。抽象类不能被密封。另外,抽象类可以派生自一个抽象类,可以覆盖基类的抽象方法也可以不覆盖,如果不覆盖,则其派生类必须覆盖它们。
b、接口类似于抽象类,和抽象类的相似之处有三点:
不能实例化;包含未实现的方法声明;派生类必须实现未实现的方法,抽象类是抽象方法,接口则是所有成员(不仅是方法包括其他成员);
c、接口的其他特性
接口除了可以包含方法之外,还可以包含属性、索引器、事件,而且这些成员都被定义为公有的。除此之外,不能包含任何其他的成员,例如:常量、域、构造函数、析构函数、静态成员。
一个类可以直接继承多个接口,但只能直接继承一个类(包括抽象类)。
d、关于接口和抽象类的形象描述(摘自网上博文)
    d1.飞机会飞,鸟会飞,他们都继承了同一个接口“飞”;但是F22属于飞机抽象类,鸽子属于鸟抽象类。
    d2. 就像铁门木门都是门(抽象类),你想要个门我给不了(不能实例化),但我可以给你个具体的铁门或木门(多态);而且只能是门,你不能说它是窗(单继承);一个门可以有锁(接口)也可以有门铃(多实现)。 门(抽象类)定义了你是什么,接口(锁)规定了你能做什么(一个接口最好只能做一件事,你不能要求锁也能发出声音(接口污染)。

posted on 2009-05-14 18:09  JeffWong  阅读(1384)  评论(0编辑  收藏  举报