面向对象---类继承与多态
- 格式:doc
- 大小:115.50 KB
- 文档页数:16
第四章面向对象---类继承与多态一. 继承基础知识为了提高软件模块的可复用性和可扩充性,以便提高软件的开发效率,我们总是希望能够利用前人或自己以前的开发成果,同时又希望在自己的开发过程中能够有足够的灵活性,不拘泥于复用的模块。
C#这种完全面向对象的程序设计语言提供了两个重要的特性--继承性inheritance 和多态性polymorphism。
继承是面向对象程序设计的主要特征之一,它可以让您重用代码,可以节省程序设计的时间。
继承就是在类之间建立一种相交关系,使得新定义的派生类的实例可以继承已有的基类的特征和能力,而且可以加入新的特性或者是修改已有的特性建立起类的新层次。
现实世界中的许多实体之间不是相互孤立的,它们往往具有共同的特征也存在内在的差别。
人们可以采用层次结构来描述这些实体之间的相似之处和不同之处。
图1 类图上图反映了交通工具类的派生关系。
最高层的实体往往具有最一般最普遍的特征,越下层的事物越具体,并且下层包含了上层的特征。
它们之间的关系是基类与派生类之间的关系。
为了用软件语言对现实世界中的层次结构进行模型化,面向对象的程序设计技术引入了继承的概念。
一个类从另一个类派生出来时,派生类从基类那里继承特性。
派生类也可以作为其它类的基类。
从一个基类派生出来的多层类形成了类的层次结构。
注意:C#中,派生类只能从一个类中继承。
这是因为,在C++中,人们在大多数情况下不需要一个从多个类中派生的类。
从多个基类中派生一个类这往往会带来许多问题,从而抵消了这种灵活性带来的优势。
C#中,派生类从它的直接基类中继承成员:方法、域、属性、事件、索引指示器。
除了构造函数和析构函数,派生类隐式地继承了直接基类的所有成员。
看下面示例:using System ;class Vehicle //定义交通工具(汽车)类{protected int wheels ; //公有成员:轮子个数protected float weight ; //保护成员:重量public Vehicle( ){;}public Vehicle(int w,float g){wheels = w ;weight = g ;}public void Speak( ){Console.WriteLine( "交通工具的轮子个数是可以变化的! " ) ;}} ;class Car:Vehicle //定义轿车类:从汽车类中继承{int passengers ; //私有成员:乘客数public Car(int w , float g , int p) : base(w, g){wheels = w ;weight = g ;passengers=p ;}}Vehicle 作为基类,体现了"汽车"这个实体具有的公共性质:汽车都有轮子和重量。
Car 类继承了Vehicle 的这些性质,并且添加了自身的特性:可以搭载乘客。
二、C#中的继承符合下列规则:1、继承是可传递的。
如果C从B中派生,B又从A中派生,那么C不仅继承了B中声明的成员,同样也继承了A中的成员。
Object 类作为所有类的基类。
2、派生类应当是对基类的扩展。
派生类可以添加新的成员,但不能除去已经继承的成员的定义。
3、构造函数和析构函数不能被继承。
除此以外的其它成员,不论对它们定义了怎样的访问方式,都能被继承。
基类中成员的访问方式只能决定派生类能否访问它们。
4、派生类如果定义了与继承而来的成员同名的新成员,就可以覆盖已继承的成员。
但这并不以为着派生类删除了这些成员,只是不能再访问这些成员。
5、类可以定义虚方法、虚属性以及虚索引指示器,它的派生类能够重载这些成员,从而实现类可以展示出多态性。
6、派生类只能从一个类中继承,可以通过接口实现多重继承。
下面的代码是一个子类继承父类的例子:using System ;public class ParentClass{public ParentClass( ){ Console.WriteLine("父类构造函数。
"); }public void print( ){ Console.WriteLine("I'm a Parent Class。
") ; }}public class ChildClass : ParentClasspublic ChildClass( ){ Console.WriteLine("子类构造函数。
") ; }public static void Main( ) {ChildClass child = new ChildClass( ) ;child.print( ) ;}}程序运行输出:父类构造函数。
子类构造函数。
I'm a Parent Class。
上面的一个类名为ParentClass,main函数中用到的类名为ChildClass。
要做的是创建一个使用父类ParentClass现有代码的子类ChildClass。
1.首先必须说明ParentClass是ChildClass的基类。
这是通过在ChildClass类中作出如下说明来完成的:"public class ChildClass : ParentClass"。
在派生类标识符后面,用分号":" 来表明后面的标识符是基类。
C#仅支持单一继承。
因此,你只能指定一个基类。
2.ChildClass的功能几乎等同于ParentClass。
因此,也可以说ChildClass "就是" ParentClass。
在ChildClass 的Main( )方法中,调用print( ) 方法的结果,就验证这一点。
该子类并没有自己的print( )方法,它使用了ParentClass中的 print( )方法。
在输出结果中的第三行可以得到验证。
3.基类在派生类初始化之前自动进行初始化。
ParentClass 类的构造函数在ChildClass的构造函数之前执行。
三. 访问与隐藏基类成员(1) 访问基类成员●通过base 关键字访问基类的成员:●调用基类上已被其他方法重写的方法。
●指定创建派生类实例时应调用的基类构造函数。
●基类访问只能在构造函数、实例方法或实例属性访问器中进行。
●从静态方法中使用base 关键字是错误的。
示例:下面程序中基类Person 和派生类Employee 都有一个名为Getinfo 的方法。
通过使用base 关键字,可以从派生类中调用基类上的Getinfo 方法。
using System ;public class Person{protected string ssn = "111-222-333-444" ;protected string name = "张三" ;public virtual void GetInfo() {Console.WriteLine("姓名: {0}", name) ;Console.WriteLine("编号: {0}", ssn) ;}}class Employee: Personpublic string id = "ABC567EFG23267" ;public override void GetInfo() {// 调用基类的GetInfo方法:base.GetInfo();Console.WriteLine("成员ID: {0}", id) ;}}class TestClass {public static void Main() {Employee E = new Employee() ;E.GetInfo() ;}}程序运行输出:姓名: 张三编号: 111-222-333-444成员ID: ABC567EFG23267//默认情况下,派生类从其基类继承属性和方法。
如果继承的属性或方法需要在派生类中有不同的行为,则可以“重写”它,即可以在派生类中定义该属性或方法的新实现,这时,在基类中该属性或方法的声明必须用virtual关键字修饰。
virtual关键字用于指定属性或方法可以在派生类中重写,具有virtual关键字方法或属性被称作虚拟成员。
当实例方法声明包含override修饰符时,该方法为重写方法。
重写方法用相同的签名重写继承的虚拟方法。
示例:派生类同基类进行通信。
using System ;public class Parent{string parentString;public Parent( ){ Console.WriteLine("Parent Constructor.") ; }public Parent(string myString) {parentString = myString;Console.WriteLine(parentString) ;}public void print( ){ Console.WriteLine("I'm a Parent Class.") ; }}public class Child : Parent{public Child( ) : base("From Derived"){ Console.WriteLine("Child Constructor.") ; }public void print( ) {base.print( ) ;Console.WriteLine("I'm a Child Class.") ;}public static void Main( ) {Child child = new Child( ) ;child.print( ) ;((Parent)child).print( ) ;}}程序运行输出:From DerivedChild Constructor.I'm a Parent Class.I'm a Child Class.I'm a Parent Class.说明:1.派生类在初始化的过程中可以同基类进行通信。
上面代码演示了在子类的构造函数定义中是如何实现同基类通信的。
分号":"和关键字base用来调用带有相应参数的基类的构造函数。
输出结果中,第一行表明:基类的构造函数最先被调用,其实在参数是字符串"From Derived"。