C#程序设计教程(第3版)李春葆 第6章
合集下载
- 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
- 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
- 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。
class A //基类 { public A() { Console.WriteLine("调用类A的构造函数");} } class B : A //从A派生类B { public B() { Console.WriteLine("调用类B的构造函数"); } } class C:B //从B派生类C { public C() { Console.WriteLine("调用类C的构造函数"); } }
一个类从另一个类派生出来时,称之为派生类或子类, 被派生的类称为基类或父类。 派生类从基类那里继承特性,派生类也可以作为其他 类的基类,从一个基类派生出来的多层类形成了类的层次 结构。
C#中的继承具有以下特点:
C#中只允许单继承,即一个派生类只能有一个基类。 C#中继承是可传递的,如果C从B派生,B从A派生,那么C不仅继承 B的成员,还继承A的成员。 C#中派生类可添加新成员,但不能删除基类的成员。 C#中派生类不能继承基类的构造函数和析构函数,但能继承基类的属 性。 C#中派生类可隐藏基类的同名成员,如果在派生类可以隐藏了基类的 同名成员,基类该成员在派生类中就不能被直接访问,只能通过 “base.基类方法名”来访问。 C#中派生类对象也是基类的对象,但基类对象却不一定是基派生类的 对象。也就是说,基类的引用变量可以引用基派生类对象,而派生类 的引用变量不可以引用基类对象。
2. 重写方法 override方法提供从基类继承的成员的新实现。通过 override声明重写的方法称为重写基方法。重写的基方法 必须与override方法具有相同的签名。
注意:不能重写非虚方法或静态方法。重写的基方
法必须是virtual、abstract或override的。
【例6.3】 分析以下程序的运行结果。
}
6.1.5
使用sealed修饰符来禁止继承
C#中提供了sealed关键字用来禁止继承。要禁止继承 一个类,只需要在声明类时加上sealed关键字就可以了, 这样的类称为密封类。例如:
sealed class 类名 { }
这样就不能从该类派生任何子类。
面向对象程序设计中的多态性是一个重要的概念。 所谓多态性,就是同一签名具有不同的表现行为,运算
B b = new B(); b.afun();
//私有字段 //保护的字段 //公有方法
//私有字段 //公有方法
从中看出Base_fun()方法 在B类中不用重写,因为B 类继承了A类,所以可以 不用重写A类中的 Base_fun()方法,就可以 被B类调用。
在主函数中包含以下代码:
//定义对象并实例化
在主函数中执行以下语句:
C b=new C(); //定义对象并实例化
运行结果如下:
调用类A的构造函数 调用类B的构造函数 调用类C的构造函数
2. 调用默认析构函数的次序
当毁对象时,它会按照相反的顺序来调用析构函数。 首先调用派生类的析构函数,然后是最近基类的析构函数, 最后才调用那个最远的析构函数。
public virtual double Area() { return x * y; }
调用虚方法时,首先调用派生类中的该重写成员,如 果没有派生类重写该成员,则它可能是原始成员。 注意:默认情况下,方法是非虚拟的,不能重写非虚 方法。virtual修饰符不能与static、abstract和override修 饰符一起使用。在静态属性上使用virtual修饰符是错误的。
类的继承的表示
6.1.3
基类成员的可访问性
派生类将获取基类的所有非私有数据和行为。 如果希望在派生类中隐藏某些基类的成员,可以在基类
中将这些成员设为private访问成员。
6.1.4 按次序调用构造函数和析构函数
1. 调用默认构造函数的次序 如果类是从一个基类派生出来的,那么在调用这个 派生类的默认构造函数之前会调用基类的默认构造函数。 调用的次序将从最远的基类开始。
运行结果如下:
B
6.2.2
重 写
重写是指在子类中编写有相同名称和参数的方法。 重写和重载的区别:后者是指编写(在同一个类中) 具有相同的名称,却有不同的参数的方法。也就是说,重 写是指子类中的方法与基类中的方法具有相同的签名,而
重载方法具有不同的签名。
1. virtual关键字 virtual关键字用于修饰方法、属性、索引器或事件声 明,并且允许在派生类中重写这些对象。例如,以下定义 了一个虚拟方法并可被任何继承它的类重写:
using System; namespace proj6_3 { class Student { protected int no; //学号 protected string name; //姓名 protected string tname; //班主任或指导教师 public void setdata(int no1, string name1,string tname1) { no = no1; name = name1;tname=tname1; } public virtual void dispdata() //虚方法 { Console.WriteLine("本科生 学号:{0} 姓名:{1} 班 主 任:{2}", no,name,tname); } }
public class Circle : Rectangle //圆类 { public Circle(double r): base(r, 0) { } public override double Area() //求面积 { return PI * x * x; } } class Sphere : Rectangle //圆球体类 { public Sphere(double r): base(r, 0) {} public override double Area() //求面积 { return 4 * PI * x * x; } } class Cylinder : Rectangle //圆柱体类 { public Cylinder(double r, double h): base(r, h) {} public override double Area() //求面积 { return 2 * PI * x * x + 2 * PI * x * y; } }
class C:B { private int z; public C() { Console.WriteLine("调用类C的构造函数"); } public C(int x1,int y1,int z1):base(x1,y1) { z = z1; Console.WriteLine("调用类C的重载构造函数"); } ~C() { Console.WriteLine("C:z={0}", z); } } class Program { static void Main(string[] args) { C c=new C(1,2,3); } }
class Graduate : Student { public override void dispdata() //重写方法 { Console.WriteLine("研究生 学号:{0} 姓名:{1} 指导教师:{2}", no, name, tname); } } class Program { static void Main(string[] args) { Student s = new Student(); s.setdata(101, "王华","李量"); s.dispdata(); Graduate g = new Graduate(); g.setdata(201,"张华","陈军"); g.dispdata(); } }
符重载和函数重载都属于多态性的表现形式。
6.2.1
隐藏基类方法
当派生类从基类继承时,它会获得基类的所有方法、字
段、属性和事件。若要更改基类的数据和行为,有两种选择:
方法1:使用新的派生成员替换基成员
方法2:重写虚拟的基成员。
方法1示例:在使用新的派生方法替换基方法时应使用 new关键字。例如:
}
【例6.4】 设计一个控制台应用程序,采用虚方法求长方形、 圆、圆球体和圆柱体的面积或表面积。
using System; namespace proj6_4 { public class Rectangle //长方形类 { public const double PI = Math.PI; protected double x, y; public Rectangle() {} public Rectangle(double x1, double y1) { x = x1;y = y1; } public virtual double Area() //求面积 { return x * y; } }
class A //基类 { ~A() { Console.WriteLine("调用类A的析构函数");} } class B : A //从A派生类B { ~B() { Console.WriteLine("调用类B的析构函数"); } } class C:B //从B派生类C { ~C() { Console.WriteLine("调用类C的析构函数"); } }
在主函数中执行语句C b=new C();其运行结果如下:
调用类C的析构函数
调用类B的析构函数
调用类A的析构函数
3. 调用重载构造函数的次序
调用基类的重载构造函数需使用base关键字。base关
键字主要是为派生类调用基类成员提供一个简写的方法, 可以在子类中使用base关键字访问的基类成员。调用基类 中重载构造函数的方法是将派生类的重载构造函数作如下 设计:
6.1.2 派生类的声明
派生类的声明格式如下:
[类修饰符] class 派生类:基类;
C#中派生类可以从它的基类中继承字段、属性、方法、
事件、索引器等。 实际上除了构造函数和析构函数,派生类隐式地继承了 基类的所有成员。
class A { private int n; protected int m; public void afun() { //方法的代码 } } class B : A { private int x; public void bfun() { //方法的代码 } }
public 派生类名(参数列表1):base(参数列表2) { }
其中,“参数列表2”和“参数列表1”存在对应关系。
【例6.1】 分析以下程序的运行结果。
using System; namespace Proj7_1 { class A { private int x; public A() { Console.WriteLine("调用类A的构造函数");} public A(int x1) { x = x1; Console.WriteLine("调用类A的重载构造函数"); } ~A() { Console.WriteLine("A:x={0}", x); } } class B : A { private int y; public B() { Console.WriteLine("调用类B的构造函数"); } public B(int x1,int y1):base(x1) { y = y1; Console.WriteLine("调用类B的重载构造函数"); } ~B() { Console.WriteLine("B:y={0}", y); } }
class A { public void fun() { Console.WriteLine("A"); } } class B:A { new public void fun() //隐藏基类方法fun { Console.WriteLine("B"); } }
在主函数中执行以下语句:
B b=new B(); b.fun();
?c中派生类可隐藏基类的同名成员如果在派生类可以隐藏了基类的同名成员基类该成员在派生类中就不能被直接访问只能通过如果在派生类可以隐藏了基类的同名成员基类该成员在派生类中就不能被直接访问只能通过base
6.1 继 承
6.2 多态性
6.3 抽象类
6.4 接口
6.5 接口在集合排序中的应用
6.1.1什么是继承