《第4章面向对象编程.ppt》由会员分享,可在线阅读,更多相关《第4章面向对象编程.ppt(77页珍藏版)》请在taowenge.com淘文阁网|工程机械CAD图纸|机械工程制图|CAD装配图下载|SolidWorks_CaTia_CAD_UG_PROE_设计图分享下载上搜索。
1、1第第4章章 C#面向对象编程面向对象编程 面向对象编程是一种功能强大的程序设计方法,它以“数据控制访问代码”为主要原则,围绕数据来组织程序。在进行面向对象编程时需要定义数据和作用于数据上的方法。类是面向对象编程的基础,在类中定义了数据和实现这些数据的代码。2本章学习要点本章学习要点理解类的定义掌握声明类的方法掌握构造函数和析构函数方法理解并掌握访问修饰符的用法掌握类事件的声明以及为类定义事件34.1 基本概念基本概念 类是一个定义对象形式的模版。它指定了数据以及操作数据的代码。C#使用类的规范来构造对象,而对象是类的实例。从定义上来说,类是一个数据结构,包含数据成员(属性、字段)、功能成员(
2、方法、事件、构造函数和析构函数等)和嵌套类型。对象属性颜色价格型号行为起动停车加速属性颜色车轮数量行为行进打铃属性颜色品种行为睡吃 2、类的成员字段:用于保持一个值的成员变量;方法:对数据进行加工的代码,是类中完成一个功能的函数;属性:智能字段,与字段类似,但可以实现只读或只写操作;常量:值不能改变的字段;事件:用于触发一些代码的运行,比如鼠标单击可以触发一些事件;运算:对一些标准的运算符进行重载并添加到类中,可以使代码更直接。4.2 类类是一类对象的抽象,用于在程序中模拟现实生活的事物对象是现实中的事物如何描述现实的事物:特征和动作,对应类中的数据成员和方法4.2.1 定义类访问修饰符 cl
3、ass /类的主体示例:class Employee /类的主体/成员变量/成员方法类修饰符修修饰饰符符说说明明abstract 指定类为其他类的基类sealed指定类不能被继承public所属类的成员以及非所属类的成员都可以访问internal当前程序集可以访问(默默认认)private只有所属类的成员才能访问protected所属类或派生自所属类的类型可以访问语法:语法:成员变量访问修饰符访问修饰符数据类型数据类型成员变量成员变量;privateprotectedinternalpublic_colormodel.priceintchar.bool class Car/汽车的数据成员 pu
4、blic string Color;/颜色public string Model;/型号public float price;/价格 访问成员变量步骤 1:创建一个类的对象Car c=new Car();步骤 2:使用点号访问成员变量c.Color=黑色;/设置汽车c的颜色c.price=1000000;/设置汽车c的价格访问修饰符Car 类private 成员protected 成员public 成员internal 成员Class 类只有 Student 类在 Teacher 类都在同一程序集中,才可访问internal成员不可访问不可访问可以访问static 成员readonly 成员访
5、问修饰符修修饰饰符符说说明明public所属类的成员以及非所属类的成员都可以访问:internal当前程序集可以访问private只有所属类的成员才能访问:protected所属类或派生自所属类的类型可以访问:见static表示属于类型本身而不是属于特定对象readonly只能赋值为该声明的一部分或在同一类的构造函数中注意C#:静态字段在类的装载时初始化;非静态字段在类的实例创建时进行初始化。字段访问class Employeeprivate static string name;private static string id;static void Main(string args)nam
6、e=Console.ReadLine();id=Console.ReadLine();直接访问字段 不经验证 用方法访问字段class Employee private static string name;private static string id;public void SetId(value)/验证输入长度小于 2if(value.Length 2)id=value;public string GetId()returnid;方法 SetId(Value)和 GetId()分别读取和写入职员 ID Employee emp;emp.SetId(A1);string Departme
7、nt=emp.Get()每次都调用 GetId()和 SetId()方法会很繁琐用属性解决!属性class Employee private static string name;private static string id;public string Id get return id;set/验证输入长度小于 2if(id.Length 2)id=value;读取 ID 时调用 将值赋给 ID 时调用 访问修饰符 数据类型 属性名 get;set;读/写属性可以赋值和检索值属性访问修饰符 数据类型 属性名get;只读属性只能检索值属性访问修饰符 数据类型 属性名set;只写属性只能赋值属
8、性访问修饰符static 数据类型 属性名get;set;静态属性应用于整个类而不是类的实例只能访问类的静态成员class SavingsAccount/类字段用于存储类字段用于存储帐号、余额和已获利息帐号、余额和已获利息private int _accountNumber;private double _balance;private double _interestEarned;/利率是静态的,因为所有帐户获得的利息相同利率是静态的,因为所有帐户获得的利息相同private static double _interestRate;/构造函数初始化类成员构造函数初始化类成员public Sa
9、vingsAccount(int accountNumber,double balance)this._accountNumber=accountNumber;this._balance =balance;/只读只读 AccountNumber 属性属性public int AccountNumbergetreturn _accountNumber;定义和调用属性只读属性 static void Main(string args)/创建 SavingsAccount 的对象SavingsAccount objSavingsAccount=new SavingsAccount(12345,500
10、0);Console.WriteLine(输入到现在为止已获得的利息和利率);objSavingsAccount.InterestEarned=Int64.Parse(Console.ReadLine();SavingsAccount.InterestRate=Int64.Parse(Console.ReadLine();objSavingsAccount.InterestEarned+=objSavingsAccount.Balance*SavingsAccount.InterestRate;Console.WriteLine(获得的总利息为:0,objSavingsAccount.Inte
11、restEarned);public double InterestEarnedgetreturn _interestEarned;set/验证数据if(value 0.0)Console.WriteLine(“利息 不能为负数);return;_interestEarned=value;static void Main(string args)/创建 SavingsAccount 的对象SavingsAccount objSavingsAccount=new SavingsAccount(12345,5000);Console.WriteLine(输入到现在为止已获得的利息和利率);objS
12、avingsAccount.InterestEarned=Int64.Parse(Console.ReadLine();SavingsAccount.InterestRate=Int64.Parse(Console.ReadLine();objSavingsAccount.InterestEarned+=objSavingsAccount.Balance*SavingsAccount.InterestRate;Console.WriteLine(获得的总利息为:0,objSavingsAccount.InterestEarned);将设置 InterestRate 属性public stati
13、c double InterestRategetreturn _interestRate;set/验证数据if(value 0.0)Console.WriteLine(“利率不能为负数);return;else_interestRate=value/100;static void Main(string args)/创建 SavingsAccount 的对象SavingsAccount objSavingsAccount=new SavingsAccount(12345,5000);Console.WriteLine(“输入到现在为止已获得的利息和利率);objSavingsAccount.I
14、nterestEarned=Int64.Parse(Console.ReadLine();SavingsAccount.InterestRate=Int64.Parse(Console.ReadLine();objSavingsAccount.InterestEarned+=objSavingsAccount.Balance*SavingsAccount.InterestRate;Console.WriteLine(获得的总利息为:0,objSavingsAccount.InterestEarned);将检索 Balance 和 InterestRate 属性public double Bal
15、ancegetif(_balance 0)Console.WriteLine(没有可用余额);return _balance;4.2.2 方法对象的行为接听响铃挂断PickUp()./接电话Ring()./响铃Hang()./挂断声明方法语法访问修饰符(可选),默认情况下为 private访问修饰符 返回类型(参数列表)/方法主体如果不需要返回任何值,方法可能返回 void 数据类型演示:示例 3调用方法 5private void Accept()Console.WriteLine(请输入复数的实部);_r=int.Parse(Console.ReadLine();Console.Write
16、Line(请输入复数的虚部);_i=int.Parse(Console.ReadLine();/显示复数值void showResult()Console.WriteLine(相加之和);Console.WriteLine(_r+_i+i);/将两个复数相加Complex Add(Complex c)c._r+=this._r;c._i+=this._i;return c;接收实部和虚部的值显示实部和虚部的值请参阅对象的实例变量b与 c 相关联STAThreadstatic void Main(string args)Complex a=new Complex();Complex b=new
17、Complex();a.Accept();b.Accept();Complex e=a.Add(b);e.showResult();Console.ReadLine();4.2.3 方法重载p重载:指允许存在多个同名函数,而这些函数的参数表不同(或许参数个数不同,或许参数类型不同,或许两者都不同)p 作用:对不同数据执行相似的功能p例如:求最大值p注意:p参数表不同:是指参数个数不同或参数类型不同p不能根据返回值不同进行重载在编程中常常需要使用两个或多个函数完成相同的任务,但其参数的数据类型不同。例如,需要使用larger()函数的不同版本,查找出任何基本数据类型的两个变量中的较大者。在理想情
18、况下,所有这些函数都使用相同的名称larger(),另一种方法是为int类型的变量定义函数largerInt()为double类型的变量定义函数largerDouble(),这两个函数的作用是相同的,但却使用不同的名字,看上去很笨拙,不如前一种方法方便。28方法重载2/基于参数不同的方法重载public int greatest(int x,int y)if(xy)return x;else return y;public int greatest(int x,int y,int z)if(xy&xz)return x;else if(yx&yz)return y;else return z;
19、具有不同数量的参数的方法重载方法重载/基于参数类型的方法重载public int greatest(int x,int y)if(xy)return x;else return y;public double greatest(double x,double y)if(xy)return x;else return y;具有不同类型的参数的方法重载4.2.4 构造函数和析构函数构造函数是类的一种特殊方法,一般用于对类的数据成员进行初始化。每次创建类的实例都会调用它。访问修饰符访问修饰符()/构造函数的主体语法:语法:/默认构造函数Car()color=“black;示例:参数化构造函数访问修饰
20、符访问修饰符 ()/构造函数的主体构造函数的主体语法:(参数列表参数列表)/参数化构造函数Car(string str)color=str;示例:构造函数举例(一)using System;class MyClass Myclass()Console.WriteLine(“我的构造函数。”);public static void Main()MyClass cM=new MyClass();new运算符创建类的一个实例。如果没有MyClass方法,则系统产生一个默认构造函数如下:MyClass()构造函数举例(二)using System;class userName string uname
21、;public userName(string name)uname=name;public void ShowName()Console.WriteLine(name);public static void Main()userName un1=new userName(“tony”);un1.ShowName();new运算符创建类的一个实例,并给出参数tony。定义构造方法,将参数赋值给域变量uname。析构函数是用于执行清除操作的特殊方法一个类只能有一个析构函数析构函数不能被继承析构函数不能被显示或手动调用,只能由系统的垃圾回收器自动调用()/析构函数的主体 语法:Car()示例:2、
22、析构函数创建实例时,系统会为实例分配空间,当实例用完以后,就要回收这些分配出去的空间,所以释放对象时要用析构函数。析构方法是用符号“”开始的并与类同名的方法,该方法不带参数,没有返回类型也不带修饰符。一个类的析构方法最多只有一个,如果没有提供析构方法,系统会自动生成一个。析构方法不能由程序显式调用,而由系统自动进行。在.net中,不必太关注内存管理,因为.net框架垃圾回收器会自动地管理对象的内存分配和释放。析构函数举例using System;class First First()Console.WriteLine(“constructor of First”);First()Console
23、.WriteLine(“destructor of First”);public static void Main()First ob=new First();程序运行结果为:constructor of Firstdestructor of First4.3 对象的创建与使用对象首先要进行声明:类名 变量名;创建对象的一般格式如下:变量名=new 构造方法(参数);声明和创建可以合写成一句:类名 变量名=new 构造方法(参数);如:Person p1=new Person(“Jenny”);new是新建对象的运算符,开辟空间并执行相应的构造方法,返回该对象的一个引用(对象实体所在的内存地址
24、)。nameage.p1对象创建举例定义一个Student类,该类由三个域年龄、姓名和性别;为该类编写构造函数,参数为三个:int、string 、string;在主方法中创建一个实例s1,对域进行初始化并输出三个域的值。using System;class Student internal int age;internal string name;internal string sex;public Student(int a,string na,string s)age=a;name=na;sex=s;class App public staitc void Main()Student s
25、1=new Student(23,”zhanghua”,”female”);Console.WriteLine(“0,1,2”,s1.age,s1.name,s1.sex);4.4 类的静态成员类可以有两类成员:静态成员和实例成员。实例成员会被类的每个实例复制;而静态成员只会被复制一次并在整个应用程序的生命周期内都存在。默认情况下,成员被定义为实例成员,如加上staticstatic关键字则被定义为静态成员。*Main()主方法一定是静态的。using System;class Myclass public Myclass()number+;static public int number=1
26、;class App public static void Main()Console.WriteLine(Myclass.number);Myclass m1=new Myclass();Console.WriteLine(Myclass.number);Myclass m2=new Myclass();Console.WriteLine(Myclass.number);程序运行结果为 123如果不是静态成员,只能用m1.number或m2.number,而不能直接用Myclass.number静态成员 实例成员比较程序区程序区数据区静态数据区静态数据区Myclass.number:1动态数
27、据区动态数据区 m1m2程序区程序区数据区静态数据区静态数据区 动态数据区动态数据区 m1:numberm2:number434.5 继承继承 在C#中继承类称为派生类或子类,被继承类称为基类或父类。如果一个派生类继承一个基类,那么这个派生类会从其基类中继承得到所有的操作、属性、特性、事件以及这些内容的实现方法,而基类中实例构造函数、析构函数和表态构造函数不会被继承,同时也不会继承那些显式拒绝访问的成员。继承的意思是一个类可以建立在另一个类的基础上,可以继承另一个类的属性和方法。我们把被继承的类叫做基类,通过继承产生的类叫做派生类(也可以叫做父类和子类)。继承的概念来源与现实的生活,比如汽车、
28、轮船、火车飞机等就是继承于交通工具这个类,而汽车类中又可以派生出新的类,比如轿车、面包车等等。引入继承可以让我们重用以前写过的代码,新编写的代码可以在原来的基础上继承而来。在C#中继承的方式就是定义派生类。在C#中,所有的类都是通过直接或间接地继承Object类得到的。继承一个类时,类成员的可访问性是一个重要的问题。子类(派生类)不能访问基类的私有成员,但是可以访问其公共成员,这就是说,只要使用public声明类成员,就可以让一个类成员被基类和子类(派生类)同时访问,同时也可以被外部的代码访问。为了解决基类成员访问问题,C#还提供了另外一种可访问性:protected,只有子类(派生类)才能访
29、问protected成员,外部代码不能访问protected成员。派生子类定义派生类的基本形式:class 派生类名字:基类名字 派生类的代码;public class Parent public Parent().定义一个构造函数 public void WriteItem().定义方法 public class Child:Parent public Child().派生类的构造函数 public static void Main()Child a=new Child();a.WriteItem();派生类使用基类的方法基类的构造函数先执行再执行派生类的构造函数。继承public clas
30、s Person public string Name;public void WriteInfo()Console.WriteLine(我是人的方法);public class Student:Personpublic string SchoolName;基类 static void Main(string args)Student s=new Student();s.WriteInfo();Console.ReadLine();无需重新编写代码派生类 域的继承、添加与隐藏1、域的继承:子类可以继承父类的所有成员。2、域的添加:在子类定义中加上新的域变量,就可以使得子类具有比父类多的属性。如
31、:class Student:Person string school;int score;子类比父类多了两个成员:school、score。3、域的隐藏:子类重新定义一个从父类中继承的域变量。class A public int a;class B:A new public int a;使用new修饰符来隐藏父类的同名成员a。方法的继承、添加与覆盖1、方法的继承:子类可以继承父类的所有方法。2、方法的添加:在子类定义中加上新的方法,以针对子类实现相应的功能。比如可以在Student类中定义分数的判断方法。3、方法的覆盖:子类定义与父类同名的方法。(多态之一)(1)定义同名但参数列表不同的方法
32、,称为方法的重载;(2)定义同名且参数列表也相同的方法,称为新增,这时应该在同名方法前面用new修饰符;(3)定义同名且参数列表也相同的方法,并且父类中的方法用abstract/virtual进行修饰,子类中的方法用override进行了修饰,称为虚方法的覆盖。virtual用于父类中,声明某方法可以重写,该方法不能是static;override(覆盖继承)(覆盖继承)用于子类中,重写父类中用virtual/override/abstract关键字声明的方法;new(隐藏继承)(隐藏继承)用于子类中,可修饰父类中有或无virtual声明的方法;如果在父类中有与父类同名同参的方法时,C#会隐式
33、在子类前添加一个new关键字。【区别区别】override与与new当将一个子类实例赋值给父类实例,在子类实例与父类实例中分别调用该方法时:使用override修饰的都将调用子类方法,而使用new修饰的会分别调用子类方法和父类方法。方法重载举例class parent public int add(int x,int y)return(x+y);class child:parent public int add(int x,int y,int z)return(x+y+z);public static void Main()child c1=new child();c1.add(1,2,3);
34、c1.add(4,5);分别使用了自己和父类的方法。方法隐藏举例class parent public int add(int x,int y)return(x+y);class child:parent new public int add(int x,int y)return(x+y+10);public static void Main()child c1=new child();c1.add(4,5);使用了自己的方法。虚方法覆盖举例Class one public void x()Console.WriteLine(“one_x”);public virtual void y()Co
35、nsole.WriteLine(“one_y”);Class two:one new public void x()/隐藏父类中的同名方法 Console.WriteLine(“two_x”);public override void y()/重写同名方法 Console.WriteLine(“two_y”);Class test public static void Main()two m2=new m2();one m1=m2;/m1指向m2实例 m1.x();m2.x();m1.y();m2.y();结果:one_x two_x two_y two_yqbaseq用于从派生类中访问基类成
36、员 q可以使用 base 关键字调用基类的构造函数qthisq用于调用本类的数据成员或方法q也可以不写 关键字 base和this1.this关键字this关键字的作用是引用调用方法的当前实例,它可以从构造函数、实例方法和实例访问器中访问成员。用法一:使用this来访问域和方法void sayHello()Console.WriteLine(“My name is”+name);与以下方法相同void sayHello()Console.WriteLine(“My name is”+this.name);用法二:解决局部变量与域同名问题public Student(string name,st
37、ring number)this.name=name;this.number=number;this关键字举例using System;public class Student public string name;public string number;public double subsidy=180;public Student(string name,string number)this.name=name;this.number=number;public void ShowInfo()Console.WriteLine(“0n1”,name,number;Console.Writ
38、eLine(“0”,AdvSubsidy.Caculate(this);public class AdvSubsidy public static double Caculate(student E)return(1.5*(E.subsidy);public class AppMain public static void Main()Student s1=new Student(“zhanghua”,“200454240”);s1.ShowInfo();this的注意事项this指的是调用的“对象”本身(1)通过this不仅可以引用该类中定义的域和方法,还可以引用该类的父类中定义的域和方法;
39、(2)在static静态方法中,不能使用this关键字。base关键字:base指的是父类1)明确指明父类的域和方法,例如,父类Person中有一个域为age,则在子类Student中用age、this.age、base.age来访问age是完全一样的。2)当子类的方法隐藏或覆盖了父类的同名方法但又要调用父类的方法时,使用base关键字。3)想使用父类的构造方法。构造方法是不能继承的,但子类可以在构造方法中调用直接父类的构造方法,如 Student(string name,int age,string school):base(name,age)this.school=school;base(
40、用法2)举例using System;public class A public int a=10;public void m()a+;Console.WriteLine(a);class B:A new public int a=20;new public void m()a+;/base.m();Console.WriteLine(a);public static void Main()A x=new A();Console.WriteLine(x.a);/10 x.m();/11 B y=new B();Console.WriteLine(y.a);/20 y.m();/11 21 如此
41、处直接使用base.m();则最后的结果为12而不是21。构造函数构造函数不能继承在实例化子类对象时,会默认调用父类构造函数如果父类有多个构造函数,子类会默认调用无参的构造函数如果需要调用有参的默认函数,需要显示指明需要使用base关键字调用 base 构造函数 public class Student:Person /调用 Person 构造函数 public Student(string name):base(name)Console.WriteLine(“这是子类的构造函数”);:base 关键字将调用 Person 类构造函数public class Person public Per
42、son()Console.WriteLine(我是人的构造方法);public class Student:Person public Student()Console.WriteLine(我是学生的构造方法);还将调用 Base 构造函数static void Main(string args)Student s=new Student(hehe);Console.ReadLine();4.6 抽象类与接口abstract class Person/类实现抽象类的访问修饰符抽象类不能创建该类的对象,必须使用继承的方法访问抽象类中的成员,即只能被用作继承。若一个类中有一个抽象方法,那该类就是抽
43、象类,必须在类前加abstract。不能实例化public abstract class Personpublic abstract void WriteInfo();public void Work()Console.WriteLine(人正在工作人正在工作);抽象方法抽象方法public class Student:PersonPublic void WriteInfo()Console.WriteLine(我我是学生的方法是学生的方法);抽象类子类提提供供重写方法原型原型必须重写重写 抽象类和抽象方法继承 C#中的类 public class Graduate:Student,Emplo
44、yee /成员变量成员变量 /成员函数成员函数 多重继承 允许多重接口实现接口如果把抽象类中的方法全部变成虚方法,把数据成员全部去掉,抽象类就变成了接口接口的作用是为了提供更高层次的抽象用接口可以实现多继承接口的语法格式:public interface Personvoid WriteInfo();void Work();public interface Personvoid WriteInfo();void Write();隐式声明为 public无访问修饰符接口public class Student:Personpublic void WriteInfo()Console.WriteL
45、ine(我是学生的方法);public void Work()Console.WriteLine(学生正在学习);static void Main(string args)Student s=new Student();s.WriteInfo();派生自 Person接口多重接口实现C#不允许多重类继承但 C#允许多重接口实现 这意味着一个类可以实现多个接口 演示:示例 11public interface Personvoid WriteInfo();void Work();interface Monkeyvoid Climb();public class MonkeyPerson:Monk
46、ey,Personpublic void WriteInfo()Console.WriteLine(我是猿人的方法我是猿人的方法);public void Work()Console.WriteLine(猿人正在打猎猿人正在打猎);public void Climb()Console.WriteLine(猴子在爬树猴子在爬树);static void Main(string args)MonkeyPerson mp=new MonkeyPerson();mp.Work();mp.Climb();Console.ReadLine();显式接口实现在 C#中,只要不发生命名冲突,就完全可以允许多重
47、接口实现public interface Person void work();public interface Monkey void work();public class MonkeyPerson:Monkey,Personvoid Person.Work()Console.WriteLine(我继承与Person接口);void Monkey.Work()Console.WriteLine(我继承与猴子接口);使用显式接口实现显式接口实现static void Main(string args)MonkeyPerson mp=new MonkeyPerson();Person p=mp
48、;p.Work();Monkey m=mp;m.Work();Console.ReadLine();演示:示例 13 public interface Personvoid Work();public interface Monkeyvoid Climb();public interface MonkeyPerson:Monkey,Personvoid Hunter();public class BjMonkeyPerson:MonkeyPersonpublic void Work()Console.WriteLine(我是人的方法);public void Climb()Console.Wr
49、iteLine(我是猴子的方法);public void Hunter()Console.WriteLine(我是猴人的方法);static void Main(string args)BjMonkeyPerson bmp=new BjMonkeyPerson();bmp.Work();bmp.Climb();bmp.Hunter();Console.ReadLine();练习一创建一个student类。字段包括学号(公共权限)、姓名(公共)、年龄(私有)、入学成绩(私有),班级(静态公共,字符串)类型自定。包括一个可读可写的年龄属性(Age)包括一个方法:功能是判断入学成绩,若高于600分则
50、返回true,否则返回false.包括一个静态方法:功能为输出班级内容。然后在Main函数中创建对象,然后用属性为年龄赋值,并调用判断入学成绩的函数,若返回true则显示高分,否则显示正常。最后调用静态方法。74练习二创建一个person类。字段包括身份证号(公共权限)、姓名(公共)、年龄(私有)包括一个方法WriteItem(),功能:输出”你好,父类”定义一个不带参数的构造函数,为字段赋值 定义一个带参数的构造函数,所有字段从参数传递创建一个student从person类继承、增加入学成绩(私有),班级(静态公共,字符串)类型自定。然后在Main函数中创建两个父类对象,分别用不带参数和带参