一、类的继承
1. 类的派生遵循的原则
(1)派生类只能继承于一个基类
(2)派生类自然继承基类的成员,但不能继承基类的构造函数
(3)类的继承可以传递。例如,假设 C 类继承 B 类,B 类又继承 A 类,那么 C 类就具有了 B 类与 A 类的成员
(4)在 C# 中,object 类是所有类的基类,即所有的类都具有 object 类的成员
(5)派生类是对基类的扩展,派生类定义中可以声明新的成员,但不能删除已继承的基类成员
(6)基类中的成员声明时,不管其是什么访问控制方式,都能被派生类继承,访问控制方式的不同只是决定派生类是否能够访问基类成员;
(7)派生类定义中如果声明了与基类同名的成员,则基类的同名成员将被覆盖,因此派生类不能直接访问同名的基类成员
(8)基类可以定义虚方法成员,这样派生类能够重写这些成员以表现类的多态性
2. 派生类
(1)特点:
- 可以拥有自己的成员
- 可以隐式地从基类继承成员,包括方法、字段、属性和事件,但构造函数和析构函数等除外
- 有些父类成员在派生类中是不可访问的,如基类的 private 成员在子类中不可访问,但 protected 成员可以访问
(2)格式
public class 派生类类名:基类类名
{
成员声明列表;
}
(3)构造函数的调用
- 创建派生类对象时,会调用基类的构造函数。
- 在创建派生类对象时,调用构造函数的顺序是先调用基类构造函数,再调用派生类的构造函数
(4)based关键字(向基类构造函数传递参数)
- base关键字即可指代当前类的父类
- 在C#中,派生类不能继承其基类的构造函数,但通过使用 base 关键字,派生类构造函数就可以调用基类的构造函数
- 向基类构造函数传递参数,必须通过派生类的构造函数实现,其格式如下: public 派生类构造函数名(形参列表):base(向基类构造函数传递的实参列表){}
- base是C#关键字,表示调用基类的有参构造函数。传递给基类构造函数的“实参列表”通常包含在派生类构造函数的“形参列表”中
-
二、多态性
1. 概念
(1)多态性是面向对象编程语言非常重要的特性:“同一个名称,多种形态”
(2)在面向对象编程中,多态是指调用同一个方法名,却执行不同的方法体。多态性是类为方法(这些方法以相同的名称调用)提供不同实现方式的能力。
(3)利用多态,可以为应用程序增加灵活性。继承的多态性可以通过虚方法、抽象类和抽象方法、接口等来实现。
2. 虚方法
(1)使用 virtual 关键字修饰的方法称为虚方法,在一个类中如果某个方法需要被派生类继承,并且需要在派生类中修改方法时,可将该类定义为虚方法。
(2)在派生类中如果需要重写该方法,可在派生类中定义同名的方法,其前加上 override 关键字修饰。
(3)基类中的声明格式为:
public virtual 方法名称(参数列表){}
(4)派生类中的声明格式为:
public override 方法名称(参数列表){}
(5)其基类与派生类中的方法名称与参数列表必须完全一致
(6)使用 virtual 时,需要注意以下事项:
- virtual 不仅可以修饰方法,还可以修饰属性、事件和索引器成员
- 虚成员的访问修饰符不能定义为 private
- virtual 关键字不能和 static, abstract 或 override 关键字一起使用
- override 关键字不能和 new, static 或 virtual 关键字一起使用
- 在派生类中重写虚方法时,方法的签名要和基类中的虚方法一致
3. 方法隐藏-new关键字
(1)在C#中,若要更改基类的数据和行为,除了用虚方法外,还可以在派生类中使用 new 关键字,创建新的派生成员来替换基成员。
(2)在派生类中,把 new 关键字放置在要替换的类成员的返回类型之前,基类中的成员就成为隐藏成员。这时在派生类实例中访问该隐藏成员时,访问的是派生类自己新定义的成员。
(3)在派生类中用new关键字声明与基类同名方法的格式是:
public new 方法名称(参数列表){}
(4)new关键字修饰的方法与基类的方法仅仅是同名,并没有什么关联
三、抽象类
1. 定义:在基类定义中,只要类体中包含一个抽象方法,该类即为抽象类。在抽象类中也可以声明一般的虚方法。
2. 声明抽象类和抽象方法
(1)声明抽象类与抽象方法均需使用关键字 abstract,其格式为:
public abstract class 类名称
{
…
public abstract 返回类型 方法名称(参数列表);//抽象方法
…
}
(2)抽象方法不是一般的空方法,抽象方法声明时,没有方法体,所以只需在方法名后跟一个分号。
3. 重写抽象方法
(1)当定义抽象类的派生类时,派生类自然从抽象类继承抽象方法成员,并且必须重写抽象类的抽象方法,这是抽象方法与虚方法的不同,对于基类的虚方法,其派生类可以不必重写。重写抽象类方法必须使用 override 关键字。
(2)重写抽象方法的格式为:
public override 返回类型 方法名称(参数列表){}
(3)其中,方法名称与参数列表必须与抽象类中的抽象方法完全一致。抽象类具有以下特性:
- 抽象类不能被实例化;
- 抽象类可以包含抽象方法和抽象属性;
- 不能用sealed修饰符修饰抽象类;
- 从抽象类派生的非抽象类,必须要实现所有抽象方法(属性)。
四、接口
1. 接口的概念及声明
(1)接口是一种用来定义程序的协议,它描述可属于任何类或结构的一组相关行为。
(2)接口具有以下特征:
- 接口和抽象类有相似之处:继承接口的任何非抽象类型都必须实现接口的所有成员。
- 不能直接实例化接口。
- 接口可以包含事件、索引器、方法和属性。
- 接口不包含方法的实现。
- 类和结构可从多个接口继承。
- 接口自身可从多个接口继承。
(3)C#中声明接口时,使用 interface 关键字,其语法格式如下:
修饰符 interface 接口名称:继承的接口列表
{
接口内容;
}
(4)定义接口时,需要注意以下事项:
- 默认访问修饰符为 public;
- 为了区别类,接口的命名建议使用大写字母I打头;
- 接口的成员是从基接口继承的成员和由接口本身定义的成员;
- 接口成员默认访问方式是 public,接口成员定义不能包含任何修饰符;
- 接口不能直接实例化,但可以通过派生类对象进行实例化。
2. 接口的实现与继承
(1)必须要有类来继承所定义的接口并实现它,否则定义接口就毫无意义。
(2)接口的实现通过类继承来实现,一个类虽然只能继承一个基类,但可以继承任意多个接口。声明实现接口的类时,需要在基类列表中包含类所实现的接口名称,接口之间用逗号分隔。
class 类名 : [父类,] 接口, 接口, ……,接口
{
………
}
(3)实现接口的任何非抽象类型都必须实现接口的所有成员;
(4)对实现了某接口的类的实例进行访问时,可以直接访问,也可以通过接口实例来访问。