C#基于对象的程序设计(二)
在这期教学前,请大家先回顾一下上期C#教程:C#基于对象的程序设计(一)
教学目标:面向对象编程是当前计算机界关心的重点,是软件开发方法的主流。本章通过具体实例讲解面向对象的特性——继承、接口和多态性,学生更加容易理解和掌握面向对象的设计方法和编程特点。
教学重点:继承和多态
教学难点:1. 类的继承
- 多态
什么是面向对象编程?
面向对象编程(Object-Oriented Programming),简称OOP,它是通过给程序中加入扩展语句,把函数封装进编程所必需的“对象“中实现的。面向对象的编程语言,使得复杂的工作条例清晰,编写容易。
- 以事物为中心来思考和认识问题
- 按照这些事物的本质特性把它们抽象为对象
- 对同类型的对象抽象其共性,形成类
- 类通过接口和外界联系
在面向对象程序设计中,包含了对象,类,封装,继承,多态性等概念
面向对象的知识点:
- 类与对象
- 在面向对象中,类是封装数据的基本单位
- 通过类的方法可以访问类中的数据
类:
- 相对对象而言,类似于蓝图
- 包含方法和数据
对象:
- 是类的实例
- 使用关键字 new 创建
- 对象具有行为
类
- 把具有共同性质的事物划分为一类,得出一个抽象的概念
- 类即是具有相同属性和服务的一组对象的集合
- 为属于该类的全部对象提供了抽象的描述,其内部包括属性和行为两个主要部分
对象
- 对象是现实世界中一个实际存在的事物
- 对象具有自己的静态特征和动态特征
- 静态特征用某些数据来描述,动态特征用对象的行为或功能来描述
- 静态特征描述为属性,动态特征描述为行为
类的成员:
- 类中的常量、变量、属性或事件不能与其他类成员同名
- 类中的方法名不能和其他类成员同名
主要包括三种成员:
字段:实例字段,静态字段
访问实例字段,直接用对象名.字段名,访问静态字段,不能用对象的名称,而要用类名,即类名.字段名
属性:get(读取 return),set(编写 value)
方法:方法的定义和调用
方法必须定义在类中,包括方法的名称、返回类型、参数列表、方法体。调用当前类的方法,直接使用方法名称,调用其他类的方法,先要创建类的实例——对象,通过对象名.方法名()来调用。
类的修饰符:
- new : 新建类的实例
- public :公有类,表示外界可以不受限制的访问
- protected :保护类,表示可以访问该类或从该类派生的类
- private :私有类,表示只有该类可以访问
- internal :内部类,表示仅能访问本组件(Application或Library)
- abstract :抽象类,表示该类是一个不完整类,只有声明而没有具体的实现。一般用来做其他类的基类,而不单独使用。也就是说抽象基类不需要实例化
- sealed : 密封类,表示该类不能作为其他类的基类,不能派生新的类,但可由其他类继承而来
面向对象的主要特点:
封装
- 面向对象方法的一个重要原则
- 把对象的全部属性和行为组合起来,形成一个独立单位
- 尽可能的隐蔽对象的内部细节,只保留有限的外部接口与外部联系
继承
- 特殊类的对象拥有一般类的全部属性和行为,即为特殊类对一般类的继承
- 继承对于软件复用有着重要意义
多态性
- 一般类中定义的属性和行为,被特殊类继承之后,可以具有不同数据类型或表现出不同的行为
1. 类的继承
在前面讲过电视的例子,从黑白发展到彩色,又到高清晰,后一代继承了前一代的功能,但是在功能上又有所发展。在面向对象理论中,这就是面向对象的两个重要特征:继承和多态。我们正是通过面向对象的继承性和多态性,开发设计清晰、稳定,易于扩展并且容易维护的软件。
在现有类(称为直接基类)上建立新类(称为派生类)的处理过程即称为继承。在建立新类的过程中,直接基类不作任何改变,派生类继承它的直接基类的成员,而基类的实例构造函数、静态构造函数和析构函数除外。派生类除了继承它的直接基类的成员外,也可以另外定义新成员,以扩展它的直接基类。
继承就是从基类中获取一些公开的成员,如方法和属性。继承的语法如下:
Class Student:Person;//继承类
Class Student:Interface1;//继承接口
C#只允许继承一个基类,但允许继承多个接口。如果子类继承了接口,则必须实现接口中定义的公开成员。所谓公开成员,就时在基类中被定义为public的成员,因为public的作用域可以在子类中生效,而private的作用域则不可。
C#中如何实现继承:
实例:定义Person(基类)
下面我们建立一个Person类,它有三个属性,一个方法,三个私有字段,一个无参数的实例构造函数和一个有三个参数的实例构造函数。
using System; using System.Windows.Forms; class Person { private string id; private string name; private string sex; public Person() {} public Person(string myid,string myname,string mysex) { ID=myid; Name=name; Sex=mysex; } public string Name { get{return name;} set{name=value;} } public string Sex { get{return sex;} set{sex=value;} } public string ID { get{return id;} set{id=value;} } public string PrintPerson() { return string.Format("{0} {1} {2}", ID, Name, Sex); } }
实例:定义Student(1)
定义一个学生类Student类,由于学生属于人,因此学生具有人的属性。前面我们已经定义了一个Person类,要定义学生类,只需以Person类为直接基类定义一派生类。实现人的属性的代码务须重写,直接继承,这样就可大大节约程序的开发时间。缩短程序的开发周期。
using System; using System.Windows.Forms; class Student : Person //指定派生类与直接基类 { private string stuid; private string department; public string Stuid { get { return stuid; } set { stuid = value; } } public string Department { get { return department; } set { department = value; } } public string Printstudent() { return string.Format("{0} {1}", Stuid, Department); } public static void Main() { string output = ""; //创建新的Student对象 Student student1; student1 = new Student(); Student student2 = new Student(); //打印出与此人关联的姓名和年龄 output=student1.PrintPerson()+"\t"; output += student1.Printstudent() + "\n"; //在student1对象上设置一些值 student1.ID = "12569850"; student1.Name = "王飞"; student1.Sex = "男"; student1.Stuid = "0987655"; student1.Department = "计算机"; output = student1.PrintPerson() + "\t"; output += student1.Printstudent() + "\n"; student2.Name = "张翔"; student2.Sex = "女"; student2.ID = "17683608"; student2.Stuid = "1004501"; student2.Department = "应用外语"; output += student2.PrintPerson() + "\t"; output += student2.Printstudent() + "\n"; MessageBox.Show(output, "运行结果"); } }
所有类的基类:object
在.NET Framework中,System.Object是一个特殊的类,它是.NET Framework中所有类的鼻祖。也就是整个类型层次结构的根。每个类不管是.NET Framework提供的,还是自行编写的,都是从System.Object类继承而来的。包括前面的Person类,虽然没有为它指定一个基类,但是编译器会自动把它作为object的派生类。
2. 接口
接口只包含成员的定义,不包含成员的实现。成员是指类中的方法、属性、索引器、事件等。接口的主要目的是为不相关的类提供通用的属性。如C#中的接口“IDbConnection”,用来定义数据源的连接,提供多个未实现的属性和方法,开发者可以自定义两个类“sqlConnection”和“AccessConnection”,并继承IDbConnection接口,那么这两个类就具备相同的成员,但实现内容不同,因为sqlConnection用来连接SQL Server数据库,而AccessConnection用来连接Access数据库。下面代码演示一个简单的接口定义。其中“interface”时定义接口的关键字。
interface Iconnection { Public string DatabaseName; Public string AddDataBase(); Public string GetDataBaseConn(); } 接口就好像一个模板,提供基本成员的结构,但并没有添加实质性的内容。由于C#不能实现多个类的继承,而可以实现多个接口的继承,所以使用接口时可以让一个类具备两个以上基类的唯一方式。
用C#如何创建接口
现在演示用C#创建一个接口,步骤如下:
- 打开应用程序,在解决方案资源管理器中,右击根目录,在弹出的快捷菜单中,依次选择“添加|新建项”菜单命令,打开项模板对话框。
- 选中“接口”模板,默认名称为“cs”,单击“添加”按钮,此时在根目录下生成一个“Interface1.cs”类文件,默认代码如下所示:
using System; using System.Collections.Generic; using System.Text; namespace Interface_eg { interface Interface1 { } }
- 默认生成一个空的接口“Interface1”,设计一个公司员工的接口定义,代码如下所示:
interface Interface1 { public string EmployeeName;//员工姓名 public void AddEmployee();//添加员工 public void DelEmployee();//删除员工 public string EmployeeAddress();//员工住址 }
-
按“Ctrl+S”键保存代码
补充:创建和使用接口
-
创建一项目InerfaceApp
-
声明接口IThing
namespace InerfaceApp { public interface IThing { string Type { get; } string TellAboutSelf(); } }
(3) 实现接口。
using System; using System.Windows.Forms; public class Temperatrue : IThing { protected float m_Value; public Temperatrue() { } public Temperatrue(float f) { m_Value = f; } public float Value { get { return m_Value; } set { m_Value = value; } } public float Celsius { get { return (m_Value - 32) * 5 / 9;} set { m_Value = value * 9.0f / 5 + 32; } } public string Type { get { return "温度"; } } public String TellAboutSelf() { return "华氏温度" + string.Format("{0:n1}", Value) + "摄氏温度" + string.Format("{0:n1}", Celsius); } } public class Manager : IThing { private string name; private decimal salary; private DateTime bornDay; public Manager() { } public Manager(string name, decimal salary, int year, int month, int day) { this.name = name; this.salary = salary; bornDay = new DateTime(year, month, day); } public string Name { get { return name; } set { name = value; } } public decimal Salary { get { return salary ; } set { salary= value; } } public DateTime BornDay { get { return bornDay; } set { bornDay = value; } } public string Type { get { return "经理"; } } public string TellAboutSelf() { return "姓名:" + Name + "出生日期:" + BornDay.ToShortDateString() + "基本工资:" + String.Format("{0:c}", salary); } }
-
添加测试类
namespace InerfaceApp { class InterfaceTest { static string Showinfo(IThing[] b) { String output = ""; for (int i = 0; i < b.Length; i++) { output +="\n"+b [i].Type +":"+b[i].TellAboutSelf ()+"\n"; } return output ; } public static void Main(string[] args) { IThing[] thinges = new IThing[4]; Manager obj1 = new Manager("王菲", 8000.6M, 1970, 6, 15); Manager obj2 = new Manager("李丽", 10000, 1972, 2, 27); Temperatrue obj3 = new Temperatrue(32); Temperatrue obj4 = new Temperatrue(0); thinges[0] = obj1; thinges[1] = obj2; thinges[2] = obj3; thinges[3] = obj4; string output = Showinfo(thinges); MessageBox.Show(output, "输出结果"); } } }
3. 多态
多态是指类可以有多种形态,通过修改可以形成多个方法。当派生类从基类继承时,它会获得基类的所有方法、字段、属性和事件。若要修改父类的数据和行为,通常有两种选择,可以创建新的成员替换基类成员,或者可以重写虚拟的基类成员。
如果要替换基类成员,需要使用new关键字。下面代码演示了GetName方法的两种形态,一种是返回父级名称,一种是返回子级名称。
class ParentClass//父类 { public string GetName() { return "父级名称"; } } class SonClass:ParentClass//子类 { public string GetName() { return "子级名称"; } }
如果要重写虚拟的基类成员,需要两个条件,父级成员使用关键字“virtual”,而子级成员使用关键字“override”。下面演示这种形式下的GetName方法,代码如下所示:
class ParentClass//父类 { public virtual string GetName() { return "父级名称"; } } class SonClass:ParentClass//子类 { public override string GetName() { return "子级名称"; } }
用C#如何实现多态(P70)
使用多态要注意被调用的究竟是哪一种形态。本例通过两个类和一个方法,演示多态的使用,实现步骤如下:
(1)创建类“Employee“,表示公司里的员工。它包含一个虚方法getDepart。代码如下所示:
Class Employee { Public virtual string getDepart () { return “总公司”;} }
(2)创建类“MarketEmployee“,表示市场部员工。它重写了父类的getDepart方法。代码如下:
Class MarketEmployee:Employee { Public override string getDepart () {return “市场部”;} }
(3)下面的代码演示了如何调用这两种形态的方法,注释中还给出了运行结果。
Employee myee=new Employee();//创建父类 String str1=myee.getDepart();//结果为“总公司“ MarketEmployee yee=new MarketEmployee();//创建子类 String str2=yee.getDepart();//结果为“市场部“。
4. 面向对象开发的简单实例
本节以一个非常简单的案例,介绍如何在日常应用开发中采用面向对象技术。
实现步骤:
- 新建一个项目“OOPSample”
- 在解决方案资源管理器的根目录下,添加类“cs”,设计员工的共性。
class Employee { //私有属性的设计 private int _id; private string _name; private int _age; private string _address; public int EmployeeID //员工号 { get { return _id; } set { _id = value; } } public string Name //员工姓名 { get { return _name; } set { _name = value; } } public int Age //员工年龄 { get { return _age; } set { _age = value; } } public string Address //员工地址 { get { return _address; } set { _address = value; } } public void WorkOn() { //上班操作的代码 } public void WorkOff() { //下班操作的代码 } }
(3)在根目录下添加一个类“SaleEmployee.cs”,设计销售部员工的特性。
class SaleEmployee:Employee { private int _salecount; public int SaleCount //销售额 { get { return _salecount; } set { _salecount = value; } } public void Sale() { //销售操作的代码 } } (4)在根目录下添加一个类“BuyEmployee.cs”,设计采购部员工的特性。 class BuyEmployee:Employee { public void Buy() { //采购操作的代码 } }
(5)下面的代码演示如何在应用程序中使用这两个部门的类。
SaleEmployee mysale = new SaleEmployee();//实例化销售部员工类 mysale.Name = "销售员"; mysale.Sale(); //销售操作 mysale.WorkOff(); //下班 label1.Text=mysale.SaleCount.ToString(); //显示此员工的销售额 BuyEmployee mybuy = new BuyEmployee();//实例化采购部员工类 mybuy.Name = "采购员"; mybuy.WorkOn();//上班 mybuy.Buy();//采购
上机实训。
class Boat { private string registrationNo; float length; string manufacturer; int year; public string RegistrationNo { get { return registrationNo; } set { registrationNo = value; } } public float Length { get { return length; } set { length = value; } } public string Manufacturer { get { return manufacturer ; } set {manufacturer = value; } } public int Year { get { return year; } set { year = value; } } public Boat() { } public virtual string ToallString() { return string.Format("{0} {1} {2} {3}", RegistrationNo, Length, Manufacturer, Year); } } class Sailboat : Boat { int keeldepth; string id; string type; public int KeelDepth { get { return keeldepth ; } set { keeldepth = value; } } public string ID { get { return id; } set {id = value; } } public string Type { get { return type ; } set { type = value; } } public Sailboat() { } public override string ToallString() { return string.Format("{0} {1} {2} ", KeelDepth ,ID,Type ); } } class Powerboat : Boat { int numberEngins; string fuletype; public int NumberEngins { get { return numberEngins ; } set { numberEngins = value; } } public string FuleType { get { return fuletype; } set { fuletype = value; } } public Powerboat() { } public override string ToallString() { return string.Format("{0} {1} ", NumberEngins ,FuleType ); } } class Program { static void Main(string[] args) { string output = ""; Sailboat sboat = new Sailboat(); sboat.KeelDepth = 10; sboat.ID = "123"; sboat.Type = "inboard"; output=sboat.ToallString(); MessageBox.Show(output); } }
评论前必须登录!
注册