c#面向对象程序设计.ppt

上传人:牧羊曲112 文档编号:6502431 上传时间:2023-11-07 格式:PPT 页数:175 大小:1.23MB
返回 下载 相关 举报
c#面向对象程序设计.ppt_第1页
第1页 / 共175页
c#面向对象程序设计.ppt_第2页
第2页 / 共175页
c#面向对象程序设计.ppt_第3页
第3页 / 共175页
c#面向对象程序设计.ppt_第4页
第4页 / 共175页
c#面向对象程序设计.ppt_第5页
第5页 / 共175页
点击查看更多>>
资源描述

《c#面向对象程序设计.ppt》由会员分享,可在线阅读,更多相关《c#面向对象程序设计.ppt(175页珍藏版)》请在三一办公上搜索。

1、第4章 面向对象的编程基础,什么是面向对象编程面向对象编程是当前最流行,同时也是技术最成熟,规范最完善的编程理念和技术,相对于传统的面向过程编程方法,面向对象编程具有强大的优势,解决了代码的重用问题,极大提高了开发人员的工作效率。如果一种语言支持面向对象风格的编程,便称其为面向对象编程语言,C#就是支持面向对象编程的语言之一。为什么要使用面向对象编程面向过程的编程方法:模块之间依赖性强,代码重用率低,维护性差。面向对象的编程方法:每个模块用于实现特定的功能,且这些模块之间都是相互独立的。传统的应用程序在执行方式上通常是简单的、线性的,面向对象编程以结构、数据的含义以及数据与数据之间的交互操作为

2、基础,这意味着开发人员需要将更多的精力放在程序的设计阶段,但程序的可扩展性很强。,第4章 面向对象的编程基础,面向对象程序设计的基本概念(1)类和对象 通常把具有同样性质和功能的东西所构成的集合叫作类。(2)属性、方法与事件 属性是对象的状态和特点。方法是对象能够执行的一些操作,它体现了对象的功能。事件是对象能够识别和响应的某些操作。(3)封装 所谓的封装,就是将用来描述客观事物的一组数据和 操作组装在一起,形成一个类。,第4章 面向对象的编程基础,(4)继承 类之间除了有相互交流或访问的关系以外,还可能存在着一种特殊的关系,这就是继承。在Visual C#中只支持单继承,即一个派生类只能有一

3、个基类。(5)重载 重载指的是方法名称一样,但如果参数不同,就会有不同的具体实现。重载主要有两类:方法重载及运算符重载。(6)多态性 所谓多态性就是在程序运行时,面向对象的语言会自动判断对象的派生类型,并调用相应的方法。,4.1 类,4.1.1 类的声明及使用 任何类型都需要先声明,然后才使用。我们能够直接使用int、double和string等基础类型,是因为.NET基础类库中已经声明了他们。一个类一旦被成功声明,就可以当成一种新的类型来使用(引用类型)。,C#中的类声明 格式:类的修饰符 class 类名:基类或接口 类体;类的访问修饰符是可选的,C#中定义了以下几种访问修饰符:inter

4、nal:内部类,表明仅有本程序能够访问该类。public:公有类,表示外界可以不受限制的访问该类。private 私有类,定义在一个类中,在定义它的类中可以访 问它。protected:保护类,表示可以访问该类或从该类派生的类型。(类和它的派生类可以访问该类)abstract:抽象类,只能做其它类的基类。sealed:密封类,该类不能做其他类的基类。类的默认修饰符为internal.class和类名是必需的;基类或接口是可选的,但如果存在,则基类或接口就是必需的;类体是必需的,可以为空。,C#的类名是一种标识符,必须符合标识符的命名规则。类名最好能够体现类的含义和用途。【例4-1】定义一个St

5、udent类,用来对学生的信息和功能进行描述。假设学生具有学号、姓名、年龄、性别、平均成绩等特征。,【例5-1】using System;/引入名称空间public class Student/定义学生类 private string No;/学号 private string Name;/姓名 private int Age;/年龄 private char Sex;/性别 private double Aver;/平均成绩,4.2 类的成员,定义在类体内的元素都是类的成员。类的主要成员包括两种类型,即描述状态的数据成员和描述操作的函数成员。类的数据成员包括:字段(域)常量,例如:下面的Pe

6、rson类定义了两个数据成员Class Person string name;const int age=1;/默认为static属性 此例中,name即为字段成员,age就是常量成员。,类的函数成员包括:方法属性索引器事件运算符构造方法和析构方法,方法(函数)用来实现类执行的计算和操作,使用前必须先定义。方法(函数)具有一个参数列表(可以为空);同时还具有一个返回类型,指定该方法计算和返回的值的类型。如果方法不返回值,则返回值类型为void。此时return可以不写。*一个return只能返回一个值。,例如:Class Person string name;int age=10;void S

7、peak()Console.WriteLine(“Hello World!”);,属性与访问器 属性 属性可以让用户可以象访问公有成员字段一样访问私有成员字段。属性由一个字段声明和存取器组成,存取器指定在它们的值被读取或写入时需执行的语句。,属性声明的格式:【修饰符】【类型】属性名 get【get访问体】set【set访问体】,get 访问器 可以对成员的值进行读操作,get 访问器对应一个不带参数的方法它返回一个和属性相同类型的值。,set 访问器 set访问器可以对成员的值进行操作。通过value隐式参数间接的对私有字段赋值。并且可以包含大量的语句,对赋予的值进行检查,如果值不安全或者不符

8、合要求,就可以进行提示。这样可以避免因为给类的数据成员设置了错误的值而导致的错误。,请看下面的代码:using System;class Rectangle protected int width;protected int height;public int Width get return width;set if(value 0)width=value;else Console.WriteLine(Width的值不能为负数);,public int Height get return height;set if(value 0)height=value;else Console.Writ

9、eLine(Height的值不能为负数);public int Area get return width*height;,public Rectangle()static void Main(string args)Rectangle rect=new Rectangle();rect.Height=2;rect.Width=4;Console.WriteLine(长方形:宽=0,长=1,面积=2,rect.Width,rect.Height,rect.Area);Rectangle rect1=new Rectangle();rect1.Height=-2;rect.Width=-4;Co

10、nsole.WriteLine(长方形:宽=0,长=1,面积=2,rect1.Width,rect1.Height,rect1.Area);,C#中的属性分别通过get和set访问器来对属性的值进行读写。get和set访问器是可选的。get访问器体与方法体相似。它必须返回属性类型的值。执行get访问器相当于读取字段的值。get访问器可以用return语句返回一个属性值。set访问器与返回void的方法类似。它使用称为value的隐式参数,此参数的类型是属性的类型。根据get和set访问器是否存在,属性可分为以下类型:读写属性 只读属性 只写属性,属性与字段的区别:属性可以实现只读或只写,而字段

11、不能属性的set方法可以对用户指定的值(value),进行有效检查,而保证只有正确的状态才能得到设置,而字段不能属性的get方法不仅可以返回字段变量的值,还可以返回经过计算或处理过的数据,如上例中的Area属性属性在实现时,实际上是方法的实现。,在C#中,属性更好地表达了事物的状态的设置与获取。在C#中一般采用以下原则:若在类的内部记录事物的状态信息,则使用字段变量字段变量一般使用private/protected修饰对外公布信息时,则使用属性属性一般与某个或某几个字段变量有对应关系,属性与方法的主要区别:1、属性不必使用括号,但方法一定要使用括号。2、属性不能指定参数,方法可以指定参数。3、

12、属性不能使用void类型,方法可以使用void类型。,构造函数与析构函数,构造方法是名称与类名相同的特殊方法,当类被实例化时,首先执行构造方法;析构方法也是一种特殊的方法,其名称由“”和类名构成,当类的实例被撤销时,执行的方法。,1构造函数 构造函数主要用来为对象分配存储空间,完成初始化操作(如给类的成员变量赋值等)。class 类名 类名(参数表)语句;,在C#中,类的构造函数遵循以下规定。(1)构造函数的函数名和类的名称一样。(2)当某个类没有构造函数时,系统将自动为其创建构 造函数,这种构造函数称为默认构造函数。如果一个类含有构造函数则系统不创建(3)构造函数的访问修饰符总是public

13、。如果是private 则表示这个类不能被实例化,这通常用于只含有静 态成员的类中。(4)构造函数由于不需要显式调用,因而不用声明返回 类型。(5)构造函数可以带参数也可以不带参数。,下面代码说明了构造方法的声明方式:using System;using System.Collections.Generic;using System.Text;namespace 面向对象3 class Dog public string name;public Dog()name=未知;Console.WriteLine(Dog类已经被实例化);public void Bark()Console.WriteL

14、ine(汪汪);static void Main(string args)Dog myDog=new Dog();Console.Write(myDog的名字为0,myDog.name);Console.WriteLine(叫声为);myDog.Bark();Console.ReadKey();,带参数的构造函数 上面例子中的构造函数不带参数,构造函数也可以带有参数.一个类可以有多个具有不同参数的构造函数,根据参数类型和个数的不同来完成不同的功能,这种方式称为构造函数的重载。请看下面代码:,请看下面代码:class Dog public string name;public int age;p

15、ublic Dog()name=未知;age=1;Console.WriteLine(Dog():Dog类已经被实例化);public Dog(string dogName)name=dogName;age=1;Console.WriteLine(Dog(string):Dog类已经被实例化);,析构函数 析构函数在对象销毁时被调用,常用来释放对象占用的存储空间。class 类名 类名()语句;析构函数具有以下特点。(1)析构函数不能带有参数。(2)析构函数不能拥有访问修饰符。(3)不能显式地调用析构函数。(4)析构函数的命名规则是在类名前加上一个 号。(5)析构函数在对象销毁时自动调用。,u

16、sing system;class Exam static public int a;public int b;public Exam()a=0;b=0;public Exam(int m,int n)a=m;b=n;Exam(),using system;Class First()public First()console.writeLine(“Firsts constructor is called”);First()console.writeLine(“Firsts destructor is called”);Class Second()public Second()console.w

17、riteLine(“Seconds constructor is called”);Second()console.writeLine(“Seconds destructor is called”);,Class Third()public Third()console.writeLine(“Thirds constructor is called”);Third()console.writeLine(“Thirds destructor is called”);,Public class MainClass public static void main()First myobject1=n

18、ew First();Second myobject2=new Second();Third myobject3=new Third();,索引器可以让我们把对象当成数组一样访问。事件用于定义可由类生成的通知或者消息,事件会导致相关代码的执行。运算符通过重载,可以扩大运算符的功能。,访问修饰符类成员访问修饰符的意义,访问修饰符都可用于类的成员,当没有定义访问修饰符时,类的成员的默认修饰符为private。下面程序说明了类成员访问修饰符的使用方法,class Vehicle public string model;protected string engine;private string de

19、signer;internal string factory;public void Dive()Console.WriteLine(我喜欢它);,class Manufactor static void Main(string args)Vehicle car=new Vehicle();car.model=ABC123;/能够访问public修饰的成员变量 car.engine=xyz-qe;/不能够访问protected修饰的成员变量 car.designer=Michel Jordon;/*不能够访问 private 修饰的成员变量*/car.factory=FAW;/能够访问inte

20、rnal修饰的成员变量 car.Dive();/能够访问public修饰的成员方法,什么是对象 对象是OOP应用程序的一个组成部件,该部件可以是一个过程、一些数据或者一些更为抽象的实体。C#中的对象是从类型中创建的,就像声明变量一样,对象的类型在C#中被称为“类”。声明类的一个对象称为是该类的实例化,“类的实例”和对象表示相同的含义,但“类”和“对象”却是完全不同的 概念。,面向对象编程,类,对象,对象的生命周期 在每个对象中,或者说在类的每个实例中,至少有一个属性具有状态。对象的状态是指在某一时刻对象中数据成员的值,实际上,每个对象都有一个明确定义的生命周期,除了使用时的正常状态外,还包含两

21、个重要的阶段:构造阶段:对象的初始化过程,由构造函数来完成。析构阶段:对象在被删除时的一些清理工作,如释放内存等,由析构函数来完成。,面向对象编程,对象的声明 类是抽象的,要使用类定义的功能,必须将类实例化,即创建类的对象。创建对象的格式:类名 对象名=new 类名(参数列表);,例如声明Person类的一个对象Mary:Person Mary=new Person();注:创建类的实例、实例化类、声明对象等说法是等价的,都说明以类为模板生成了一个对象的操作,使用new关键字创建一个类的对象同时,也为该对象分配了内存空间,每一个对象都有不同的内存。因此,两个不同的对象,即使它们的所有成员的值和

22、代码都相同,它们也是不相等的。就像同一型号的每一辆车都不一样。,class Dog public string name;public void Bark()Console.WriteLine(汪汪);,class DifferentDog static void Main(string args)Dog myDog=new Dog();myDog.name=豆豆;Dog yourDog=new Dog();yourDog.name=豆豆;/*如果将该句改名yourDog=myDog,那么结果如何?*/Console.WriteLine(我的狗的名字为0,叫声为,myDog.name);myD

23、og.Bark();Console.WriteLine(你的狗的名字为0,叫声为,yourDog.name);yourDog.Bark();if(myDog=yourDog)Console.WriteLine(我的狗和你的狗是同一条狗!);else Console.WriteLine(我的狗和你的狗名字相同,但不是同一条狗!);Console.ReadKey();,静态成员与实例成员 在类的成员的类型前面加上关键字static,就能将该成员定义为静态成员。其他没有用static修饰的成员都是实例成员或称为非静态成员。静态成员属于类,实例成员属于对象(类的实例)。静态成员具有以下特征:静态成员必

24、须通过类名使用.运算符引用,不能用对象名引用 一个静态字段只标识一个存储位置。无论创建多少个该类的实例,它的静态字段在内存中都只占同一块区域 静态函数成员不能作用于具体的实例,必须通过类名来引用,常量也属于静态成员,实例成员具有以下的特点:实例成员必须通过对象名使用.运算符来引用,而不能用类名来引用。类的实例字段属于类的实例所有,每创建一个类的实例,都在内存中为实例字段开辟了一块区域。类的每个实例分别包含一组该类的所有实例字段的副本。实例函数成员作用于类的给定实例。分析下面程序运行结果,using System class Count public static int count=0;pub

25、lic int number=0;public void CountPlus()number=0;count=count+1;number=number+1;class test static void Main(string args)Count a=new Count();a.CountPlus();Console.WriteLine(0,1,a.number,Count.count);a.CountPlus();Console.WriteLine(0,1,a.number,Count.count);Count b=new Count();b.CountPlus();Console.Wri

26、teLine(0,1,b.number,Count.count);,从上面的例子可以看出,类的静态字段count的值是不同的,并且应该使用类名引用;而每个实例的成员字段number的值是相同的,不能被其他实例改变。,this 关键字 this关键字用来引用类的当前实例,成员通过this关键字可以知道自己属于哪一个实例.this关键字只能用在类的构造函数、类的实例方法和实例索引器中,在其他地方使用this关键字是错误的。,索引器 索引器又被称为带参数的属性,索引器可以让我们把对象当成数组一样来方便的使用:【修饰符】【类型】this参数列表 get【get访问器】set【get访问器】,注意:索引

27、器的名称必须是关键字this.this后面一定要跟一对方括号,在方括号之间指定索引 的参数列表,其中至少一个参数。,class Group public const int MaxNum=8;private string member;public string thisint idx get return memberidx;set memberidx=value;public Group()member=new stringMaxNum;,This表示类的实例对象,二、方法 方法又称为函数,是对象或类执行计算或操作的成员。方法是最基本和最主要的函数成员,其他函数成员(属性、索引器、构造函数

28、等)都是以方法为基础来实现的,本质上都是方法。方法用来完成类或对象的行为。方法是类、对象与外界交互的基本方式。,方法声明格式:【修饰符】【数据类型说明符】方法名(形式参数说明列表)变量、数组等的定义语句。其他可执行部分。,说明:方法中可以有参数,也可以没参数,不论有没有参数,小括号是必需的。如果有多个参数,用逗号隔开 如果声明一个void类型的方法,return语句可以省略,如果是一个非void类型方法,则方法中必须有return语句。,方法的调用:方法定义好后,在程序中要完成与方法相同的功能,不需要再编写相应的程序段,而只要调用相应的方法就可以了,方法调用的格式:格式1:方法名(实际参数列表

29、);作用:在类中的某个方法中调用本类中方法 名指定的方法。格式2:对象名.方法名(实际参数列表);功能:调用“对象名”指定的对象的“方法名”指 定的方法,格式3:类名.方法名(实际参数列表);功能:只能调用非本类的另一个类的静太方 法。,静态方法与实例方法 使用static修饰符的方法是静态方法,没有使用static修饰符的方法是实例方法。前面已经介绍过。静态方法是一种特殊的成员方法,不属于类的某一个具体的实例或对象,而属于类本身。实例方法可以使用类的任何成员。调用实例方法时,必须使用类的实例(对象)来引用。下面的程序说明静态方法和实例方法的使用:,class test static void

30、 Main(string args)Program.SetNextSerialNo(1000);Program pp1=new Program();Program pp2=new Program();Console.WriteLine(pp1.GetSerialNo();Console.WriteLine(pp2.GetSerialNo();Console.WriteLine(Program.GetNextSerialNo();,nextSerialNo=1000,对象pp1的serialNo 的值为1000nextSerialNo的值为1001,对象pp2的serialNo的值为1001ne

31、xtSerialNo的值为1002,2.3 方法参数C#提供了四种参数传递方式:值参数:声明时不含任何修饰符引用参数:以ref修饰符声明输出参数:以out修饰符声明参数数组:以params修饰符声明,值参数 定义值类型参数的方式很简单,只要注明参数类型和参数名即可。格式:【修饰符】【数据类型说明符】方法名(类型 形参名,类型 形参名)注意:当该方法被调用时,便会把实参的值复制一份传给形参,形参接收了实参的值后与实参不再有任何联系。在方法中更改形参参数的值不会影响到方法外对应的实参的值(和C语言中的值传递类似)。,using System;class Program static void No

32、tSwap(int x,int y)Console.WriteLine(进入NotSwap时:x=0,y=1,x,y);int temp=x;x=y;y=temp;Console.WriteLine(退出NotSwap时:x=0,y=1,x,y);static void Main(string args)int i=1,j=2;Console.WriteLine(执行NotSwap前:i=0,j=1,i,j);NotSwap(i,j);Console.WriteLine(执行NotSwap后:i=0,j=1,i,j);,引用参数 与传递值类型参数不同,引用类型的参数传递的并不是实参的值,实际上

33、传递的是实参变量的内存地址(指针),即形参和实参保存在同一地址(和C语言中的地址传递类似)。格式:【修饰符】【数据类型说明符】方法名(ref 类型 形参名,ref 类型 形参名),using System;class Program static void NotSwap(ref int x,ref int y)Console.WriteLine(进入NotSwap时:x=0,y=1,x,y);int temp=x;x=y;y=temp;Console.WriteLine(退出NotSwap时:x=0,y=1,x,y);static void Main(string args)int i=1,

34、j=2;Console.WriteLine(执行NotSwap前:i=0,j=1,i,j);NotSwap(ref i,ref j);Console.WriteLine(执行NotSwap后:i=0,j=1,i,j);,传递的是变量i,j的地址,class Program static void NotSwap(out int x,out int y)x=5;y=6;static void Main(string args)int i,j;NotSwap(out i,out j);Console.WriteLine(执行NotSwap后:i=0,j=1,i,j);,class Program

35、static void NotSwap(out int x,out int y)int temp=x;/错误:x,y未被赋值 x=y;y=temp;static void Main(string args)int i=1,j=2;NotSwap(out i,out j);Console.WriteLine(执行NotSwap后:i=0,j=1,i,j);,形参x,y都需要在使用前赋值,参数数组 用params修饰符声明的参数是参数数组,通过参数数组可以向函数传递个数变化的参数。关于参数数组,需掌握以下几点。(1)若形参表中含一个参数数组,则该参数数组必须位于形参 列表的最后;(2)参数数组必须

36、是一维数组;(3)不允许将params修饰符与ref和out修饰符组合起来使用;(4)与参数数组对应的实参可以是同一类型的数组名,也可以是 任意多个与该数组的元素属于同一类型的变量;(5)若实参是数组则按引用传递,若实参是变量或表达式则按值传递。,引用参数,值参数,2.4 方法重载 方法重载是指多个方法,具有同一个方法名,有多种不同的实现方式。这些同名的方法包括从基类继承而来的方法,但每个方法的参数类型或个数不同,从而便于在用户调用方法时系统能够根据参数的类型和个数自动识别应调用的方法。,public static int Add(int i,int j)return i+j;public s

37、tatic string Add(string s1,string s2)return s1+s2;public static long Add(long x)return x+5;static void Main(string args)Console.WriteLine(Add(1,2);Console.WriteLine(Add(ccut,soft);Console.WriteLine(Add(10);,输出i+j的和,2.4 递归 在调用一个方法的过程中,又出现了直接或者间接地调用该方法本身。【例】若干个人排成一个队领苹果,已知第一个人的领的苹果数为1个,从第二个人开始每个人领的苹果数

38、是前一个人领的苹果数的2倍再加3,问第n个人领了多少个苹果?,人的次序 第一个人 第二个人 第n-1个人 第n个人 对应的苹果数 1个 2*1+3 apple(n-1)apple(n)第n个人,一般来说如果某个问题能够用递归来求解,该问题一定能够归结成一个函数公式,如本题求第n个人领的苹果数,用函数apple(n)表示,则本题的apple(n)可描述如下。,第n-1个人的苹果数用apple(n-1)表示,根据条件apple(n)=2*apple(n-1)+3,从程序设计的角度来说,递归过程必须解决两个问题:一是递归计算的公式,二是递归结束的条件。本题递归计算公式:apple(n)=2*appl

39、e(n-1)+3(n1)递归结束条件:apple(1)=1 凡是能够表示成上述式子的数学问题均可以用递归来实现,在递归函数中一般可采用双分支语句来实现:if(递归结束条件)return(递归终止值);else return(递归计算公式);,三、继承与多态 继承性是面向对象语言的重要特性之一,是指类能够从它的父类中继承所有的数据和功能。通过继承,程序员能够直接享用他人或自己事先写好的功能,而不必从头开始、从无到有地编写类。类的继承性增强了代码的可重用性。,构造函数和析构函数不能继承,多态性是指相同的操作或方法可在用于多种类型的对象,并获得不同的结果。如果多个子类继承同一个父类,不同子类的相同的

40、方法可能有不同的表现形式并得到不同的结果。多态性允许每个对象以适合自身的方式去响应相同的消息。多态性是通过继承来实现的。多态性增强了软件的灵活性和重用性,3.1 继承 C#中,作为基础、被继承的类称为基类(Base Class)继承自别的类的子类称为派生类(Derived Class)。继承将生成类之间的层次结构,因此,在定义继承之前,应该首先定义好类之间的层次结构。例如,车类是自行车类的基类,自行车类是车类的派生类。为了表示它们之间的层次关系,可以画出下面的类图,由于子类继承了基类的成员,因此在定义子类之前,应该首先定义好基类。定义基类时,应该在基类中设计所有的派生类都共同具有的数据成员和函

41、数成员。,声明继承类格式:【修饰符】class【类名】:【基类】类体;,车类与自行类之间的类关系如上图,这是VS2005中的类关系图,派生,可以访问继承来的基类中的私有成员,继承可以传递。如果C从B派生,而B从A派生,那么C既继承在B中声明的成员,又继承在A中声明的成员。类不能循环继承。类可以声明虚方法、虚属性等,而派生类可以重写这些函数成员的实现。(多态的一种)派生类可以扩展它的直接基类。派生类能够在基类的基础上添加新的成员,但不能移除基类的成员(构造和析构除外)在派生类中可以声明和基类具有相同名称的成员来隐藏从基类继承而来的成员,隐藏方法 在派生类中,可以使用与基类的成员相同名称的成员,这

42、种情况下,在子类中不能访问基类的同名成员,这叫做派生类成员隐藏了基类的成员。隐藏一个从基类继承而来的成员不算错误,但会导致编译警告。如下例:,明确表示派生类成员是要有意隐藏基类的同名成员,在派生类中隐藏基类的成员并不会移除基类的成员,只是基类的成员在派生类中不可见当在派生类B中声明的一个新成员隐藏了基类A的成员时,只能在新成员的作用范围内隐藏基类的成员。如果新成员为private类型的,那么,在从子类B派生的类C中,C将继承A的成员,而不是B的;如果新成员是public类型的则 C类将继承B中的新成员。如下例:,通过new关键字,3.2 多态 在具有继承关系的类中,不同对象的相同的函数成员可以

43、具有不同的实现,因而会产生不同的执行结果,这就是多态。多态有两种:一种是编译时的多态,也就是指方法的重载;另一种是运行时的多态,通过继承和虚成员来实现的。运行时的多态性是指系统在编译时不确定选用哪个重载方法,而是直到程序运行时,才根据实际情况决定采用哪个重载方法。,隐藏,重写,虚方法与重写方法 如果一个实例方法的声明中含有virtual修饰符,则称该方法为虚方法。若没有virtual修饰符则称该方法为非虚方法。virtual修饰符不允许与static、abstract或者override修饰符同时使用,虚方法不能是私有的,也不能和private修饰符同时使用。如果一个实例方声明中包含overr

44、ide修饰符,则称该方法是重写方法,重写方法用相同的签名(参数个数和类型)重写所继承的虚方法。重写方法只能用于重写基类的虚方法(virtual)。,非虚方法实现是不变的:无论是在声明方法的类的实例中还是在派生类的实例中调用该方法,实现都是相同的。即子类不能改变基类中声明的非虚方法的实现。即使子类隐藏基类的方法,通过基类对象访问的方法依然是基类方法的实现,如下例:,class A public void F()Console.WriteLine(A.F();class B:A new public void F()/隐藏基类的方法 Console.WriteLine(B.F();class Pr

45、ogram static void Main(string args)A a=new A();/基类的对象 B b=new B();/子类的对象 A c=b;/c的编译时类型为A,运行时类型为B a.F();/调用基类A的方法 b.F();/调用子类B的方法 c.F();/调用基类A的方法,可以看出,只要通过声明A的对象(a和c)来引用F(),总会调用类A中定义的方法F(),而不调用B中的F()方法。然而虚方法性质则不同。虚方法的实现可以由派生类中的实现来取代,即被子类的实现重写。,class A public void F()/非虚方法 Console.WriteLine(A.F();pub

46、lic virtual void G()/虚方法 Console.WriteLine(B.G();class B:A new public void F()/隐藏非虚方法 Console.WriteLine(B.F();public override void G()/重写虚方法 Console.WriteLine(B.G();,注意:语句a.G()调用的是B.G(),而不是A.G()。这是因为,对于虚方法而言,确定调用哪个方法的根据是该实例运行时的类型(B),而不是该实例编译时的类型(A)。,在C#中,继承、虚方法和重写方法组合在一起才能实现多态。多态是面向对象编程最具魔力的工具。通过使用多

47、态性,程序在运行时就可以通过声明基类的对象来调用子类中的方法。这样使程序获得极大的灵活性和方便性。例如,可以把一组具有共同基类的对象放到一个数组中,然后通过声明为基类的对象来调用他们的同名方法,这样不同的类的对象就能调用各自的对应方法。,【例】编写一个程序,能够模拟画出圆、三角形、矩形和正方形,类关系图如下:,可以看出,声明为Shape类的数组,根据其运行时类型(运行多态性),正确地调用了各自的画图方法。,抽象类与抽象方法,如果一个类并不与具体的事物相联系,只表达一种 抽象的概念,仅仅为它的派生类提供一个公共的界面,那么这样的类就是抽象类(abstract class)。抽象类是不完整的。格式

48、:【修饰符】abstract class【类名】:【基类或接口】类体;,抽象类与非抽象类区别:抽象类不能被实例化,并且对抽象类使用new运算符会导致编译时错误。允许抽象类包含抽象成员,抽象成员不能是private的。抽象类不能被密封。抽象成员隐含为虚成员,但声明抽象成员时不能使用virtual修饰符,也不能与static同时使用。,抽象类中,当使用abstract修饰符修饰实例方法时,称该方法为抽象方法。抽象方法声明,引入一个新的虚方法,但不提供该方法的实现。当从抽象类派生出一个非抽象类时,需要在非抽象派生类中使用override修饰符重写抽象方法,提供它的实现。下面用抽象类和抽象方法改写上例

49、。,abstract class Shape public abstract void Draw();class Rectangle:Shape public override void Draw()Console.WriteLine(画矩形);class Square:Rectangle public override void Draw()Console.WriteLine(画正方形);,class Triangle:Shape public override void Draw()Console.WriteLine(画三角形);class Circle:Shape public over

50、ride void Draw()Console.WriteLine(画圆);,3.4 密封类与密封方法 如果所有的类都可以被继承,就很容易导致继承的滥用,使类的层次体系结构十分庞大,对类的理解和使用都会变得十分困难。如果一个类已经没有必要被继承,或者这个类不希望被继承,就可以将类声明为密封类(sealed class)。格式:【修饰符】sealed class【类名】:【基类或接口】【类体】,如下的代码定义了一个密封类。sealed class MySealedClass 类成员;密封类不能用作基类。如下代码将产生编译时错误。,sealed class MySealedClass class

展开阅读全文
相关资源
猜你喜欢
相关搜索
资源标签

当前位置:首页 > 生活休闲 > 在线阅读


备案号:宁ICP备20000045号-2

经营许可证:宁B2-20210002

宁公网安备 64010402000987号