配色: 字号:
《C#语言程序设计项目教程》第7章 面向对象编程写字字帖
2023-05-24 | 阅:  转:  |  分享 
  
第7章 面向对象编程本章导读: 本章的主要内容是学习面向对象编程技术。然后通过项目“学生信息表”为导向,九个任务(定义一个简单学生类、为学
生类添加构造函数和析构函数、为学生类创建3个对象、为学生类添加一个方法显示学生信息和学生状态、修改学生类,利用方法访问字段等)为驱
动,学习类和对象、接口等知识,本项目中将学习面向对象程序设计中的基本概念知识和高级技术。第7章 面向对象编程 ——任务一 定义
一个简单学生类 一、任务描述:定义一个学生类。包含学生的姓名、出生日期、年龄等字段。姓名:张三出生日期:1992年2月14日年龄:
12岁二、知识准备:1类的概念2类的声明二、知识准备:1、类的概念类与对象这两个概念是在面向对象程序设计的基本。类是现实世界或思维
世界中的实体在计算机中的反映,它将数据以及这些数据上的操作封装在一起。类是对象的抽象,而对象是类的具体实例。类是抽象的,不占用内存
,而对象是具体的,占用存储空间。类是用于创建对象的蓝图,它是一个定义包括在特定类型的对象中的方法和变量的软件模板。二、知识准备:例
如:如果汽车是一个类,那么大众高尔夫、长安福特等就是对象。汽车的品牌、型号、颜色等就是汽车类的属性,汽车的制造、上色、启动、刹车、
停车等就是汽车类的方法。特种车也可以看做一个类,特种车拥有汽车类的所以属性和方法,但是他还有自己特别的用途,比如它是防弹的,那么我
们就可以说特种车类继承了汽车类。开放人员在进行类的定义时,既包括类的属性,也包括类的方法。1、类的概念二、知识准备:在C#中,使用
class关键字来声明类:语法如下:下面介绍几个常用的类修饰符:public:不能限制对类的访问private:只有.NET中的应
用程序或库才能访问。protected:只能从所在类和所在类的子类进行访问。2、类的声明类修饰符 class 类名{//类体}三、
任务分析:2、如何在项目中添加类。单击【Solution Exploer】,选中项目名称,单击右键选择【Add】|【Class】,
在弹出来的对话框中输入类的名称,单击【OK】,即可在项目中添加一个新类。1、定义学生类需要以下字段,如下表所示:学生类字段声明说明
表四、任务实施:1、启动Visual Studio 2010,建立名为“stuclass”的控制台应用程序。2、声明一个学生类St
udent,为学生类添加3个字段: class Student { public string name;//
姓名 public string birthday;//出生日期 public int age;//年
龄 }五、任务小结:1、字段就是程序开发中常见的变量或常量,是类的一个构成部分,像任务中的name、birthday和age
就是字段。2、声明类的字段时,要对字段添加访问权限修饰符,属性访问权限为public表明该属性可以直接访问。第7章 面向对象编程
——任务二 为学生类添加构造函数和析构函数 一、任务描述:1、添加构造函数。为学生类添加1个不带参数的构造函数,为对象进行默
认初始化。为学生类添加1个带参数的构造函数,通过构造函数的参数对对象进行初始化。2、添加析构函数为学生类添加1个析构函数,输出1句
话表明析构函数被自动调用。二、知识准备:构造函数和析构函数二、知识准备:1、构造函数和析构函数析构函数和构造函数是类中两个比较特殊
的函数,主要用来对对象进行初始化和回收对象资源。在对象被创建时,自动调用构造函数,当对象被销毁时,自动调用析构函数,自动释放这个对
象所占用的内存空间。二、知识准备:(1)构造函数1、构造函数和析构函数(2)析构函数构造函数是在创建对象时自动调用的类方法,该函数
的函数名与类名相同,通常用作对对象进行初始化,一般用public来修饰构造函数。析构函数的函数名与类名相同,只是前面多了一个~符号
,以此通构造函数做区分。.NET类库有垃圾回收功能,当某个类的实例被认为不再有效,.NET类库的垃圾回收功能就会自动调用析构函数实
现垃圾回收。一般情况下不建议定义析构函数,因为C#中无用的对象会由垃圾收集器回收。三、任务分析:为学生类添加1个不带参数的构造函数
,为对象进行默认初始化。1、添加构造函数public Student(){name = "无名氏";birthday = "199
0年1月1日";age = 23;}为学生类添加1个带参数的构造函数,通过构造函数的参数对对象进行初始化。public Stude
nt(string xm, string sr, int nl){ name = xm; sr = birthday;
nl = age; }注意对比三、任务分析:2、添加析构函数~Student() { Con
sole.WriteLine("学生:"+name+"信息删除!"); Console.ReadLine()
; }四、任务实施:1、打开任务一中建立的stuclass控制台应用程序。2、在学生类Student中,为学生类添加
构造函数和析构函数: class Student {//变量定义,字段 public string name;
//姓名 public string birthday;//出生日期 public int age;/
/年龄//构造函数和析构函数public Student() { name = "无名氏";
birthday = "1990年1月1日"; age = 23; }四
、任务实施: public Student(string xm, string sr, int nl) {
name = xm; sr = birthday; nl = age;
} ~Student() { Console.WriteLine("学生:"+n
ame+"信息删除!"); Console.ReadLine(); }}五、任务小结:1、构造
函数在定义时,通常使用public修饰符。2、析构函数一般不需要定义,这里只是为了示范析构函数的作用。第7章 面向对象编程 —
—任务三 为学生类创建3个对象 一、任务描述:为学生类创建3个对象:对象stu1通过直接对其字段赋值来进行初始化。对象stu2通过
不带参数的构造函数进行初始化。对象stu3通过带参数的构造函数进行初始化。二、任务准备:1、对象的声明和初始化对象是面向对象应用程
序的一个重要组成部分,是具有数据、行为和标识的编程结构。对象包含变量成员和方法类型,所包含的变量组成了存储在对象中的数据,其包含的
方法可以访问对象的变量。对象是把类进行实例化。类的实例和对象表示同样的含义。但是“类”和“对象”是两个不同的概念。四、任务实施:1
、打开任务二中建立的stuclass控制台应用程序。2、定义3个对象在Program.cs文件中的static void Main
(string[] args) { } 方法中定义3个对象。四、任务实施:①对象stu1通过直
接对其字段赋值来进行初始化。②对象stu2通过不带参数的构造函数进行初始化。③ 对象stu3通过带参数的构造函数进行初始化。
Student stu1 = new Student(); stu1.name = "李雷"; s
tu1.birthday = "1992年5月1日"; stu1.age = 21; Student st
u2 = new Student();Student stu3 = new Student("李明","1993年3月15日",2
0);2、定义3个对象五、任务小结:1、在声明带参数的对象时,其参数的顺序和类型必须与带参数的构造函数参数列表的顺序和类型一致。2
、类是一种抽象的数据类型,是对同一类事物的共同属性和方法的抽象。对象是类的实例,同一个类可以有多个对象,而一个对象只属于一类。例如
任务三中,学生类有3个学生对象,stu1、stu2和stu3,这3个对象都分别有自己的名字、出生年月和年龄。第7章 选择流程控制
语句 ——任务四 为学生类添加一个方法显示学生信息和学生状态一、任务描述:为任务三的学生类添加如下4个非静态方法1、方法dis
play,其功能是显示学生基本信息。2、方法register,其功能是显示学生正在注册状态。3、方法onschool,其功能是显示
学生正在校学习状态。4、方法graduate,其功能是显示学生已经毕业状态。 在Main方法中利用stu1对象调用这4个方法,运行
结果如图所示:二、任务准备:(1)方法的声明1、方法类的方法主要是和类相关的操作,类似于C语言和C++语言里的函数。方法是类的外部
界面,对于某些私有属性来说,外部界面要实现对它们的操作只能通过方法来实现。方法类似于函数。方法的声明可以包含一组特性和privat
e、public、protected、internal个访问修饰符的任何一个有效组合,还可以包含new、static、virtua
l、override、sealed、abstract以及extern等修饰符。二、任务准备:如果以下所有条件都为“真”,则表明所声
明的方法具有一个有效的修饰符组合。方法的声明格式如下:修饰符 方法名(形参列表){方法主体}1、方法(1)方法的声明二、任务准备:
1、方法(2)方法的分类方法分为静态方法和非静态方法。1)静态方法静态方法通过static修饰符修饰。静态方法不对特定实例进行操作
,在该方法中引用this指针会报错。2)非静态方法非静态方法是对类的某个给定的实例进行操作,该方法可以使用this指针来访问。二、
任务准备:1、方法(3)方法的重载方法的重载是指方法的名字一样,但是方法中的参数个数、类型或顺序不一样。例如任务6.2中我们就定义
了两个构造函数,一个带参数、一个不带参数,这就是构造函数的重载。那么,其方法的重载也是这一个意思。例 定义一个方法add可以实现2
个整数的相加和两个字符串的连接,如图所示。二、任务准备:程序代码如下所示:class Program { pu
blic int add(int a, int b) { return a + b;
} public string add(string str1, string str2) {
return str1 + str2; } static void Main(s
tring[] args) { Program ab = new Program();
Program str = new Program(); Console.WriteLine
("{0}+{1}={2}",2,3,ab.add(2,3)); Console.WriteLine("{0}+{1}={2}",
"C#", "程序设计", str.add("C#", "程序设计")); Console.ReadLin
e(); } }四、任务实施:1、打开任务三中建立的stuclass控制台应用程序。2、为Student类添加
display方法: public void display() { Console.Writ
eLine("姓名:"+name + ",出生日期:"+birthday+",年龄:"+age); } 四、任务实施
:3、为Student类添加register、onschool和graduate方法:public void register()
{ Console.WriteLine(name+"注册中..."); }
public void onschool() { Console.WriteLin
e(name + "在校学习..."); } public void graduate()
{ Console.WriteLine(name + "已经毕业了..."); }四、任务
实施: stu2.display(); stu2.reg
ister(); stu2.onschool(); stu2.graduate();4
、在Main函数中调用display、register、onschool和graduate方法。5、运行程序显示如图所示。1、非静
态方法属于对象,使用对象来引用,方法如下:五、任务小结:2、静态方法属于类,不属于某个实例。请大家修改display为静态方法,在
public前面加上static修饰符,然后运行,会发现编译错误。3、将display方法做如下修改:对象名.方法名(实参列表);
static public void display() { Console.WriteLin
e("显示学生基本信息!"); }在Main函数中直接调用:五、任务小结:然后运行程序,显示如下图所示结果:disp
lay();第7章 面向对象编程 ——任务五 修改学生类,利用方法访问字段 一、任务描述:修改任务四中的字段访问修饰符为p
rivate。然后添加方法来访问name、birthday和age字段。 class Student {public str
ing name;public string birthday;public int age; } class Studen
t {private string name;private string birthday;private int age
; }直接访问通过方法访问二、任务准备:字段是与对象或类相关联的变量,它的作用是用来存储对象属性的值。如果把字段声明为pub
lic,那么在类外面能够访问此字段。在类外访问字段的格式是:对象名.字段名例如任务三中的: stu1.name = "
李雷"; stu1.birthday = "1992年5月1日"; stu1.age = 21;1、字段
三、任务分析://设置字段name的值public void SetName(string xm) {
}因为private字段不能在类体外直接访问,需要通过类的方法,现在为类添加6个方法来为字段进行赋值和取值
:其余4个方法类似。1、字段//获取字段name的值public string GetName() {
}四、任务实施:‘Student.name'' is inaccessible due to its pr
otection level ‘Student.birthday'' is inaccessible due to its prot
ection level‘Student.age'' is inaccessible due to its protection l
evel1、修改字段name、birthday和age的访问修饰符为private。这时运行会出现以下错误:出错原因:这3个字段均
为私有,外部是不能直接访问的。四、任务实施://设置字段name的值public void SetName(string xm)
{ name = xm; }3、对于私有变量,类体外是不能直接访问,需要通过方法
来访问。下面,我们来定义方法来访问Student类的私有变量name。//获取字段name的值public string GetN
ame() { return name; }4、在Main函数中可以通过Set
Name方法为字段name赋值。 stu2.SetName("李雷");四、任务实施://读取birthady方法public v
oid SetBirthday(string sr) { birthday = sr;
}public string GetBirthday() { return birth
day; }5、为其他2个字段birthday和age仿造上述方法添加方法实现访问://读取age方法
public void SetAge(int nl) { age = nl;
} public int GetAge() { return age;
}四、任务实施:stu2.SetName("李雷");stu2.SetBirthday( "1992年5月1日");5、为其
他2个字段birthday和age仿造上述方法添加方法实现访问在Main函数中可以通过SetBirthday和SetAge方法为字
段birthday和age赋值6、编译运行,查看结果,无错误,结果与之前一致。五、任务小结:1、对于private私有变量,在类的
外部不能直接访问,只能通过类的方法来访问。第7章 面向对象编程 ——任务六 利用属性和索引器分别访问存储数据一、任务描述:修
改任务五中的字段读取方法为属性访问器。二、任务准备:属性是对实体特征的描述,比如任务五中的name、birthday和age就是类
Student的属性。属性不表示具体的存储位置,属性具有访问器,这些访问器指定属性的值被写入或读出的执行语句。开发者可以像公共数据
成员一样使用属性。属性的声明格式如下:修饰符 类型 属性名{ get {get访问器体} set {set访问器体}}1、
属性根据有无get和set访问器体,属性分为以下几种:(1)可读可写属性:有get和set访问器体。(2)只读属性:只有get访问
器体。(3)只写属性:只有set访问器体。二、任务准备:索引器通常用来操作数组中的元素。索引器的声明方式与属性很相似,两者之间的区
别在于索引器在声明时需要定义参数。索引器的声明格式如下:修饰符 类型 this[参数列表]{ get {get访问器体} s
et {set访问器体}}2、索引器属性访问器与方法有一样的重要,属性访问器实际上也是方法,但是开发者在使用起来像字段。四、任务
实施://读取name方法public void SetName(string xm) { n
ame = xm; }public string GetName() { ret
urn name; }1、打开任务五中建立的stuclass控制台应用程序,修改字段读取name的方法为属性访问器
:public string Name { set {
name = value; } get {
return name; } }value代表属性值四、任务实施:s
tu2.Name="李雷";2、使用属性访问器Name。属性访问器使用起来像是对字段直接赋值,实际上也是用方法实现。3、为其他2个
字段birthday和age仿造上述方法添加方法实现访问: public int Age {
set { Age = value; }
get { return Age; }
}public int Age { set {
Age = value; } get {
return Age; } }四、任务实施:stu2.Birthady=
"1992年5月1日";stu2.Age = 21;3、为其他2个字段birthday和age仿造上述方法添加方法实现访问在Mai
n函数中可以通过Birthday和Age属性访问器为字段birthday和age赋值:4、编译运行,查看结果,无错误,结果与之前一
致。五、任务小结:1、对于类的属性,可以通过属性访问器来访问。2、属性访问器的类型应该与属性的类型一致。第7章 面向对象编程
——任务七 定义一个newStudent类一、任务描述:定义一个Student类的派生类:newStudent类,该派生类增加一个
属性:专业。并在派生类中重载方法display。定义newStudent类的对象newstu并赋值,调用方法display显示学生
信息。运行如下图所示。二、任务准备:面向对象的三个基本特征是:封装、继承、多态,如图所示。1、面向对象特性二、任务准备:1、面向对
象特性(1)封装封装是面向对象的特征之一,是对象和类概念的主要特性。面向对象编程中,大多都是以封装作为数据封装的基本单位。封装就是
把客观事物封装成抽象的类,类可以把自己的数据和方法只让可信的类或者对象操作,对不可信的进行信息隐藏。封装的目的是增强安全性和简化编
程。类的使用者不需要了解类内部细节,只需要通过外部接口来访问类的成员。二、任务准备:1、面向对象特性(2)继承“继承”是面向对象编
程 (OOP) 语言的一个主要功能。继承是指这样一种能力:它可以使用现有类的所有功能,并在无需重新编写原来的类的情况下对这些功能进
行扩展。任何类都是另外一个类的继承。在面向对象编程中,被继承的类称为基类、父类或超类,通过继承创建的新类称为“子类”或“派生类”。
C#中提供了的类的继承机制,但只支持单继承,不支持多重继承。在考虑使用继承时,有一点需要注意,那就是两个类之间的关系应该是“属于”
关系。例如,Employee 是一个人,Manager 也是一个人,因此这两个类都可以继承 Person 类。但是 Leg 类却不
能继承 Person 类,因为腿并不是一个人。二、任务准备:1、面向对象特性(2)继承继承一个类时,类成员的访问性是一个重要的问题
。在进行类的继承时,要注意对基类成员的访问问题。C#共有五种访问修饰符:public、private、protected、inte
rnal、protected internal,作用范围如下表所示。访问修饰符二、任务准备:1、面向对象特性(3)多态在C#中,类
的多态性是通过在子类(派生类)中重载基类的虚方法或函数成员来实现的。三、任务分析:1、基类中被重载的方法要修饰为虚方法,修饰符为v
itual。2、派生类在进行方法重载时需要加上修饰符override。3、本任务只为说明多态性,对学生类的定义尽量简单。四、任务实
施:class Student { //字段 public string name;
public string birthday; public int age; //方法
public virtual void display() { Console.Wr
iteLine("显示基类对象学生基本信息!"); Console.WriteLine("姓名:"+name
); Console.WriteLine("出生年月:" + birthday); C
onsole.WriteLine("年龄:" + age); } }1、打开VS2010,建立一个控制台
应用程序。2、添加类Student,为类添加display方法来显示学生基本信息:四、任务实施:class newStudent:
Student { public string major;//专业 public overri
de void display() { Console.WriteLine("显示派生
类对象学生基本信息!"); Console.WriteLine("姓名:"+name);
Console.WriteLine("出生年月:" + birthday); Console.Write
Line("年龄:" + age); Console.WriteLine("专业:" + major);
} }3、添加类newStudent,为类多添加1个major字段表示专业,重载display方法来显示派生类对
象的基本信息:overvide关键字四、任务实施:static void Main(string[] args) {
Student stu = new Student();stu.name="李雷";stu.birthday= "1992年5月1
日";stu.age = 21;stu.display(); 4、在Main函数分别定义基类Student和
派生类newStudent的对象并赋值,都调用display方法来显示基本信息:newStudent newstu = new n
ewStudent();newstu.name = "韩梅梅";newstu.birthday = "1993年7月9日";new
stu.major = "软件技术";newstu.age = 20;newstu.display();}调用基类的Display
方法调用派生类的Display方法四、任务实施:5、运行程序,观察结果。可以看出虽然基类和派生类中有同名的display方法,但是
在调用时,基类对象会调用基类的display方法,而派生类会自动调用派生类中重载的display方法,是面向对象程序设计中多态的体
现。五、任务小结:1、基类中被重载的方法要修饰为虚方法,修饰符为vitual。2、派生类在进行方法重载时需要加上修饰符overri
de。第7章 面向对象编程 ——任务八 定义抽象类Person一、任务描述:定义一个抽象类Person,里面包含私有字段姓名n
ame和抽象方法Say。定义一个抽象类Person的派生类Chinese,在派生类Chinese中写抽象方法Say。最后在Main
中实例化派生类Chinese的一个对象。二、任务准备:1、抽象类与抽象方法(1)抽象类访问修饰符 abstract class 类
名:基类或接口{}抽象类主要用来提供多个派生类可共享的基类的公共定义。具体语法格式如下:其中abstract为关键字。抽象类不能被
实例化为具体的对象。二、任务准备:1、抽象类与抽象方法(2)抽象方法public abstract void Say();在方法的
前面加上abstract为关键字就是抽象方法,例如:C#中规定,类中只要有一个方法为abstract修饰的抽象方法,那么这个类就必
须被定义为抽象类。声明抽象方法时,不能使用virtual、statci和private修饰符。抽象方法不提供任何具体实现,需要在非
抽象派生类中重写抽象方法。三、任务分析:1、基类中被重载的方法要修饰为虚方法,修饰符为vitual。2、派生类在进行方法重载时需要
加上修饰符override。3、本任务只为说明多态性,对学生类的定义尽量简单。四、任务实施:public abstract cla
ss Person { private string name;//字段 public string
Name//属性 { get { retu
rn name; } set {
name = value; } } public abstract void
Say(); //抽象方法 }1、打开VS2010,建立一个控制台应用程序。2、定义一个抽象类Person,里面包含私有字段
姓名name和抽象方法Say:抽象方法abstract关键字四、任务实施:public class Chinese : Pers
on { public override void Say() {Console.WriteLi
ne("我的名字是{0},我是中国人!",Name); } }3、定义一个抽象类Person的派生类Chine
se,在派生类Chinese中重写抽象方法Say。四、任务实施:static void Main(string[] args)
{ Chinese Li = new Chinese(); Li.Name
= "李雷"; Li.Say(); Console.ReadLine();
}4、在Main中实例化派生类Chinese的一个对象。派生类对象抽象方法调用四、任务实施:5、运行程序,观察结果。修改Ch
inese Li = new Chinese();为Person Li = new Person();会报错: Cannot cr
eate an instance of the abstract class or interface ''inter.Person
''。表示抽象类或接口不能被实例化。五、任务小结:1、抽象类和抽象方法必须加abstract修饰符,抽象类不能被实例化为具体对象。2
、抽象类中的抽象方法只有声明,没有具体实现。3、从抽象类派生来的派生类必须重写抽象方法,不然会报错。第7章 面向对象编程 ——
任务九 定义接口一、任务描述:本任务主要学习接口的定义,领略接口和抽象类的不同。定义一个接口Flyable,里面有一个方法Fly,
定义一个方法Walkable,里面有一个方法Walk。定义一个类Dog,继承接口Walkable。定义一个类Bird,继承接口Fl
yabl和Walkable。二、任务准备:1、接口接口相当于一种契约,使用接口的开发人员必须严格遵守该接口提出的约定。例如:每个手
机都有一个充电器接口,只要跟这个接口匹配的充电器都可以为这个手机充电。二、任务准备:1、接口(1)接口的声明修饰符 interfa
ce 接口名称:继承的接口列表{接口内容}接口可以包含方法、属性、索引器和事件作为成员,但是不能设置这些成员的具体值。语法格式如下
:其中interface为关键字。接口不能实例化,继承接口的任何非抽象类都必须实现接口的所有成员。类和接口都可以实现多个接口继承。
二、任务准备:1、接口(2)接口的实现接口的名字一般在最前面加上”I”,跟抽象类做区分,通过类继承可以对接口进行实现,一个类可以继
承1个或多个接口。声明实现接口的类时,需要在基类列表中包含所有实现的接口。二、任务准备:1、接口(2)接口的实现如果类实现的两个接
口中包含相同的成员,则在类实现时应该采取显示实现。例如:interface ICal1{ int Add();}interfac
e ICal2{ int Add();}Class CCalculate: ICal1, ICal2{ //用“,“隔开 in
t ICal1.Add( ){int x=10;int y=20;return x+y;} int ICal2.Add( ){
int x=10;int y=20;int z=30;return x+y+z;}}定义接口类继承2个接口三、任务分析:1、定义接
口:IFlyable 和IWalkable。2、类Bird继承自接口:IFlyable 和IWalkable,类Dog继承自接口IWalkable。四、任务实施:interface IFlyable { void Fly(); }1、打开VS2010,建立一个控制台应用程序。2、定义一个接口Flyable,里面有一个方法Fly: 定义一个方法Walkable,里面有一个方法Walk:interface IWalkable { void Walk(); }四、任务实施:3、定义一个类Bird,继承接口Flyabl和Walkable。把鼠标移动到Flyable,单击右键,选择【Implement】|【Implement Interface】,在类中将自动添加对接口中方法的实现,只需要修改代码即可,如下图所示。class Bird : IFlyable,I Walkable { public void Fly() { Console.WriteLine("小鸟在天上飞!"); ; } public void Walk() { Console .WriteLine("小鸟在地上走!"); } } 实现接口方法四、任务实施:class Dog : IWalkable { public void Walk() { Console.WriteLine("小狗在地上跑着走!"); } }4、定义一个类Dog,继承接口IWalkable:实现接口方法四、任务实施:static void Main(string[] args) { Bird littlebird = new Bird(); littlebird.Fly (); littlebird.Walk(); Dog littledog = new Dog(); littledog.Walk(); Console.ReadLine(); }5、在Main中测试类Bird和类Dog:谢谢观看
献花(0)
+1
(本文系小磊老师首藏)