第06章继承与多态

上传人:cl****1 文档编号:578823036 上传时间:2024-08-25 格式:PPT 页数:136 大小:631KB
返回 下载 相关 举报
第06章继承与多态_第1页
第1页 / 共136页
第06章继承与多态_第2页
第2页 / 共136页
第06章继承与多态_第3页
第3页 / 共136页
第06章继承与多态_第4页
第4页 / 共136页
第06章继承与多态_第5页
第5页 / 共136页
点击查看更多>>
资源描述

《第06章继承与多态》由会员分享,可在线阅读,更多相关《第06章继承与多态(136页珍藏版)》请在金锄头文库上搜索。

1、第6章 继承与多态6.1 继承简介6.2 基类与派生类6.3 重写与隐藏6.4 引用类型转换6.5 多态与动态绑定6.6 抽象类和抽象方法第6章 继承与多态(续)6.7 密封类、密封方法和静态类6.8 接口6.9 Object类6.10 装箱与拆箱6.11 两个常用.NET框架类型6.12 习题6.1 继承简介继承是软件复用的一种形继承是软件复用的一种形继承是软件复用的一种形继承是软件复用的一种形式。采用这种形式,可吸式。采用这种形式,可吸式。采用这种形式,可吸式。采用这种形式,可吸收现有类的数据和行为,收现有类的数据和行为,收现有类的数据和行为,收现有类的数据和行为,为其赋予新功能,从而创为

2、其赋予新功能,从而创为其赋予新功能,从而创为其赋予新功能,从而创建出新类。软件复用节省建出新类。软件复用节省建出新类。软件复用节省建出新类。软件复用节省了程序开发时间。它还鼓了程序开发时间。它还鼓了程序开发时间。它还鼓了程序开发时间。它还鼓励人们重用经过实践检验励人们重用经过实践检验励人们重用经过实践检验励人们重用经过实践检验和调试的高质量软件,使和调试的高质量软件,使和调试的高质量软件,使和调试的高质量软件,使系统能高效地实现。系统能高效地实现。系统能高效地实现。系统能高效地实现。父类父类子类子类动物动物大象大象猫猫6.1 继承简介(续)继承继承继承继承是从一个类派生出一个新类的过程。是从一

3、个类派生出一个新类的过程。是从一个类派生出一个新类的过程。是从一个类派生出一个新类的过程。通过继承,可以让一个类拥有另一个现有类的通过继承,可以让一个类拥有另一个现有类的通过继承,可以让一个类拥有另一个现有类的通过继承,可以让一个类拥有另一个现有类的全部成员,也即让一个类继承另一个现有类的全部成员,也即让一个类继承另一个现有类的全部成员,也即让一个类继承另一个现有类的全部成员,也即让一个类继承另一个现有类的全部成员。全部成员。全部成员。全部成员。继承的类可以使用另一个现有类的所有功能,继承的类可以使用另一个现有类的所有功能,继承的类可以使用另一个现有类的所有功能,继承的类可以使用另一个现有类的

4、所有功能,并在无需重新编写原来的类的情况下对这些功并在无需重新编写原来的类的情况下对这些功并在无需重新编写原来的类的情况下对这些功并在无需重新编写原来的类的情况下对这些功能进行扩展。能进行扩展。能进行扩展。能进行扩展。 使用继承而产生的类被称为使用继承而产生的类被称为使用继承而产生的类被称为使用继承而产生的类被称为派生类派生类派生类派生类或者子类,或者子类,或者子类,或者子类,而被继承的类则称为而被继承的类则称为而被继承的类则称为而被继承的类则称为基类基类基类基类、超类或父类。、超类或父类。、超类或父类。、超类或父类。6.1 继承简介(续)客观世界中的许多事物之间往往都是具有相同的特客观世界中

5、的许多事物之间往往都是具有相同的特客观世界中的许多事物之间往往都是具有相同的特客观世界中的许多事物之间往往都是具有相同的特征,具有继承的特点。征,具有继承的特点。征,具有继承的特点。征,具有继承的特点。如,一个如,一个如,一个如,一个Rectangle(Rectangle(矩形矩形矩形矩形) )类类类类“ “属于属于属于属于” ”四边形四边形四边形四边形( (正正正正方形、平行四边形和梯形同样是四边形方形、平行四边形和梯形同样是四边形方形、平行四边形和梯形同样是四边形方形、平行四边形和梯形同样是四边形) )。也可以。也可以。也可以。也可以说,说,说,说,Rectangle(Rectangle(

6、矩形类矩形类矩形类矩形类) )是从是从是从是从Quadrilateral(Quadrilateral(四边四边四边四边形形形形) )类继承而来的。类继承而来的。类继承而来的。类继承而来的。 QuadrilateralQuadrilateral类是基类,类是基类,类是基类,类是基类, RectangleRectangle类是派生类。类是派生类。类是派生类。类是派生类。再如,教师类和学生类可以由大学成员类派生,讲再如,教师类和学生类可以由大学成员类派生,讲再如,教师类和学生类可以由大学成员类派生,讲再如,教师类和学生类可以由大学成员类派生,讲师、教授又可以由教师类派生,毕业生和在校生又师、教授又可

7、以由教师类派生,毕业生和在校生又师、教授又可以由教师类派生,毕业生和在校生又师、教授又可以由教师类派生,毕业生和在校生又可以由学生类派生。可以由学生类派生。可以由学生类派生。可以由学生类派生。6.1 继承简介(续)四边形四边形矩形矩形梯形梯形正方形正方形大学成员大学成员教师教师学生学生讲师讲师教授教授在校生在校生毕业生毕业生6.1 继承简介(续)单继承是指从一个基类派生出一个派生类的过单继承是指从一个基类派生出一个派生类的过单继承是指从一个基类派生出一个派生类的过单继承是指从一个基类派生出一个派生类的过程,而多继承是指从一个以上的基类派生出一程,而多继承是指从一个以上的基类派生出一程,而多继承

8、是指从一个以上的基类派生出一程,而多继承是指从一个以上的基类派生出一个派生类的过程。个派生类的过程。个派生类的过程。个派生类的过程。C#C#语言仅支持单继承,其多继承只能通过接口语言仅支持单继承,其多继承只能通过接口语言仅支持单继承,其多继承只能通过接口语言仅支持单继承,其多继承只能通过接口等间接实现。等间接实现。等间接实现。等间接实现。计算机计算机台式机台式机便携机便携机硬盘硬盘输入设备输入设备输出设备输出设备6.2 基类与派生类6.2.1 继承的语法6.2.2 派生类的构造函数6.2.3 结构与继承6.2.1 继承的语法 一般语法如下:一般语法如下:一般语法如下:一般语法如下: 访问权限访

9、问权限访问权限访问权限 classclass派生类名派生类名派生类名派生类名 :基类名:基类名:基类名:基类名 定义派生类新成员定义派生类新成员定义派生类新成员定义派生类新成员 访问权限可以是访问权限可以是访问权限可以是访问权限可以是publicpublic和和和和internalinternal(默认的)(默认的)(默认的)(默认的) 派生类名就是通过继承派生的类的名称派生类名就是通过继承派生的类的名称派生类名就是通过继承派生的类的名称派生类名就是通过继承派生的类的名称 基类名指明了这个派生类的基类基类名指明了这个派生类的基类基类名指明了这个派生类的基类基类名指明了这个派生类的基类 派生时,

10、基类的访问权限不能小于派生类派生时,基类的访问权限不能小于派生类派生时,基类的访问权限不能小于派生类派生时,基类的访问权限不能小于派生类6.2.1 继承的语法(续)例:派生时,基类的访问权限不能小于派生类派生时,基类的访问权限不能小于派生类派生时,基类的访问权限不能小于派生类派生时,基类的访问权限不能小于派生类class Apublic class Bclass C:A/class D:B/public class E:A/public class F:B/正确正确正确错误Class Base / 成员变量 int basevar; / 成员函数 public Base_fun1() / 定义

11、 . .Class Derived : Base / 成员变量 int derivedvars; / 成员函数 Derived_fun1() / 定义 . .基类 void Main() Derived dr_obj = new Derived() ; dr_obj.Base_fun1();无需重新编写代码派生类例6-1 派生类的定义/ /Cat.csCat.csusingusingSystem;System;publicpublic classclass AnimalAnimal privateprivate intintweight;weight;privateprivate intint

12、age;age;publicpublic intintAgeAgegetgetreturnreturnage;age;setsetage=(age=(valuevalue=0)?=0)?valuevalue:0);:0);publicpublic intintWeightWeightgetgetreturnreturnweight;weight;setsetweight=(weight=(valuevalue=0)?=0)?valuevalue:0);:0); 例6-1 派生类的定义(续)publicpublic classclass CatCat:AnimalAnimal publicpub

13、lic voidvoidMeow()Meow()ConsoleConsole.WriteLine(.WriteLine(MeowMeow.); );publicpublic staticstatic voidvoidMain()Main()CatCatc=c=newnew CatCat();();c.Agec.Age=2;=2;/使用基类的公有属性使用基类的公有属性使用基类的公有属性使用基类的公有属性c.Weightc.Weight=5;=5;/使用基类的公有属性使用基类的公有属性使用基类的公有属性使用基类的公有属性ConsoleConsole.WriteLine(.WriteLine(CAT

14、CAT ); );c.Meowc.Meow();();ConsoleConsole.WriteLine(.WriteLine(AgeAge=0,tWeight=1=0,tWeight=1, ,c.Agec.Age, ,c.Weightc.Weight); );6.2.1 继承的语法(续)派生类自动获取基类的派生类自动获取基类的派生类自动获取基类的派生类自动获取基类的除除除除构造函数和析构函数构造函数和析构函数构造函数和析构函数构造函数和析构函数外的所有成员。外的所有成员。外的所有成员。外的所有成员。基类的基类的基类的基类的publicpublic成员被派生类继承后在派生类中成员被派生类继承后在

15、派生类中成员被派生类继承后在派生类中成员被派生类继承后在派生类中可以直接访问,也可以在程序的任何地方通过可以直接访问,也可以在程序的任何地方通过可以直接访问,也可以在程序的任何地方通过可以直接访问,也可以在程序的任何地方通过派生类的对象或派生类名访问;派生类的对象或派生类名访问;派生类的对象或派生类名访问;派生类的对象或派生类名访问;基类的基类的基类的基类的privateprivate成员不能在派生类中访问,也不成员不能在派生类中访问,也不成员不能在派生类中访问,也不成员不能在派生类中访问,也不能通过派生类的对象或派生类名访问;能通过派生类的对象或派生类名访问;能通过派生类的对象或派生类名访问

16、;能通过派生类的对象或派生类名访问;基类的基类的基类的基类的protectedprotected成员只能在基类和派生类中成员只能在基类和派生类中成员只能在基类和派生类中成员只能在基类和派生类中访问,不过在访问,不过在访问,不过在访问,不过在派生类中不能通过基类的对象访派生类中不能通过基类的对象访派生类中不能通过基类的对象访派生类中不能通过基类的对象访问。问。问。问。6.2.1 继承的语法(续)思考题:思考题:using System;class A private int i=0; protected int j=0; public int k=0; protected static int

17、m=0;6.2.1 继承的语法(续)class B:A public void Method() i=0; /1 j=2; /2 k=3; /3 m=4; /4 A a=new A(); a.j=20; /5 B b=new B(); b.j=20; /6 A.m=40; /7 B.m=400; /8 1 1、/ /错误,在所属类外不能访问私有成员错误,在所属类外不能访问私有成员错误,在所属类外不能访问私有成员错误,在所属类外不能访问私有成员2 2、/ /正确,派生类中可以直接访问基类的保护成员正确,派生类中可以直接访问基类的保护成员正确,派生类中可以直接访问基类的保护成员正确,派生类中可以直

18、接访问基类的保护成员3 3、/ /正确,派生类中可以直接访问基类的公共成员正确,派生类中可以直接访问基类的公共成员正确,派生类中可以直接访问基类的公共成员正确,派生类中可以直接访问基类的公共成员4 4、/ /正确,派生类中可以直接访问基类的保护成员正确,派生类中可以直接访问基类的保护成员正确,派生类中可以直接访问基类的保护成员正确,派生类中可以直接访问基类的保护成员5 5、/ /错误,派生类中不能通过基类对象访问基类的保护成员错误,派生类中不能通过基类对象访问基类的保护成员错误,派生类中不能通过基类对象访问基类的保护成员错误,派生类中不能通过基类对象访问基类的保护成员6 6、 / /正确,派生

19、类中可以通过该类对象访问基类的保护成员正确,派生类中可以通过该类对象访问基类的保护成员正确,派生类中可以通过该类对象访问基类的保护成员正确,派生类中可以通过该类对象访问基类的保护成员7 7、 / /正确,派生类中可以通过基类名访问基类的静态保护成员正确,派生类中可以通过基类名访问基类的静态保护成员正确,派生类中可以通过基类名访问基类的静态保护成员正确,派生类中可以通过基类名访问基类的静态保护成员8 8、/ /正确,派生类中可以通过该类的类名访问基类的静态保护成员正确,派生类中可以通过该类的类名访问基类的静态保护成员正确,派生类中可以通过该类的类名访问基类的静态保护成员正确,派生类中可以通过该类

20、的类名访问基类的静态保护成员6.2.1 继承的语法(续)class Test static void Main() B b=new B(); b.i=11; /1 b.j=22; /2 b.k=33; /3 b.Method(); 1、错误,在所属类外不能访问私有成员错误,在所属类外不能访问私有成员2、错误,保护成员只能在所属类及其派生类中访问错误,保护成员只能在所属类及其派生类中访问3、正确,公共成员可以在任何地方访问正确,公共成员可以在任何地方访问6.2.1 继承的语法(续)当派生类与基类的定义在同一程序集时当派生类与基类的定义在同一程序集时当派生类与基类的定义在同一程序集时当派生类与基类

21、的定义在同一程序集时 基类的基类的基类的基类的internalinternal成员和基类的成员和基类的成员和基类的成员和基类的publicpublic成员类似成员类似成员类似成员类似 基类的基类的基类的基类的protectedinternalprotectedinternal成员与基类的成员与基类的成员与基类的成员与基类的protectedprotected成成成成员的类似员的类似员的类似员的类似当派生类与基类的定义不在同一程序集时当派生类与基类的定义不在同一程序集时当派生类与基类的定义不在同一程序集时当派生类与基类的定义不在同一程序集时 基类的基类的基类的基类的internalinterna

22、l成员不能在位于另一个程序集的派生类成员不能在位于另一个程序集的派生类成员不能在位于另一个程序集的派生类成员不能在位于另一个程序集的派生类中访问,也不能通过该派生类的对象或派生类名访问;中访问,也不能通过该派生类的对象或派生类名访问;中访问,也不能通过该派生类的对象或派生类名访问;中访问,也不能通过该派生类的对象或派生类名访问; 基类的基类的基类的基类的protectedinternalprotectedinternal成员只能在所属程序集及所成员只能在所属程序集及所成员只能在所属程序集及所成员只能在所属程序集及所属类的派生类中访问,不能通过位于另一个程序集的属类的派生类中访问,不能通过位于另

23、一个程序集的属类的派生类中访问,不能通过位于另一个程序集的属类的派生类中访问,不能通过位于另一个程序集的派生类对象或派生名在派生类外访问,也不能在位于派生类对象或派生名在派生类外访问,也不能在位于派生类对象或派生名在派生类外访问,也不能在位于派生类对象或派生名在派生类外访问,也不能在位于另一个程序集的派生类中通过基类对象访问。另一个程序集的派生类中通过基类对象访问。另一个程序集的派生类中通过基类对象访问。另一个程序集的派生类中通过基类对象访问。6.2.2 派生类的构造函数派派生生类类不不能能继继承承基基类类的的构构造造函函数数。因因此此,创创建建派派生生类类对对象象时时,为为了了初初始始化化从

24、从基基类类中中继继承承来来的的字字段段,系系统统需需要要调调用用其其基基类类构造函数。构造函数。例6-2 调用基类的默认构造函数源代码运 行/例6-2 调用基类的默认构造函数usingusingSystem;System;publicpublic classclass PeoplePeople publicpublicPeople()People()ConsoleConsole.WriteLine.WriteLine( ( 调用调用调用调用PeoplePeople的构造函数的构造函数的构造函数的构造函数 ); ); publicpublic classclass TeacherTeacher:

25、PeoplePeople publicpublicTeacher()Teacher()ConsoleConsole.WriteLine.WriteLine( ( 调用调用调用调用TeacherTeacher的构造函数的构造函数的构造函数的构造函数 ); ); publicpublic classclass ProfessorProfessor:TeacherTeacher publicpublicProfessor()Professor()ConsoleConsole.WriteLine.WriteLine( ( 调用调用调用调用ProfessorProfessor的构造函数的构造函数的构造函

26、数的构造函数 ); );publicpublic staticstatic voidvoidMain()Main()ProfessorProfessorp=p=newnew ProfessorProfessor();(); 6.2.2 派生类的构造函数(续)C#C#编译器虽然会自动在派生类构造函数中插入对编译器虽然会自动在派生类构造函数中插入对编译器虽然会自动在派生类构造函数中插入对编译器虽然会自动在派生类构造函数中插入对基类构造函数的调用,但它调用的是基类的默认基类构造函数的调用,但它调用的是基类的默认基类构造函数的调用,但它调用的是基类的默认基类构造函数的调用,但它调用的是基类的默认构造函

27、数。构造函数。构造函数。构造函数。如果基类中没有默认构造函数或者希望调用带参如果基类中没有默认构造函数或者希望调用带参如果基类中没有默认构造函数或者希望调用带参如果基类中没有默认构造函数或者希望调用带参数的基类构造函数,就要使用关键字数的基类构造函数,就要使用关键字数的基类构造函数,就要使用关键字数的基类构造函数,就要使用关键字basebase来显式来显式来显式来显式调用基类构造函数。语法如下:调用基类构造函数。语法如下:调用基类构造函数。语法如下:调用基类构造函数。语法如下: basebase( 参数参数参数参数 ); ;例例例例6-3 6-3 6-3 6-3 显式调用基类的构造函数显式调用

28、基类的构造函数显式调用基类的构造函数显式调用基类的构造函数usingSystem;publicclassAirplaneprivateintspeed;publicAirplane(ints)speed=s;Console.WriteLine(调用构造函数调用构造函数Airplane(ints);publicclassWarplane:AirplanepublicWarplane():base(600)Console.WriteLine(调用构造函数调用构造函数Warplane();publicWarplane(ints):base(s)Console.WriteLine(调用构造函数调用构造

29、函数Warplane(ints);publicpublic classclass FighterFighter:WarplaneWarplane publicpublicFighter():Fighter():basebase()()/ /可省略可省略可省略可省略base()base()ConsoleConsole.WriteLine.WriteLine( ( 调用构造函数调用构造函数调用构造函数调用构造函数Fighter()Fighter(); );publicpublic Fighter(Fighter(intints):s):basebase(s(s) )ConsoleConsole.W

30、riteLine.WriteLine( ( 调用构造函数调用构造函数调用构造函数调用构造函数Fighter(intFighter(ints)s); );publicpublic staticstatic voidvoidMain()Main()ConsoleConsole.WriteLine.WriteLine( ( 创建对象:创建对象:创建对象:创建对象:Fighterf1=newFighter()Fighterf1=newFighter(); );FighterFighterf1=f1=newnew FighterFighter();();ConsoleConsole.WriteLine(

31、.WriteLine(nn创建对象:创建对象:创建对象:创建对象:Fighterf2=newFighterf2=newFighter(500)Fighter(500); );FighterFighterf2=f2=newnew FighterFighter(500);(500); 6.2.2 派生类的构造函数(续)使用关键字使用关键字base调用基类构造函数的调用表调用基类构造函数的调用表达式只允许出现在构造函数的函数头之后,达式只允许出现在构造函数的函数头之后,不能出现在函数体内。不能出现在函数体内。例:例:例:例:publicpublicFighter(intFighter(ints)s)

32、 base(sbase(s); );/ /错误错误错误错误Console.WriteLineConsole.WriteLine( ( 调用构造函数调用构造函数调用构造函数调用构造函数Fighter(intFighter(ints)s) ); ); 6.2.2 派生类的构造函数(续)调用基类构造函数时传递的参数不能是关键字调用基类构造函数时传递的参数不能是关键字调用基类构造函数时传递的参数不能是关键字调用基类构造函数时传递的参数不能是关键字thisthis或当前对象的非静态成员,因为此时当前对或当前对象的非静态成员,因为此时当前对或当前对象的非静态成员,因为此时当前对或当前对象的非静态成员,因为

33、此时当前对象还没有创建完成。象还没有创建完成。象还没有创建完成。象还没有创建完成。 例:例:例:例:public class public class public class public class A A A A private private private private intintintint i i i i; ; ; ; public public public public A(A(A(A(intintintint a) i = a; a) i = a; a) i = a; a) i = a; public class public class public class pu

34、blic class B : AB : AB : AB : A private private private private intintintint j j j j; ; ; ; public public public public B():B():B():B(): basebasebasebase(j(j(j(j) ) ) ) /错误错误错误错误 j = 10; j = 10; j = 10; j = 10; 6.2.3 结构与继承结构不支持继承结构不支持继承,但可以实现接口。,但可以实现接口。所有的结构都是隐式从所有的结构都是隐式从ValueType类直接类直接或间接派生出来的,而或

35、间接派生出来的,而ValueType类又是类又是从从Object类派生出来的。但类派生出来的。但C#C#语言不允语言不允许程序员声明一个继承于结构的类,也不许程序员声明一个继承于结构的类,也不允许声明一个继承于结构的结构或继承于允许声明一个继承于结构的结构或继承于类的结构。类的结构。 结构成员不能用结构成员不能用protectedinternal和和protected修饰。修饰。6.3 重写与隐藏派生时,如果某个基类成员不能满足派生类的需派生时,如果某个基类成员不能满足派生类的需派生时,如果某个基类成员不能满足派生类的需派生时,如果某个基类成员不能满足派生类的需要,可以在派生类中改写。要,可以

36、在派生类中改写。要,可以在派生类中改写。要,可以在派生类中改写。C#C#语言中,基类成员语言中,基类成员语言中,基类成员语言中,基类成员的改写有重写与隐藏两种方式。的改写有重写与隐藏两种方式。的改写有重写与隐藏两种方式。的改写有重写与隐藏两种方式。6.3.1重写基类成员重写基类成员6.3.2隐藏基类成员隐藏基类成员 6.3.1 重写基类成员只有虚拟方法成员可以重写。只有虚拟方法成员可以重写。要将某个方法显式声明为虚拟方法需要使要将某个方法显式声明为虚拟方法需要使用关键字用关键字virtual,而要重写某个虚拟方法,而要重写某个虚拟方法则必须使用关键字则必须使用关键字override显式声明。显

37、式声明。方法重写时,派生类中的方法应该与基类方法重写时,派生类中的方法应该与基类中被重写的方法有相同的中被重写的方法有相同的方法名方法名、返回值返回值类型类型、参数列表参数列表和和访问权限访问权限。6.3.1 重写基类成员(续)如果某个类中的一个方法是其基类的重写方法,那如果某个类中的一个方法是其基类的重写方法,那如果某个类中的一个方法是其基类的重写方法,那如果某个类中的一个方法是其基类的重写方法,那么该方法也就隐式成为一个虚拟方法(该方法不能么该方法也就隐式成为一个虚拟方法(该方法不能么该方法也就隐式成为一个虚拟方法(该方法不能么该方法也就隐式成为一个虚拟方法(该方法不能使用关键字使用关键字

38、使用关键字使用关键字 virtualvirtual显式声明)显式声明)显式声明)显式声明)。例:例:例:例:classAclassA publicvirtualvoidMethod()publicvirtualvoidMethod() classB:AclassB:A publicoverridevoidMethod()publicoverridevoidMethod()/ /隐式成为一个虚拟方法隐式成为一个虚拟方法隐式成为一个虚拟方法隐式成为一个虚拟方法 classC:BclassC:B publicoverridevoidMethod()publicoverridevoidMethod()

39、 6.3.1 重写基类成员(续)派生类无法调用基类的私有方法,也就没有所派生类无法调用基类的私有方法,也就没有所派生类无法调用基类的私有方法,也就没有所派生类无法调用基类的私有方法,也就没有所谓的派生类对基类私有方法的重写,因此,类谓的派生类对基类私有方法的重写,因此,类谓的派生类对基类私有方法的重写,因此,类谓的派生类对基类私有方法的重写,因此,类的私有方法不能声明为虚拟的。的私有方法不能声明为虚拟的。的私有方法不能声明为虚拟的。的私有方法不能声明为虚拟的。类的静态方法不能声明为虚拟的。类的静态方法不能声明为虚拟的。类的静态方法不能声明为虚拟的。类的静态方法不能声明为虚拟的。例例例例6-4

40、6-4 6-4 6-4 重写虚拟方法重写虚拟方法重写虚拟方法重写虚拟方法/TestOverride.csusingSystem;publicclassAprivateinti;publicvirtualintI/虚拟方法虚拟方法getreturni;seti=value;publicvirtualvoidMethod()/虚拟方法虚拟方法Console.WriteLine(Method()inA);Console.WriteLine(i=0,i);publicvirtualvoidMethod(inti)/虚拟方法虚拟方法Console.WriteLine(Method(inti)inA);C

41、onsole.WriteLine(i=0,i);publicpublic classclass B B: :A A privateprivate intinti;i;publicpublic overrideoverride intintI I/ /重写方法重写方法重写方法重写方法 getget returnreturni;i; setset i=i=valuevalue; ; publicpublic overrideoverride voidvoidMethod()Method()/ /重写方法重写方法重写方法重写方法 ConsoleConsole.WriteLine(.WriteLine

42、(MethodMethod()inB()inB); );ConsoleConsole.WriteLine(.WriteLine(i i=0=0,i);,i); publicvoidPrint()base.I=10;/使用基类的属性使用基类的属性I=20;base.Method();/调用基类的方法调用基类的方法Method();base.Method(30);/调用基类的方法调用基类的方法Method(30);publicstaticvoidMain()Bb=newB();b.Print();6.3.2 隐藏基类成员 如如如如果果果果没没没没有有有有使使使使用用用用关关关关键键键键字字字字ov

43、erridieoverridie,只只只只是是是是在在在在派派派派生生生生类类类类中中中中定定定定义义义义一一一一个个个个与与与与基基基基类类类类同同同同名名名名的的的的方方方方法法法法,派派派派生生生生类类类类中中中中的的的的方方方方法法法法将将将将隐隐隐隐藏藏藏藏基基基基类类类类的中的同名方法。的中的同名方法。的中的同名方法。的中的同名方法。例:public class A public virtual void Method()/ public void Method()Console.WriteLine(“Method() in A”);public class B:A public

44、void Method()Console.WriteLine(“Method() in B”);编译器会给出警告信息编译器会给出警告信息编译器会给出警告信息编译器会给出警告信息. .6.3.2 隐藏基类成员 成成员员隐隐藏藏并并不不局局限限于于方方法法成成员员,它它也也能能用于数据成员和内部数据类型。用于数据成员和内部数据类型。使使用用关关键键字字new隐隐藏藏基基类类成成员员时时并并不不要要求求基基类类中中的的成成员员是是虚虚拟拟的的。它它通通常常用用于于改写基类中的非虚拟方法改写基类中的非虚拟方法。例6-5 隐藏基类成员 源代码运 行例6-5 隐藏基类成员/TestNew.csusingS

45、ystem;publicclassApublicintI;publicvoidMethod()Console.WriteLine(Method()inA);Console.WriteLine(I=0,I);publicclassB:ApublicnewintI;/使用关键字使用关键字new隐藏基类成员隐藏基类成员publicnewvoidMethod()/使用关键字使用关键字new隐藏基类成员隐藏基类成员Console.WriteLine(Method()inB);Console.WriteLine(I=0,I);publicvoidPrint()base.I=10;I=20;base.Met

46、hod();Method();publicstaticvoidMain()Bb=newB();b.Print();6.3.2 隐藏基类成员(续)关键字关键字base代表的是当前派生类对象中代表的是当前派生类对象中的基类子对象,因此,通过它可以访问基的基类子对象,因此,通过它可以访问基类成员。不过,与关键字类成员。不过,与关键字this相同,关键相同,关键字字base只能用在实例方法中。只能用在实例方法中。6.4 引用类型转换一个类的对象在一定条件下可以转换成一个类的对象在一定条件下可以转换成继承链中的另一个类的对象:继承链中的另一个类的对象:一个派生类对象的类型可以向上转换成它的一个派生类对象

47、的类型可以向上转换成它的一个派生类对象的类型可以向上转换成它的一个派生类对象的类型可以向上转换成它的基类类型,这种转换是安全的,基类类型,这种转换是安全的,基类类型,这种转换是安全的,基类类型,这种转换是安全的,C#C#编译器编译器编译器编译器能隐式进行。能隐式进行。能隐式进行。能隐式进行。一个基类对象的类型一般不能向下转换成它一个基类对象的类型一般不能向下转换成它一个基类对象的类型一般不能向下转换成它一个基类对象的类型一般不能向下转换成它的派生类类型。但有一种情况除外,如果一的派生类类型。但有一种情况除外,如果一的派生类类型。但有一种情况除外,如果一的派生类类型。但有一种情况除外,如果一个基

48、类个基类个基类个基类对象引用对象引用对象引用对象引用实际引用的是一个派生类对实际引用的是一个派生类对实际引用的是一个派生类对实际引用的是一个派生类对象,就可以使用显式转换将这个基类对象转象,就可以使用显式转换将这个基类对象转象,就可以使用显式转换将这个基类对象转象,就可以使用显式转换将这个基类对象转换成派生类类型。换成派生类类型。换成派生类类型。换成派生类类型。6.4 引用类型转换(续) 显式引用类型转换的一般语法形式与数值类型相同。显式引用类型转换的一般语法形式与数值类型相同。显式引用类型转换的一般语法形式与数值类型相同。显式引用类型转换的一般语法形式与数值类型相同。例:例:例:例:clas

49、sAclassAclassB:AclassB:AclassC:BclassC:BAa1=newB();Aa1=newB(); / /隐式转换隐式转换隐式转换隐式转换Aa2=newC();Aa2=newC(); / /隐式转换隐式转换隐式转换隐式转换Bb1=(B)a1;Bb1=(B)a1; / /显式转换显式转换显式转换显式转换Bb2=(B)a2;Bb2=(B)a2;/ /显式转换显式转换显式转换显式转换Cc1=(C)a1;Cc1=(C)a1;/ /错误,不能转换,否则引发异常错误,不能转换,否则引发异常错误,不能转换,否则引发异常错误,不能转换,否则引发异常Cc2=(C)a2;Cc2=(C)a

50、2;/ /显式转换显式转换显式转换显式转换 6.4 引用类型转换(续)将一个基类对象的类型转换成它的派生类将一个基类对象的类型转换成它的派生类类型时,必须确保其引用实际引用是该派类型时,必须确保其引用实际引用是该派生类的一个对象,否则会引发异常。为了生类的一个对象,否则会引发异常。为了防止这种情况发生,可以使用运算符防止这种情况发生,可以使用运算符is或或as。6.4 引用类型转换(续) 运算符运算符运算符运算符isis的作用是检查某个表达式值的实际类型是否的作用是检查某个表达式值的实际类型是否的作用是检查某个表达式值的实际类型是否的作用是检查某个表达式值的实际类型是否是某个指定的值类型、引用

51、类型,或者派生于某个指是某个指定的值类型、引用类型,或者派生于某个指是某个指定的值类型、引用类型,或者派生于某个指是某个指定的值类型、引用类型,或者派生于某个指定的类、实现了某个指定的接口,又或者由某个指定定的类、实现了某个指定的接口,又或者由某个指定定的类、实现了某个指定的接口,又或者由某个指定定的类、实现了某个指定的接口,又或者由某个指定值类型装箱而来。如果是,且该对象不为值类型装箱而来。如果是,且该对象不为值类型装箱而来。如果是,且该对象不为值类型装箱而来。如果是,且该对象不为nullnull,则返回,则返回,则返回,则返回truetrue,否则返回,否则返回,否则返回,否则返回fals

52、efalse。其语法形式如下:。其语法形式如下:。其语法形式如下:。其语法形式如下:表达式表达式表达式表达式isis数据类型数据类型数据类型数据类型例:例:例:例:b1 is Ab1 is A/true/truea1 is B a1 is B /true/truea1 is Ca1 is C/false/false5is5isintint/true/true6.4 引用类型转换(续)使用运算符使用运算符使用运算符使用运算符asas可以将某个可以将某个可以将某个可以将某个表达式的值转换成指表达式的值转换成指表达式的值转换成指表达式的值转换成指定的引用类型定的引用类型定的引用类型定的引用类型,而且

53、转换时,自动完成运算符,而且转换时,自动完成运算符,而且转换时,自动完成运算符,而且转换时,自动完成运算符isis所作的检查。如果运算符所作的检查。如果运算符所作的检查。如果运算符所作的检查。如果运算符asas检测到不能进行转检测到不能进行转检测到不能进行转检测到不能进行转换,表达式的结果就为换,表达式的结果就为换,表达式的结果就为换,表达式的结果就为nullnull,不会引发异常。,不会引发异常。,不会引发异常。,不会引发异常。其其其其语法形式如下:语法形式如下:语法形式如下:语法形式如下:表达式表达式表达式表达式 asas数据类型数据类型数据类型数据类型运算符运算符运算符运算符asas不能

54、不能不能不能用于将某个表达式的值转换为值用于将某个表达式的值转换为值用于将某个表达式的值转换为值用于将某个表达式的值转换为值类型。类型。类型。类型。例:例:例:例:C c1=a1 as C;C c1=a1 as C; / /正确正确正确正确intint i= 2.4 as i= 2.4 as intint; ;/ /错误错误错误错误例6-6 引用类型转换/ /TestObjectCast.csTestObjectCast.cs usingusingSystem;System;classclass AirplaneAirplane privateprivate intintspeed=500;s

55、peed=500;publicpublic intintSpeedSpeedgetgetreturnreturnspeed;speed;setsetspeed=speed=valuevalue; classclass WarplaneWarplane:AirplaneAirplane privateprivate intint missileNumbermissileNumber=8;=8;publicpublic intint MissileNumberMissileNumbergetgetreturnreturn missileNumbermissileNumber;setsetmissi

56、leNumbermissileNumber=valuevalue; classclass FighterFighter:WarplaneWarplane publicpublic voidvoidPrint()Print()ConsoleConsole.WriteLine(.WriteLine(ItItisafighter!isafighter!); ); classclass TestObjectCastTestObjectCast publicpublic staticstatic voidvoidMain()Main()AirplaneAirplanep1=p1=newnew Warpl

57、aneWarplane();();AirplaneAirplanep2=p2=newnew FighterFighter();();WarplaneWarplanew1,w2;w1,w2;FighterFighterf1,f2;f1,f2;p2.Speed=600;p2.Speed=600;if if(p1(p1isis WarplaneWarplane) )ConsoleConsole.WriteLine(.WriteLine(p1p1引用的是一个引用的是一个引用的是一个引用的是一个WarplaneWarplane对象对象对象对象 ); );w1=(w1=(WarplaneWarplane)

58、p1;)p1;ConsoleConsole.WriteLine(.WriteLine(w1.speed=0tw1.missileNumber=w1.speed=0tw1.missileNumber=1n1n,w1.Speed,w1.MissileNumber);,w1.Speed,w1.MissileNumber);elseelseConsoleConsole.WriteLine(.WriteLine(p1p1引用的不是一个引用的不是一个引用的不是一个引用的不是一个WarplaneWarplane对象对象对象对象nn); );if if(p2(p2isis WarplaneWarplane)

59、)ConsoleConsole.WriteLine(.WriteLine(p2p2引用的是一个引用的是一个引用的是一个引用的是一个WarplaneWarplane对象对象对象对象 ); );w2=(w2=(WarplaneWarplane)p2;)p2;w2.MissileNumber=12;w2.MissileNumber=12;ConsoleConsole.WriteLine(.WriteLine(w2.speed=0tw2.missileNumber=1nw2.speed=0tw2.missileNumber=1n ,w2.Speed,w2.MissileNumber);,w2.Spee

60、d,w2.MissileNumber);elseelseConsoleConsole.WriteLine(.WriteLine(p2p2引用的不是一个引用的不是一个引用的不是一个引用的不是一个WarplaneWarplane对象对象对象对象nn); );if if(f1=p1(f1=p1asas FighterFighter)!=)!=nullnull) )ConsoleConsole.WriteLine(.WriteLine(p1p1引用的是一个引用的是一个引用的是一个引用的是一个FighterFighter对象对象对象对象 ); );f1.Print();f1.Print();Consol

61、eConsole.WriteLine.WriteLine();();elseelseConsoleConsole.WriteLine(.WriteLine(p1p1引用的不是一个引用的不是一个引用的不是一个引用的不是一个FighterFighter对象对象对象对象nn); );if if(f2=p2(f2=p2asas FighterFighter)!=)!=nullnull) )ConsoleConsole.WriteLine(.WriteLine(p2p2引用的是一个引用的是一个引用的是一个引用的是一个FighterFighter对象对象对象对象 ); );f2.Print();f2.Pr

62、int();elseelseConsoleConsole.WriteLine(.WriteLine(p2p2引用的不是一个引用的不是一个引用的不是一个引用的不是一个FighterFighter对象对象对象对象 ); ); 6.5 多态与动态绑定通过方法重写可以在具有继承关系的多通过方法重写可以在具有继承关系的多个类中定义名称相同但操作不同的多个个类中定义名称相同但操作不同的多个方法,多态指的正是程序运行时判断执方法,多态指的正是程序运行时判断执行其中哪个方法代码的能力。行其中哪个方法代码的能力。例6-7 多态源代码运 行例6-7 多态usingusingSystem;System;public

63、public classclass AnimalAnimal publicpublic virtualvirtual voidvoidSpeak()Speak()ConsoleConsole.WriteLine(.WriteLine(AnimalAnimalspeak.speak.); ); publicpublic classclass DogDog:AnimalAnimal publicpublic overrideoverride voidvoidSpeak()Speak()ConsoleConsole.WriteLine(.WriteLine(BowwowBowwow.); ); pu

64、blicpublic classclass CatCat:AnimalAnimal publicpublic overrideoverride voidvoidSpeak()Speak()ConsoleConsole.WriteLine(.WriteLine(MeowMeow.); ); publicpublic classclass TestPolymorphismTestPolymorphism publicpublic staticstatic voidvoid MakeSpeak(MakeSpeak(AnimalAnimala)a)a.Speaka.Speak();();publicp

65、ublic staticstatic voidvoidMain()Main()CatCatc=c=newnew CatCat();();DogDogd=d=newnew DogDog();();MakeSpeak(cMakeSpeak(c); );MakeSpeak(dMakeSpeak(d); ); 6.5 多态与动态绑定(续)C#C#语言的多态性是通过动态绑定实现的。所谓语言的多态性是通过动态绑定实现的。所谓语言的多态性是通过动态绑定实现的。所谓语言的多态性是通过动态绑定实现的。所谓绑定是指建立方法调用语句和方法之间的关系,绑定是指建立方法调用语句和方法之间的关系,绑定是指建立方法调用语句

66、和方法之间的关系,绑定是指建立方法调用语句和方法之间的关系,而动态绑定是指在程序运行时,根据对象的实际而动态绑定是指在程序运行时,根据对象的实际而动态绑定是指在程序运行时,根据对象的实际而动态绑定是指在程序运行时,根据对象的实际类型调用相应的方法。类型调用相应的方法。类型调用相应的方法。类型调用相应的方法。应用多态,可使程序具有良好的可扩充性应用多态,可使程序具有良好的可扩充性应用多态,可使程序具有良好的可扩充性应用多态,可使程序具有良好的可扩充性。 6.5 多态与动态绑定(续)C#C#语言中,所有方法默认都是非虚拟的。非虚语言中,所有方法默认都是非虚拟的。非虚语言中,所有方法默认都是非虚拟的

67、。非虚语言中,所有方法默认都是非虚拟的。非虚拟方法的调用在编译时绑定(即静态绑定),拟方法的调用在编译时绑定(即静态绑定),拟方法的调用在编译时绑定(即静态绑定),拟方法的调用在编译时绑定(即静态绑定),因此,调用非虚拟方法时,实际执行的总是用因此,调用非虚拟方法时,实际执行的总是用因此,调用非虚拟方法时,实际执行的总是用因此,调用非虚拟方法时,实际执行的总是用于调用的对象引用类型中定义(或其从基类继于调用的对象引用类型中定义(或其从基类继于调用的对象引用类型中定义(或其从基类继于调用的对象引用类型中定义(或其从基类继承来的)的方法。承来的)的方法。承来的)的方法。承来的)的方法。虚拟方法的调

68、用是动态绑定的,当通过某个对虚拟方法的调用是动态绑定的,当通过某个对虚拟方法的调用是动态绑定的,当通过某个对虚拟方法的调用是动态绑定的,当通过某个对象引用调用一个虚拟方法时,程序运行时会根象引用调用一个虚拟方法时,程序运行时会根象引用调用一个虚拟方法时,程序运行时会根象引用调用一个虚拟方法时,程序运行时会根据该引用实际引用的对象类型,按继承链从对据该引用实际引用的对象类型,按继承链从对据该引用实际引用的对象类型,按继承链从对据该引用实际引用的对象类型,按继承链从对象引用类型到实际对象类型顺序搜索其重写方象引用类型到实际对象类型顺序搜索其重写方象引用类型到实际对象类型顺序搜索其重写方象引用类型到

69、实际对象类型顺序搜索其重写方法,最终执行的是最后找到的重写方法。法,最终执行的是最后找到的重写方法。法,最终执行的是最后找到的重写方法。法,最终执行的是最后找到的重写方法。6.5 多态与动态绑定(续)成员隐藏不支持多态。成员隐藏不支持多态。静态方法不能声明为虚拟的,静态方法也静态方法不能声明为虚拟的,静态方法也不能是重写的。不能是重写的。重写方法不能同时是隐藏方法。不过,虚重写方法不能同时是隐藏方法。不过,虚拟方法可以同时是隐藏方法,虚拟的隐藏拟方法可以同时是隐藏方法,虚拟的隐藏方法允许在派生类中重写。方法允许在派生类中重写。例例例例6-8 6-8 6-8 6-8 方法隐藏与多态方法隐藏与多态

70、方法隐藏与多态方法隐藏与多态源代码运 行例例6-8 6-8 方法隐藏与多态方法隐藏与多态usingusingSystem;System;classclass A A publicpublic virtualvirtual voidvoidMethod()Method()ConsoleConsole.WriteLine(.WriteLine(MethodMethodinAinA);); classclass B B:A A publicpublic overrideoverride voidvoidMethod()Method()ConsoleConsole.WriteLine(.WriteLi

71、ne(MethodMethodinBinB);); classclass C C:B B publicpublic newnew voidvoidMethod()Method()ConsoleConsole.WriteLine(.WriteLine(MethodMethodinCinC);); classTestNew1publicstaticvoidMain()Aa1=newA();Aa2=newB();Aa3=newC();a1.Method();a2.Method();a3.Method();6.6 抽象类和抽象方法抽象方法一种虚拟方法。抽象方法一种虚拟方法。抽象方法只有方法头,没有具体

72、的方法抽象方法只有方法头,没有具体的方法体。定义抽象普通方法的语法形式为:体。定义抽象普通方法的语法形式为:abstractabstract返回值类型返回值类型返回值类型返回值类型 方法名(形式参数)方法名(形式参数)方法名(形式参数)方法名(形式参数); ;定义属性等特殊方法为抽象方法的语法为:定义属性等特殊方法为抽象方法的语法为:定义属性等特殊方法为抽象方法的语法为:定义属性等特殊方法为抽象方法的语法为:abstractabstract返回值类型返回值类型返回值类型返回值类型 属性名属性名属性名属性名 get;get;set;set; 6.6 抽象类和抽象方法其中其中abstractabs

73、tract是声明抽象方法的关键字是声明抽象方法的关键字是声明抽象方法的关键字是声明抽象方法的关键字例:例:例:例:abstractvoidMethod();abstractvoidMethod();abstractabstractintintWeightWeight get;get;set;set; 6.6 抽象类和抽象方法(续)含有抽象方法的类是抽象类,抽象类必含有抽象方法的类是抽象类,抽象类必须使用关键字须使用关键字abstract修饰。不过,一修饰。不过,一个抽象类并不一定拥有抽象方法。个抽象类并不一定拥有抽象方法。例:例:例:例:abstract class Aabstract cla

74、ss A public void Method()public void Method() 注意:注意:注意:注意:抽象类只能用作其他类的抽象类只能用作其他类的抽象类只能用作其他类的抽象类只能用作其他类的基类基类基类基类,不能创,不能创,不能创,不能创建其对象。建其对象。建其对象。建其对象。6.6 抽象类和抽象方法(续)继承于抽象类的类一般应该实现抽象类继承于抽象类的类一般应该实现抽象类中的所有抽象方法(重写)。中的所有抽象方法(重写)。如果没有,那么该派生类也就成为抽象如果没有,那么该派生类也就成为抽象类,必须使用关键字类,必须使用关键字abstract修饰修饰。6.6 抽象类和抽象方法(续

75、)abstractclassAabstractclassA publicabstractvoidpublicabstractvoidMethodAMethodA();(); classB:AclassB:A/ /错误,错误,错误,错误,B B或声明为抽象的,或实现或声明为抽象的,或实现或声明为抽象的,或实现或声明为抽象的,或实现A A类的抽象方法类的抽象方法类的抽象方法类的抽象方法 publicvoidpublicvoidMethodBMethodB()() classC:AclassC:A publicoverridevoidpublicoverridevoidMethodAMethodA(

76、)() 6.6 抽象类和抽象方法(续)静态方法不能声明为抽象的。静态方法不能声明为抽象的。静态方法不能声明为抽象的。静态方法不能声明为抽象的。私有方法不能声明为抽象的。私有方法不能声明为抽象的。私有方法不能声明为抽象的。私有方法不能声明为抽象的。 例例例例6-9 6-9 6-9 6-9 抽象类和抽象方法抽象类和抽象方法抽象类和抽象方法抽象类和抽象方法源代码运 行 例6-9 抽象类和抽象方法usingSystem;publicabstractclassAnimalpublicabstractvoidSpeak();publicclassDog:AnimalpublicoverridevoidSp

77、eak()Console.WriteLine(Bowwow.);publicclassCat:AnimalpublicoverridevoidSpeak()Console.WriteLine(Meow.);publicclassAbstractClassMethodpublicstaticvoidMakeSpeak(Animala)a.Speak();publicstaticvoidMain()Catc=newCat();Dogd=newDog();MakeSpeak(c);MakeSpeak(d);6.7 密封类、密封方法和静态类用关键字用关键字sealed修饰的类为密封类。修饰的类为密封类

78、。密封类不能被其他类继承。密封类不能被其他类继承。例例sealed class Asealed class Aclass B : Aclass B : A / /错误错误错误错误因为密封类不能被继承,因此,其中的方因为密封类不能被继承,因此,其中的方法不能声明为虚拟或抽象的,否则就违背法不能声明为虚拟或抽象的,否则就违背了声明密封类的初衷。了声明密封类的初衷。6.7密封类、密封方法和静态类(续)密封类、密封方法和静态类(续)用关键字用关键字sealed修饰的方法就是密封方法。修饰的方法就是密封方法。修饰的方法就是密封方法。修饰的方法就是密封方法。密封方法不能在派生类重写。密封方法不能在派生类重

79、写。将某个方法声明为密封的是为了说明该方将某个方法声明为密封的是为了说明该方法不能被重写,因此,密封方法应该同时法不能被重写,因此,密封方法应该同时是一个重写方法,关键字是一个重写方法,关键字sealed必须和必须和override在方法声明时同时出现在方法声明时同时出现。6.7密封类、密封方法和静态类(续)密封类、密封方法和静态类(续)publicabstractclassApublicabstractclassA publicabstractvoidMethod();publicabstractvoidMethod(); classB:AclassB:A publicpublicseale

80、doverridesealedoverridevoidMethod()voidMethod() Console.WriteLineConsole.WriteLine(在类在类在类在类B B中重写中重写中重写中重写);); 6.7密封类、密封方法和静态类(续)密封类、密封方法和静态类(续)classC:BclassC:B publicoverridevoidMethod()publicoverridevoidMethod()/ /错误,不能重写错误,不能重写错误,不能重写错误,不能重写 Console.WriteLineConsole.WriteLine(在类在类在类在类C C中重写中重写中重写

81、中重写);); publicnewvoidMethod()publicnewvoidMethod()/ /正确,可以隐藏正确,可以隐藏正确,可以隐藏正确,可以隐藏 Console.WriteLineConsole.WriteLine(在类在类在类在类C C中重写中重写中重写中重写);); 6.7密封类、密封方法和静态类(续)密封类、密封方法和静态类(续)静态类既不能被继承,也不能创建其对象,静态类既不能被继承,也不能创建其对象,其中所有成员都应是静态的。其中所有成员都应是静态的。staticstatic class A class A public static public static i

82、ntint i; i;public void Method()public void Method() / /错错错错误误误误 6.8接接口口接接口口是是一一种种抽抽象象的的数数据据类类型型,可可以以把把每每个个接接口口都都理理解解为为是是一一个个契契约约,其其中中约约定定了了实实现现接接口口的的对对象象必必须须实实现现的的方方法法,其其目目的的就就是是让让这这些些方方法法可可以以作作为为接接口口实实例例被引用。被引用。利用接口,可以间接实现多继承。利用接口,可以间接实现多继承。6.8.1定义接口定义接口6.8.2实现接口实现接口6.8.3显式实现接口显式实现接口6.8.1定义接口定义接口接口

83、中定义的成员可以是接口中定义的成员可以是方法、属性、索方法、属性、索引器和事件引器和事件,但不能是字段、常量、构造,但不能是字段、常量、构造函数、析构函数、运算符和内部数据类型,函数、析构函数、运算符和内部数据类型,而且不能包含任何静态成员。而且不能包含任何静态成员。接口本身并不提供它所定义成员的具体实接口本身并不提供它所定义成员的具体实现,它只是指定了实现该接口的类或结构现,它只是指定了实现该接口的类或结构必须实现的成员。必须实现的成员。6.8.1定义接口(续)定义接口(续)接口定义的一般语法:接口定义的一般语法:interfaceinterface ITestITest intint X

84、X get;get;set;set; void Method();void Method(); 6.8.1定义接口(续)定义接口(续)接口中定义的成员的访问权限总是公共的,接口中定义的成员的访问权限总是公共的,不过接口成员前一般不能有任何修饰符。不过接口成员前一般不能有任何修饰符。但如果一个接口是另一接口的派生接口时,但如果一个接口是另一接口的派生接口时,成员前可以使用关键字成员前可以使用关键字new显式声明某成显式声明某成员隐藏了基接口中的成员。员隐藏了基接口中的成员。通过继承,可以在现有接口的基础上定义通过继承,可以在现有接口的基础上定义派生接口。不过,与类不同,一个接口可派生接口。不过,

85、与类不同,一个接口可以同时继承多个接口。以同时继承多个接口。6.8.1定义接口(续)定义接口(续)例:例:例:例:public interface IApublic interface IA void Method1();void Method1(); public interface IBpublic interface IB void Method2();void Method2(); public interface IC : IApublic interface IC : IA void Method3();void Method3(); public interface ID : I

86、B,ICpublic interface ID : IB,IC void Method4();void Method4();new void Method3();new void Method3();/ /隐藏隐藏隐藏隐藏 6.8.1定义接口(续)定义接口(续)除内部接口外,接口的访问权限只能是除内部接口外,接口的访问权限只能是除内部接口外,接口的访问权限只能是除内部接口外,接口的访问权限只能是publicpublic或或或或internalinternal(默认)。(默认)。(默认)。(默认)。内部接口内部接口内部接口内部接口的访问权限则可以是的访问权限则可以是的访问权限则可以是的访问权限则

87、可以是publicpublic、internalinternal、protectedinternalprotectedinternal、protectedprotected或或或或privateprivate(默认)。(默认)。(默认)。(默认)。可以将接口想像成一个更纯粹的抽象类,不过,抽可以将接口想像成一个更纯粹的抽象类,不过,抽可以将接口想像成一个更纯粹的抽象类,不过,抽可以将接口想像成一个更纯粹的抽象类,不过,抽象类中还可以包含字段和具体方法等。在使用上,象类中还可以包含字段和具体方法等。在使用上,象类中还可以包含字段和具体方法等。在使用上,象类中还可以包含字段和具体方法等。在使用上,

88、接口与抽象类有许多相似之处。比如,不能创建接接口与抽象类有许多相似之处。比如,不能创建接接口与抽象类有许多相似之处。比如,不能创建接接口与抽象类有许多相似之处。比如,不能创建接口的对象,可以用作变量的数据类型,可以用作对口的对象,可以用作变量的数据类型,可以用作对口的对象,可以用作变量的数据类型,可以用作对口的对象,可以用作变量的数据类型,可以用作对象转换的类型,等等。象转换的类型,等等。象转换的类型,等等。象转换的类型,等等。6.8.2实现接口实现接口接接口口中中的的所所有有方方法法都都要要靠靠使使用用接接口口的的类类或或结结构构实实现现。但但是是与与抽抽象象方方法法不不同同,接接口口中中的

89、的方方法法并并不不是是虚虚拟拟方方法法,实实现现时时不不能能使使用用关关键键字字override。不不过过,它同样具有多态性。它同样具有多态性。 例例例例6-10 6-10 6-10 6-10 实现接口实现接口实现接口实现接口源代码运 行using System;public interface IAnimal int Age get; set; void Speak();public class Cat : IAnimal/实现接口实现接口 private int age; public int Age/实实现接口中的属性现接口中的属性 get return age; set age = v

90、alue; public virtual void Speak()/实现接口中的方法,并声明为虚拟的实现接口中的方法,并声明为虚拟的 Console.WriteLine(Cat Meow. 0, Age); public class Tomcat : Cat public override void Speak() /重写类重写类Cat中的方法中的方法 Console.WriteLine(Tomcat Meow. 0, Age); public class InterfaceImplements public static void MakeSpeak(IAnimal a) a.Speak()

91、; public static void Main() Tomcat t = new Tomcat(); t.Age = 2; MakeSpeak(t);/自动类型转换,多态自动类型转换,多态 Cat c = new Cat(); c.Age = 3; MakeSpeak(c);/自动类型转换,多态自动类型转换,多态 6.8.2实现接口(续)实现接口(续)如果一个类实现了某个接口,这个接口就相当如果一个类实现了某个接口,这个接口就相当如果一个类实现了某个接口,这个接口就相当如果一个类实现了某个接口,这个接口就相当于它的基类,派生类对象类型和接口类型可以于它的基类,派生类对象类型和接口类型可以于

92、它的基类,派生类对象类型和接口类型可以于它的基类,派生类对象类型和接口类型可以相互转换。相互转换。相互转换。相互转换。实现接口中的方法时,必须用实现接口中的方法时,必须用实现接口中的方法时,必须用实现接口中的方法时,必须用publicpublic修饰。修饰。修饰。修饰。接口中的方法不是虚拟方法,实现时不能使用接口中的方法不是虚拟方法,实现时不能使用接口中的方法不是虚拟方法,实现时不能使用接口中的方法不是虚拟方法,实现时不能使用关键字关键字关键字关键字overrideoverride。因此,实现接口的类被继承。因此,实现接口的类被继承。因此,实现接口的类被继承。因此,实现接口的类被继承时,默认情

93、况下,派生类中不能重写该类中实时,默认情况下,派生类中不能重写该类中实时,默认情况下,派生类中不能重写该类中实时,默认情况下,派生类中不能重写该类中实现的接口成员。如果希望这个类中实现的某个现的接口成员。如果希望这个类中实现的某个现的接口成员。如果希望这个类中实现的某个现的接口成员。如果希望这个类中实现的某个接口成员可以被重写,应该将它显式声明为虚接口成员可以被重写,应该将它显式声明为虚接口成员可以被重写,应该将它显式声明为虚接口成员可以被重写,应该将它显式声明为虚拟的。拟的。拟的。拟的。当然,如果是一个结构实现某接口,其中实现当然,如果是一个结构实现某接口,其中实现当然,如果是一个结构实现某

94、接口,其中实现当然,如果是一个结构实现某接口,其中实现的方法就不能使用的方法就不能使用的方法就不能使用的方法就不能使用virtualvirtual修饰,因为结构不能修饰,因为结构不能修饰,因为结构不能修饰,因为结构不能被继承。被继承。被继承。被继承。6.8.2实现接口(续)实现接口(续)如果某个接口方法没有被实现,实现类中必须将如果某个接口方法没有被实现,实现类中必须将如果某个接口方法没有被实现,实现类中必须将如果某个接口方法没有被实现,实现类中必须将它声明为抽象的,该类当然也必须声明为抽象的。它声明为抽象的,该类当然也必须声明为抽象的。它声明为抽象的,该类当然也必须声明为抽象的。它声明为抽象

95、的,该类当然也必须声明为抽象的。例:例:例:例:interfaceinterfaceIMsgIMsg voidMessage();voidMessage(); publicabstractclasspublicabstractclassMyClassMyClass:IMsgIMsg publicabstractvoidMessage();publicabstractvoidMessage(); 注意:使用结构实现接口时,结构必须实现接口中所有方法注意:使用结构实现接口时,结构必须实现接口中所有方法注意:使用结构实现接口时,结构必须实现接口中所有方法注意:使用结构实现接口时,结构必须实现接口中所

96、有方法6.8.2实现接口(续)实现接口(续)C#语语言言中中,为为了了得得到到多多继继承承的的效效果果,允允许许在在一一个个类类中中实实现现多多个个接接口口,甚甚至至,还允许同时继承一个类。还允许同时继承一个类。例例例例6-11 6-11 6-11 6-11 间接多继承间接多继承间接多继承间接多继承源代码运 行usingSystem;interfaceIAvoidMethod1();interfaceIBvoidMethod2();classCpublicvirtualvoidMethod3()Console.WriteLine(Method3()inC);classD:C,IA,IBpubl

97、icvoidMethod1()Console.WriteLine(Method1()inD);publicvoidMethod2()Console.WriteLine(Method2()inD);publicoverridevoidMethod3()Console.WriteLine(Method3()inD);publicclassMultiExtendsstaticvoidRunMethod1(IAa)a.Method1();staticvoidRunMethod2(IBb)b.Method2();staticvoidRunMethod3(Cc)c.Method3();publicstat

98、icvoidMain()Dd=newD();RunMethod1(d);/自动类型转换,多态自动类型转换,多态RunMethod2(d);/自动类型转换,多态自动类型转换,多态RunMethod3(d);/自动类型转换,多态自动类型转换,多态6.8.2实现接口(续)实现接口(续)在间接实现多继承时,可能遇到下列问题在间接实现多继承时,可能遇到下列问题interfaceIAinterfaceIA voidMethod();voidMethod(); interfaceIBinterfaceIB intMethod(inti);intMethod(inti); classCclassC publi

99、cvoidMethod()publicvoidMethod() classD:C,IA,IBclassD:C,IA,IB publicintMethod(inti)publicintMethod(inti) returni;returni; 6.8.2实现接口(续)实现接口(续)在类在类D中中接口接口接口接口IAIA中的方法中的方法中的方法中的方法voidMethod()voidMethod()由继承过来的由继承过来的由继承过来的由继承过来的类类类类C C的的的的publicvoidMethod()publicvoidMethod()实现,当然也可实现,当然也可实现,当然也可实现,当然也可在类

100、在类在类在类D D中重新定义方法隐藏它。中重新定义方法隐藏它。中重新定义方法隐藏它。中重新定义方法隐藏它。接口接口接口接口IBIB中的方法中的方法中的方法中的方法voidvoidMethod(Method(intinti i) )直接实现直接实现直接实现直接实现。6.8.2实现接口(续)实现接口(续)要同时实现下述接口必须使用显式方式要同时实现下述接口必须使用显式方式要同时实现下述接口必须使用显式方式要同时实现下述接口必须使用显式方式interfaceIAinterfaceIA voidMethod();voidMethod(); interfaceIBinterfaceIB intintMe

101、thod();Method(); 6.8.3显式实现接口显式实现接口一个实现接口的类也可以显式实现接口中的方法。一个实现接口的类也可以显式实现接口中的方法。一个实现接口的类也可以显式实现接口中的方法。一个实现接口的类也可以显式实现接口中的方法。例:例:例:例:interfaceIAinterfaceIAvoidMethod();voidMethod(); interfaceIBinterfaceIBintintMethod();Method(); classC:IA,IBclassC:IA,IBintint IB.MethodIB.Method() () return0;return0; vo

102、idvoidIA.MethodIA.Method()() 6.8.3显式实现接口(续)显式实现接口(续)显式实现接口方法时,方法名前必须使用显式实现接口方法时,方法名前必须使用接口名限定,而且该方法一定是公共的,接口名限定,而且该方法一定是公共的,不需要也不能使用任何访问权限修饰符修不需要也不能使用任何访问权限修饰符修饰。饰。显式实现的方法被排除在类的公共成员之显式实现的方法被排除在类的公共成员之外,不能通过类的对象调用,必须通过相外,不能通过类的对象调用,必须通过相应接口的对象调用。应接口的对象调用。显式实现的方法不能声明为虚拟的。显式实现的方法不能声明为虚拟的。6.8.3显式实现接口(续)

103、显式实现接口(续)例例例例:interfaceIAinterfaceIA intint Sum(intSum(intx1,intx2);x1,intx2); classB:IAclassB:IA intint IA.Sum(intIA.Sum(intx1,intx2)x1,intx2) returnx1+x2;returnx1+x2; classclassTestBTestBstaticvoidMain()staticvoidMain()Bb1=newB();Bb1=newB();intintsum1=b1.Sum(2,5);sum1=b1.Sum(2,5);/ /错误,显式实现的方法不能通过

104、类对象调用错误,显式实现的方法不能通过类对象调用错误,显式实现的方法不能通过类对象调用错误,显式实现的方法不能通过类对象调用IAIAiaia=newB();newB();intintsum2=ia.Sum(2,5);/sum2=ia.Sum(2,5);/正确,正确,正确,正确,显式实现的方法必须通过接口对象调用显式实现的方法必须通过接口对象调用显式实现的方法必须通过接口对象调用显式实现的方法必须通过接口对象调用 6.8.3显式实现接口(续)显式实现接口(续)显式接口成员没被声明为显式接口成员没被声明为public,这是因为,这是因为这些方法都有着双重的身份。当在一个类这些方法都有着双重的身份。

105、当在一个类中使用显式接口成员时,该方法被认为是中使用显式接口成员时,该方法被认为是私有方法,因此不能用类的实例调用它。私有方法,因此不能用类的实例调用它。但是,当将类的引用转型为接口引用时,但是,当将类的引用转型为接口引用时,接口中定义的方法就可以被调用,这时它接口中定义的方法就可以被调用,这时它又成为了一个公有方法。又成为了一个公有方法。课堂练习:输出结果using System;public interface IPartAvoid SetDataA(string dataA);public interface IPartB:IPartAvoid SetDataB(string dataB

106、);publicpublic classclass SharedClassSharedClass: :IPartBIPartB privateprivate stringstringDataA;DataA;privateprivate stringstringDataB;DataB;publicpublic voidvoidSetDataA(SetDataA(stringstringdataA)dataA)DataA=dataA;DataA=dataA;ConsoleConsole.WriteLine(.WriteLine(00,DataA);,DataA); publicpublic voi

107、dvoidSetDataB(SetDataB(stringstringdataB)dataB)DataB=dataB;DataB=dataB;ConsoleConsole.WriteLine(.WriteLine(00, ,DataBDataB); ); classclass testtest staticstatic voidvoidMain()Main()SharedClassSharedClassa=a=newnew SharedClassSharedClass();();a.SetDataA(a.SetDataA(interfaceIPartAinterfaceIPartA); );a

108、.SetDataB(a.SetDataB(interfaceIPartBinterfaceIPartB); ); 6.9 Object类System.Object类是类是.NET框架的根类,框架的根类,C#语言中,所有的类或结构都直接或间接语言中,所有的类或结构都直接或间接继承于它。继承于它。6.9.1 Equals方法方法6.9.2ToString方法方法6.9.1 Equals方法 用于比较两个对象是否相等,它有两种定义形式:用于比较两个对象是否相等,它有两种定义形式:publicvirtualpublicvirtualboolboolEquals(ObjectEquals(Objecto

109、bjobj) )/ /判断指定的判断指定的判断指定的判断指定的objobj对象是否等于当前对象对象是否等于当前对象对象是否等于当前对象对象是否等于当前对象publicstaticpublicstaticboolboolEquals(ObjectEquals(ObjectobjAobjA,Object,ObjectobjBobjB) )/ /判断指定的判断指定的判断指定的判断指定的objAobjA 和和和和objBobjB对象是否相等对象是否相等对象是否相等对象是否相等说明:说明:说明:说明: 静态方法静态方法静态方法静态方法Equals(objectEquals(object objA,obj

110、ectobjA,object objBobjB) )首先检查两首先检查两首先检查两首先检查两个对象个对象个对象个对象objAobjA和和和和objBobjB是否都为是否都为是否都为是否都为nullnull,如果是则返回,如果是则返回,如果是则返回,如果是则返回truetrue,否则进行否则进行否则进行否则进行objA.Equals(objBobjA.Equals(objB) )调用并返回其值。调用并返回其值。调用并返回其值。调用并返回其值。 实例方法实例方法实例方法实例方法Equals(objectEquals(object objobj) )缺省的实现其实就是缺省的实现其实就是缺省的实现其实

111、就是缺省的实现其实就是returnthis=returnthis=objobj; ;也就是判断两个对象是否引用相等。也就是判断两个对象是否引用相等。也就是判断两个对象是否引用相等。也就是判断两个对象是否引用相等。 6.9.1 Equals方法 对于对于对于对于值类型值类型值类型值类型,EqualsEquals方法判断对象所包含的值方法判断对象所包含的值方法判断对象所包含的值方法判断对象所包含的值是否相等。是否相等。是否相等。是否相等。对于对于对于对于引用类型引用类型引用类型引用类型,EqualsEquals方法默认情况下支持引方法默认情况下支持引方法默认情况下支持引方法默认情况下支持引用相等。

112、如果需要使用用相等。如果需要使用用相等。如果需要使用用相等。如果需要使用EqualsEquals方法判断两个引方法判断两个引方法判断两个引方法判断两个引用类型对象是否值相等,必须在派生类中重写上用类型对象是否值相等,必须在派生类中重写上用类型对象是否值相等,必须在派生类中重写上用类型对象是否值相等,必须在派生类中重写上述述述述虚拟虚拟虚拟虚拟EqualsEquals方法。方法。方法。方法。需要注意的是如果我们重写了某类型的实例方法需要注意的是如果我们重写了某类型的实例方法需要注意的是如果我们重写了某类型的实例方法需要注意的是如果我们重写了某类型的实例方法Equals(objectEquals(

113、object objobj) ),也应该重写实例方法,也应该重写实例方法,也应该重写实例方法,也应该重写实例方法GetHashCodeGetHashCode() ()。否则可能引发异常。否则可能引发异常。否则可能引发异常。否则可能引发异常。6.9.1 Equals方法(续)重写重写Equals方法时应该保证:方法时应该保证:x.Equals(xx.Equals(x) )都返回都返回都返回都返回 truetrue。 x.Equals(yx.Equals(y) )返回与返回与返回与返回与 y.Equals(xy.Equals(x) )相同的值。相同的值。相同的值。相同的值。如果如果如果如果 ( (

114、x.Equals(yx.Equals(y)&)&y.Equals(zy.Equals(z)返回返回返回返回 truetrue,则,则,则,则 x.Equals(zx.Equals(z) )返回返回返回返回 truetrue。只要不修改只要不修改只要不修改只要不修改 xx和和和和 yy引用的对象,对引用的对象,对引用的对象,对引用的对象,对 x.Equals(yx.Equals(y) )的相继调用将返回相同的值。的相继调用将返回相同的值。的相继调用将返回相同的值。的相继调用将返回相同的值。x.Equals(nullx.Equals(null) )返回返回返回返回 falsefalse。Equal

115、sEquals 的实现必须不引发异常。的实现必须不引发异常。的实现必须不引发异常。的实现必须不引发异常。usingSystem;structPoint1intx,y;publicPoint1(intx,inty)this.x=x;this.y=y;classPoint2intx,y;publicPoint2(intx,inty)this.x=x;this.y=y;例6-12 使用Equals方法classPoint3intx,y;publicPoint3(intx,inty)this.x=x;this.y=y;publicoverrideboolEquals(objectobj)/重写重写ob

116、ject类中的方法类中的方法if(obj=null)/如果参数为空,返回如果参数为空,返回falsereturnfalse;Point3p=objasPoint3;if(object)p=null) /如果参数不能转换为如果参数不能转换为Point,返,返回回falsereturnfalse;return(x=p.x)&(y=p.y);publicoverrideintGetHashCode()returnxy;classTestEqualsstaticvoidMain()Point1p11=newPoint1(1,2),p12=newPoint1(3,4);Console.Write(0t1

117、,p11.Equals(p12),Object.Equals(p11,p12);Point1p13=newPoint1(1,2);Console.WriteLine(t0t1,p11.Equals(p13),Object.Equals(p11,p13);Console.WriteLine();Point2p21=newPoint2(1,2),p22=newPoint2(3,4);Console.Write(0t1,p21.Equals(p22),Object.Equals(p21,p22);Point2p23=newPoint2(1,2);Console.WriteLine(t0t1,p21.

118、Equals(p23),Object.Equals(p21,p23);Console.WriteLine();Point3p31=newPoint3(1,2);Point3p32=newPoint3(3,4);Console.Write(0t1,p31.Equals(p32),Object.Equals(p31,p32);Point3p33=newPoint3(1,2);Console.WriteLine(t0t1,p31.Equals(p33),Object.Equals(p31,p33);课堂练习:输出结果using System; class Program static void Ma

119、in(string args) Object Obj1 = new Object(); Object Obj2 = new Object(); Console.WriteLine(Obj1.Equals(Obj2); Obj2 = Obj1; Console.WriteLine(Obj1.Equals(Obj2); False True 6.9.2 ToString方法ToStringToString方法返回一个代表有关当前对象本身方法返回一个代表有关当前对象本身方法返回一个代表有关当前对象本身方法返回一个代表有关当前对象本身信息的字符串。信息的字符串。信息的字符串。信息的字符串。默认情况下,

120、返回的字符串是该对象所属的类型默认情况下,返回的字符串是该对象所属的类型默认情况下,返回的字符串是该对象所属的类型默认情况下,返回的字符串是该对象所属的类型的完全限定名。的完全限定名。的完全限定名。的完全限定名。在派生类中可以重写此方法,以返回对该类型有在派生类中可以重写此方法,以返回对该类型有在派生类中可以重写此方法,以返回对该类型有在派生类中可以重写此方法,以返回对该类型有意义的值。意义的值。意义的值。意义的值。 public virtual string ToString () 例例例例6-13 6-13 使用使用使用使用ToStringToString方法方法方法方法源代码运 行例例6

121、-13 使用使用ToString方法方法usingSystem;namespaceLiu.CSharp.Ch06classCat/Cat类没有重写类没有重写ToString方法方法privateintcatNo;publicCat(intn)catNo=n;classDog/Dog类重写了类重写了ToString方法方法privateintdogNo;publicDog(intn)dogNo=n;publicoverrideStringToString()return+dogNo;publicclassTestToStringpublicstaticvoidMain()Catc=newCat(

122、1);Console.WriteLine(c.ToString();/显式调用显式调用ToString方法方法Console.WriteLine(c);/自动调用自动调用ToString方法方法Dogd=newDog(1);Console.WriteLine(d.ToString();/显式调用显式调用ToString方法方法Console.WriteLine(d); /自动调用自动调用ToString方法方法Console.WriteLine(DogNo.0,d);/自动调用自动调用ToString方法方法6.10 装箱与拆箱如果某对值类型和引用类型之间满足特定如果某对值类型和引用类型之间满

123、足特定条件,可以进行转换。从值类型到引用类条件,可以进行转换。从值类型到引用类型的转换称为装箱,从引用类型到值类型型的转换称为装箱,从引用类型到值类型的转换称为拆箱。的转换称为拆箱。6.10.1 装箱6.10.2 拆箱6.10.1 装 箱装箱转换是指将一个值类型隐式或显式地转换成装箱转换是指将一个值类型隐式或显式地转换成装箱转换是指将一个值类型隐式或显式地转换成装箱转换是指将一个值类型隐式或显式地转换成一个一个一个一个objectobject类型,或者把这个值类型转换成一个类型,或者把这个值类型转换成一个类型,或者把这个值类型转换成一个类型,或者把这个值类型转换成一个被该值类型应用的接口类型。

124、被该值类型应用的接口类型。被该值类型应用的接口类型。被该值类型应用的接口类型。把一个值类型的值装箱,就是创建一个把一个值类型的值装箱,就是创建一个把一个值类型的值装箱,就是创建一个把一个值类型的值装箱,就是创建一个objectobject实实实实例并将这个值复制给这个例并将这个值复制给这个例并将这个值复制给这个例并将这个值复制给这个objectobject,装箱后的,装箱后的,装箱后的,装箱后的objectobject对象中的数据位于堆中,堆中的地址在栈对象中的数据位于堆中,堆中的地址在栈对象中的数据位于堆中,堆中的地址在栈对象中的数据位于堆中,堆中的地址在栈中。被装箱的类型的值是作为一个拷贝

125、赋给对象中。被装箱的类型的值是作为一个拷贝赋给对象中。被装箱的类型的值是作为一个拷贝赋给对象中。被装箱的类型的值是作为一个拷贝赋给对象的。例:的。例:的。例:的。例: intinti=123;i=123;objecto=i;objecto=i;/隐式装箱隐式装箱隐式装箱隐式装箱objecto=objecto=object(iobject(i);/);/显式装箱显式装箱显式装箱显式装箱6.10.1 装箱(续)例6-14 装箱转换usingSystem;publicclassBoxingpublicstaticvoidMain()inti=11;objecto=i;i=22;Console.Wri

126、teLine(inti=0,i);Console.WriteLine(objecto=0,o);6.10.2 拆 箱拆箱转换是指将一个对象类型显式地转换成一个拆箱转换是指将一个对象类型显式地转换成一个拆箱转换是指将一个对象类型显式地转换成一个拆箱转换是指将一个对象类型显式地转换成一个值类型,或是将一个接口类型显式地转换成一个值类型,或是将一个接口类型显式地转换成一个值类型,或是将一个接口类型显式地转换成一个值类型,或是将一个接口类型显式地转换成一个执行该接口地值类型。执行该接口地值类型。执行该接口地值类型。执行该接口地值类型。拆箱必须显式进行,它包括以下两个步骤:拆箱必须显式进行,它包括以下两

127、个步骤:拆箱必须显式进行,它包括以下两个步骤:拆箱必须显式进行,它包括以下两个步骤: 检查对象实例,确保它是给定值类型的一个装箱值。检查对象实例,确保它是给定值类型的一个装箱值。检查对象实例,确保它是给定值类型的一个装箱值。检查对象实例,确保它是给定值类型的一个装箱值。 将该值从实例复制到值类型变量中。将该值从实例复制到值类型变量中。将该值从实例复制到值类型变量中。将该值从实例复制到值类型变量中。 例:例:例:例: intinti=123;i=123;objecto=i;objecto=i;/ /装箱装箱装箱装箱 intintj=(j=(int)oint)o; ;/ /拆箱拆箱拆箱拆箱6.10

128、.2 拆箱(续)例6-15 拆箱转换usingSystem;publicclassUnboxingpublicstaticvoidMain()objecto=10;inti=(int)o;i=20;Console.WriteLine(objecto=0,o);Console.WriteLine(inti=0,i);6.10.2 拆箱(续) 被拆箱的引用类型对象必须是先前通过装箱该值类型变量被拆箱的引用类型对象必须是先前通过装箱该值类型变量被拆箱的引用类型对象必须是先前通过装箱该值类型变量被拆箱的引用类型对象必须是先前通过装箱该值类型变量所创建的,如果所创建的,如果所创建的,如果所创建的,如果o

129、bjectobject型或接口类型的值为型或接口类型的值为型或接口类型的值为型或接口类型的值为nullnull,或者与,或者与,或者与,或者与目标类型不兼容,拆箱将会失败,系统会引发异常。目标类型不兼容,拆箱将会失败,系统会引发异常。目标类型不兼容,拆箱将会失败,系统会引发异常。目标类型不兼容,拆箱将会失败,系统会引发异常。 objectobjectobjobj=10;=10;/ /装箱装箱装箱装箱 doublei=(doublei=(double)odouble)o; ;/ /拆箱拆箱拆箱拆箱, ,错误错误错误错误 拆箱转换前,可以使用运算符拆箱转换前,可以使用运算符拆箱转换前,可以使用运算

130、符拆箱转换前,可以使用运算符isis判断待拆箱的对象是否由目判断待拆箱的对象是否由目判断待拆箱的对象是否由目判断待拆箱的对象是否由目标值类型装箱而来的。例:标值类型装箱而来的。例:标值类型装箱而来的。例:标值类型装箱而来的。例:objectobjectobjobj=10;=10;doublex;doublex;if(objif(objisdouble)x=(isdouble)x=(double)objdouble)obj; ;6.11 两个常用.NET框架类型框架类库是框架类库是.NET框架提供的一个可重复使框架提供的一个可重复使用的以面向对象方法设计成的类和结构等用的以面向对象方法设计成的类

131、和结构等类型的集合。类型的集合。6.11.1DateTime结构结构6.11.2Math类类6.11.1 DateTime结构结构DateTime结构用于表示值范围在公元结构用于表示值范围在公元0001年年1月月1日午夜日午夜12:00:00到公元到公元9999年年12月月31日晚上日晚上11:59:59之间的日期和时间,之间的日期和时间,时间值以时间值以100毫微秒为单位(该单位称为刻毫微秒为单位(该单位称为刻度)进行计量。度)进行计量。6.11.1 DateTime结构(续)/2007年年1月月1日午夜日午夜00:00:00dt=newDateTime(2007,1,1);/2007年年7

132、月月1日中午日中午12:00:00dt=newDateTime(2007,7,1,12,0,0);/2007年年12月月1日晚上日晚上10:30:3050msdtdt=new=newDateTimeDateTime(2007,12,1,22,30,30,50);(2007,12,1,22,30,30,50);6.11.1 DateTime结构(续)DateTime结构中定义有大量的公共属性和方法,使用它们可以操作相应的DateTime 对象。 例6-16 使用DateTime结构源代码运 行DateTime结构的公共属性DateDateDateDate获取此实例的日期部分。获取此实例的日期部分

133、。获取此实例的日期部分。获取此实例的日期部分。DayDayDayDay获取此实例所表示的日期为该月中的第几天。获取此实例所表示的日期为该月中的第几天。获取此实例所表示的日期为该月中的第几天。获取此实例所表示的日期为该月中的第几天。DayOfWeekDayOfWeekDayOfWeekDayOfWeek获取此实例所表示的日期是星期几。获取此实例所表示的日期是星期几。获取此实例所表示的日期是星期几。获取此实例所表示的日期是星期几。DayOfYearDayOfYearDayOfYearDayOfYear获取此实例所表示的日期是该年中的第几天。获取此实例所表示的日期是该年中的第几天。获取此实例所表示的

134、日期是该年中的第几天。获取此实例所表示的日期是该年中的第几天。HourHourHourHour获取此实例所表示日期的小时部分。获取此实例所表示日期的小时部分。获取此实例所表示日期的小时部分。获取此实例所表示日期的小时部分。KindKindKindKind获取一个值,该值指示由此实例表示的时间是基于本地时间、协调通用时间获取一个值,该值指示由此实例表示的时间是基于本地时间、协调通用时间获取一个值,该值指示由此实例表示的时间是基于本地时间、协调通用时间获取一个值,该值指示由此实例表示的时间是基于本地时间、协调通用时间 (UTC)(UTC),还是两者,还是两者,还是两者,还是两者皆否。皆否。皆否。皆

135、否。MillisecondMillisecondMillisecondMillisecond获取此实例所表示日期的毫秒部分。获取此实例所表示日期的毫秒部分。获取此实例所表示日期的毫秒部分。获取此实例所表示日期的毫秒部分。MinuteMinuteMinuteMinute获取此实例所表示日期的分钟部分。获取此实例所表示日期的分钟部分。获取此实例所表示日期的分钟部分。获取此实例所表示日期的分钟部分。MonthMonthMonthMonth获取此实例所表示日期的月份部分。获取此实例所表示日期的月份部分。获取此实例所表示日期的月份部分。获取此实例所表示日期的月份部分。NowNowNowNow获取一个获取

136、一个获取一个获取一个 DateTimeDateTime 对象,该对象设置为此计算机上的当前日期和时间,表示为本地时间。对象,该对象设置为此计算机上的当前日期和时间,表示为本地时间。对象,该对象设置为此计算机上的当前日期和时间,表示为本地时间。对象,该对象设置为此计算机上的当前日期和时间,表示为本地时间。SecondSecondSecondSecond获取此实例所表示日期的秒部分。获取此实例所表示日期的秒部分。获取此实例所表示日期的秒部分。获取此实例所表示日期的秒部分。TicksTicksTicksTicks获取表示此实例的日期和时间的刻度数。获取表示此实例的日期和时间的刻度数。获取表示此实例的

137、日期和时间的刻度数。获取表示此实例的日期和时间的刻度数。TimeOfDayTimeOfDayTimeOfDayTimeOfDay获取此实例的当天的时间。获取此实例的当天的时间。获取此实例的当天的时间。获取此实例的当天的时间。TodayTodayTodayToday获取当前日期。获取当前日期。获取当前日期。获取当前日期。UtcNowUtcNowUtcNowUtcNow获取一个获取一个获取一个获取一个 DateTimeDateTime 对象,该对象设置为此计算机上的当前日期和时间,表示为协调通用时对象,该对象设置为此计算机上的当前日期和时间,表示为协调通用时对象,该对象设置为此计算机上的当前日期和

138、时间,表示为协调通用时对象,该对象设置为此计算机上的当前日期和时间,表示为协调通用时间间间间 (UTC)(UTC)。YearYearYearYear获取此实例所表示日期的年份部分。获取此实例所表示日期的年份部分。获取此实例所表示日期的年份部分。获取此实例所表示日期的年份部分。 例6-16 使用DateTime结构usingSystem;classTestDateTimestaticvoidMain()DateTimedt=DateTime.Now;Console.WriteLine(当前的日期和时是当前的日期和时是0,dt);Console.WriteLine(今天的日期是今天的日期是0年年1

139、月月2日日,dt.Year,dt.Month,dt.Day);Console.WriteLine(现在的时间是现在的时间是0,dt.TimeOfDay);Console.WriteLine(现在的时间是现在的时间是0点点1分分2秒秒,dt.Hour,dt.Minute,dt.Second);Console.WriteLine(今天是今天是0,dt.DayOfWeek);Console.WriteLine(今天是今年的第今天是今年的第0天天,dt.DayOfYear);6.11.2 Math类MathMath类是一个静态类,为三角函数、对数函数和类是一个静态类,为三角函数、对数函数和类是一个静态

140、类,为三角函数、对数函数和类是一个静态类,为三角函数、对数函数和其他通用数学函数提供常数和静态方法。其他通用数学函数提供常数和静态方法。其他通用数学函数提供常数和静态方法。其他通用数学函数提供常数和静态方法。常量:常量:常量:常量: public const double Epublic const double E/e/e public const double PIpublic const double PI / / 常用方法:常用方法:常用方法:常用方法: 三角函数方法三角函数方法三角函数方法三角函数方法 指数或幂函数方法指数或幂函数方法指数或幂函数方法指数或幂函数方法 对数函数方法对数

141、函数方法对数函数方法对数函数方法 其他常用方法其他常用方法其他常用方法其他常用方法6.11.2 Math类(续)三角函数方法三角函数方法三角函数方法三角函数方法: : public static double Sin (double a) public static double Sin (double a) public static double Cos (double d) public static double Cos (double d) public static double Tan (double a)public static double Tan (double a) p

142、ublic static double public static double AsinAsin (double d) (double d) public static double public static double AcosAcos (double d) (double d) public static double public static double AtanAtan (double d) (double d)其中,传递或返回的角度以弧度为单位计量其中,传递或返回的角度以弧度为单位计量其中,传递或返回的角度以弧度为单位计量其中,传递或返回的角度以弧度为单位计量。6.11.2

143、 Math类(续)指数或幂函数方法:指数或幂函数方法:指数或幂函数方法:指数或幂函数方法:publicstaticdoubleExp(doubled)publicstaticdoubleExp(doubled)publicstaticdoublepublicstaticdoublePowPow(double(doublex,doublex,doubley)y)publicstaticdoublepublicstaticdoubleSqrtSqrt(doubled)(doubled)6.11.2 Math类(续)对数函数方法:对数函数方法:publicstaticdoubleLog(double

144、d)publicstaticdoubleLog(doubled)publicstaticdoubleLogpublicstaticdoubleLog(double(doublea,doublea,double newBasenewBase) )publicstaticdoubleLog10(doubled)publicstaticdoubleLog10(doubled)6.11.2 Math类(续)其他常用方法:其他常用方法:AbsAbsCeilingCeilingFloorFloorMinMin、MaxMaxRoundRoundSignSignTruncateTruncateMath类公共方

145、法AbsAbsAbsAbs已重载。已重载。已重载。已重载。 返回指定数字的绝对值。返回指定数字的绝对值。返回指定数字的绝对值。返回指定数字的绝对值。AcosAcosAcosAcos返回余弦值为指定数字的角度。返回余弦值为指定数字的角度。返回余弦值为指定数字的角度。返回余弦值为指定数字的角度。AsinAsinAsinAsin返回正弦值为指定数字的角度。返回正弦值为指定数字的角度。返回正弦值为指定数字的角度。返回正弦值为指定数字的角度。AtanAtanAtanAtan返回正切值为指定数字的角度。返回正切值为指定数字的角度。返回正切值为指定数字的角度。返回正切值为指定数字的角度。Atan2Atan2

146、Atan2Atan2返回正切值为两个指定数字的商的角度。返回正切值为两个指定数字的商的角度。返回正切值为两个指定数字的商的角度。返回正切值为两个指定数字的商的角度。BigMulBigMulBigMulBigMul生成两个生成两个生成两个生成两个 32 32 位数字的完整乘积。位数字的完整乘积。位数字的完整乘积。位数字的完整乘积。CeilingCeilingCeilingCeiling已重载。已重载。已重载。已重载。 返回大于或等于指定数字的最小整数。返回大于或等于指定数字的最小整数。返回大于或等于指定数字的最小整数。返回大于或等于指定数字的最小整数。CosCosCosCos返回指定角度的余弦值

147、。返回指定角度的余弦值。返回指定角度的余弦值。返回指定角度的余弦值。CoshCoshCoshCosh返回指定角度的双曲余弦值。返回指定角度的双曲余弦值。返回指定角度的双曲余弦值。返回指定角度的双曲余弦值。DivRemDivRemDivRemDivRem已重载。已重载。已重载。已重载。 计算两个数字的商,并在输出参数中返回余数。计算两个数字的商,并在输出参数中返回余数。计算两个数字的商,并在输出参数中返回余数。计算两个数字的商,并在输出参数中返回余数。EqualsEqualsEqualsEquals已重载。已重载。已重载。已重载。 确定两个确定两个确定两个确定两个 Object Object 实

148、例是否相等。实例是否相等。实例是否相等。实例是否相等。 (从(从(从(从 Object Object 继承。)继承。)继承。)继承。)ExpExpExpExp返回返回返回返回 e e 的指定次幂。的指定次幂。的指定次幂。的指定次幂。FloorFloorFloorFloor已重载。已重载。已重载。已重载。 返回小于或等于指定数字的最大整数。返回小于或等于指定数字的最大整数。返回小于或等于指定数字的最大整数。返回小于或等于指定数字的最大整数。GetHashCodeGetHashCodeGetHashCodeGetHashCode用作特定类型的哈希函数。用作特定类型的哈希函数。用作特定类型的哈希函数

149、。用作特定类型的哈希函数。GetHashCodeGetHashCode 适合在哈希算法和数据结构(如哈希表)中适合在哈希算法和数据结构(如哈希表)中适合在哈希算法和数据结构(如哈希表)中适合在哈希算法和数据结构(如哈希表)中使用。使用。使用。使用。 (从(从(从(从 Object Object 继承。)继承。)继承。)继承。)GetTypeGetTypeGetTypeGetType获取当前实例的获取当前实例的获取当前实例的获取当前实例的 TypeType。 (从(从(从(从 Object Object 继承。)继承。)继承。)继承。)IEEERemainderIEEERemainderIEEE

150、RemainderIEEERemainder返回一指定数字被另一指定数字相除的余数。返回一指定数字被另一指定数字相除的余数。返回一指定数字被另一指定数字相除的余数。返回一指定数字被另一指定数字相除的余数。LogLogLogLog已重载。已重载。已重载。已重载。 返回指定数字的对数。返回指定数字的对数。返回指定数字的对数。返回指定数字的对数。Log10Log10Log10Log10返回指定数字以返回指定数字以返回指定数字以返回指定数字以 10 10 为底的对数。为底的对数。为底的对数。为底的对数。Math类公共方法(续)MaxMaxMaxMax已重载。已重载。已重载。已重载。 返回两个指定数字中

151、较大的一个。返回两个指定数字中较大的一个。返回两个指定数字中较大的一个。返回两个指定数字中较大的一个。MinMinMinMin已重载。已重载。已重载。已重载。 返回两个数字中较小的一个。返回两个数字中较小的一个。返回两个数字中较小的一个。返回两个数字中较小的一个。PowPowPowPow返回指定数字的指定次幂。返回指定数字的指定次幂。返回指定数字的指定次幂。返回指定数字的指定次幂。ReferenceEqualsReferenceEqualsReferenceEqualsReferenceEquals确定指定的确定指定的确定指定的确定指定的 Object Object Object Object

152、 实例是否是相同的实例。实例是否是相同的实例。实例是否是相同的实例。实例是否是相同的实例。 (从(从(从(从 Object Object Object Object 继承。)继承。)继承。)继承。)RoundRoundRoundRound已重载。已重载。已重载。已重载。 将值舍入到最接近的整数或指定的小数位数。将值舍入到最接近的整数或指定的小数位数。将值舍入到最接近的整数或指定的小数位数。将值舍入到最接近的整数或指定的小数位数。SignSignSignSign已重载。已重载。已重载。已重载。 返回表示数字符号的值。返回表示数字符号的值。返回表示数字符号的值。返回表示数字符号的值。SinSinS

153、inSin返回指定角度的正弦值。返回指定角度的正弦值。返回指定角度的正弦值。返回指定角度的正弦值。SinhSinhSinhSinh返回指定角度的双曲正弦值。返回指定角度的双曲正弦值。返回指定角度的双曲正弦值。返回指定角度的双曲正弦值。SqrtSqrtSqrtSqrt返回指定数字的平方根。返回指定数字的平方根。返回指定数字的平方根。返回指定数字的平方根。TanTanTanTan返回指定角度的正切值。返回指定角度的正切值。返回指定角度的正切值。返回指定角度的正切值。TanhTanhTanhTanh返回指定角度的双曲正切值。返回指定角度的双曲正切值。返回指定角度的双曲正切值。返回指定角度的双曲正切值

154、。ToStringToStringToStringToString返回表示当前返回表示当前返回表示当前返回表示当前 Object Object 的的的的 StringString。 (从(从(从(从 Object Object 继承。)继承。)继承。)继承。)TruncateTruncateTruncateTruncate已重载。已重载。已重载。已重载。 计算一个数字的整数部分。计算一个数字的整数部分。计算一个数字的整数部分。计算一个数字的整数部分。 6.11.2 Math类(续) 例6-17 使用Math类源代码运 行usingSystem;classTestMathstaticvoidMa

155、in()Console.WriteLine(Math.Cos(Math.PI)=0,Math.Cos(Math.PI);Console.WriteLine(Math.Tan(0)=0,Math.Tan(0);Console.WriteLine(Math.Asin(0)=0,Math.Asin(0);Console.WriteLine(Math.Exp(2)=0,Math.Exp(2);Console.WriteLine(Math.Pow(2,3)=0,Math.Pow(2,3);Console.WriteLine(Math.Sqrt(4)=0,Math.Sqrt(4);Console.Writ

156、eLine(Math.Log(Math.E)=0,Math.Log(Math.E);Console.WriteLine(Math.Log10(10)=0,Math.Log10(10);Console.WriteLine(Math.Abs(-5.2)=0,Math.Abs(-5.2);Console.WriteLine(Math.Min(10.2,12.5)=0,Math.Min(10.2,12.5);Console.WriteLine(Math.Max(10.2,12.5)=0,Math.Max(10.2,12.5);Console.WriteLine(Math.Round(10.2)=0,M

157、ath.Round(10.2);6.12 习 题2.2.什么是继承?什么是基类?什么是派生类?什么是继承?什么是基类?什么是派生类?什么是继承?什么是基类?什么是派生类?什么是继承?什么是基类?什么是派生类? 继承是从一个类派生出一个新类的过程继承是从一个类派生出一个新类的过程继承是从一个类派生出一个新类的过程继承是从一个类派生出一个新类的过程 被继承的类则称为基类、超类或父类。被继承的类则称为基类、超类或父类。被继承的类则称为基类、超类或父类。被继承的类则称为基类、超类或父类。 使用继承而产生的类被称为派生类或者子类使用继承而产生的类被称为派生类或者子类使用继承而产生的类被称为派生类或者子类

158、使用继承而产生的类被称为派生类或者子类8.8.关键字关键字关键字关键字basebase的主要作用是什么?的主要作用是什么?的主要作用是什么?的主要作用是什么? 要使用关键字要使用关键字要使用关键字要使用关键字basebase来显式调用基类构造函数。来显式调用基类构造函数。来显式调用基类构造函数。来显式调用基类构造函数。 关键字关键字关键字关键字basebase代表的是当前派生类对象中的基类子对象,因此,通代表的是当前派生类对象中的基类子对象,因此,通代表的是当前派生类对象中的基类子对象,因此,通代表的是当前派生类对象中的基类子对象,因此,通过它可以访问基类成员。过它可以访问基类成员。过它可以访

159、问基类成员。过它可以访问基类成员。9.9.成员重写与隐藏的适用范围有什么不同?成员重写与隐藏的适用范围有什么不同?成员重写与隐藏的适用范围有什么不同?成员重写与隐藏的适用范围有什么不同? 成员隐藏并不局限于方法成员,它也能用于数据成员和内部数据成员隐藏并不局限于方法成员,它也能用于数据成员和内部数据成员隐藏并不局限于方法成员,它也能用于数据成员和内部数据成员隐藏并不局限于方法成员,它也能用于数据成员和内部数据类型。类型。类型。类型。 使用关键字使用关键字使用关键字使用关键字newnew隐藏基类成员时并不要求基类中的成员是虚拟的。隐藏基类成员时并不要求基类中的成员是虚拟的。隐藏基类成员时并不要求

160、基类中的成员是虚拟的。隐藏基类成员时并不要求基类中的成员是虚拟的。它通常用于改写基类中的非虚拟方法。它通常用于改写基类中的非虚拟方法。它通常用于改写基类中的非虚拟方法。它通常用于改写基类中的非虚拟方法。 隐藏方法不支持多态隐藏方法不支持多态隐藏方法不支持多态隐藏方法不支持多态10.10.简述引用类型装换的规则简述引用类型装换的规则简述引用类型装换的规则简述引用类型装换的规则 一个派生类对象的类型可以向上转换成它的基类类型,这种转换一个派生类对象的类型可以向上转换成它的基类类型,这种转换一个派生类对象的类型可以向上转换成它的基类类型,这种转换一个派生类对象的类型可以向上转换成它的基类类型,这种转

161、换是安全的,是安全的,是安全的,是安全的,C#C#编译器能隐式进行。编译器能隐式进行。编译器能隐式进行。编译器能隐式进行。 一个基类对象的类型一般不能向下转换成它的派生类类型。但有一个基类对象的类型一般不能向下转换成它的派生类类型。但有一个基类对象的类型一般不能向下转换成它的派生类类型。但有一个基类对象的类型一般不能向下转换成它的派生类类型。但有一种情况除外,如果一个基类对象引用实际引用的是一个派生类一种情况除外,如果一个基类对象引用实际引用的是一个派生类一种情况除外,如果一个基类对象引用实际引用的是一个派生类一种情况除外,如果一个基类对象引用实际引用的是一个派生类对象,就可以使用显式转换将这

162、个基类对象转换成派生类类型。对象,就可以使用显式转换将这个基类对象转换成派生类类型。对象,就可以使用显式转换将这个基类对象转换成派生类类型。对象,就可以使用显式转换将这个基类对象转换成派生类类型。11.11.什么是多态?什么是动态绑定?什么是多态?什么是动态绑定?什么是多态?什么是动态绑定?什么是多态?什么是动态绑定? 通过方法重写可以在具有继承关系的多个类中定义名称相同但操通过方法重写可以在具有继承关系的多个类中定义名称相同但操通过方法重写可以在具有继承关系的多个类中定义名称相同但操通过方法重写可以在具有继承关系的多个类中定义名称相同但操作不同的多个方法,多态指的正是程序运行时判断执行其中哪

163、个作不同的多个方法,多态指的正是程序运行时判断执行其中哪个作不同的多个方法,多态指的正是程序运行时判断执行其中哪个作不同的多个方法,多态指的正是程序运行时判断执行其中哪个方法代码的能力。方法代码的能力。方法代码的能力。方法代码的能力。 所谓绑定是指建立方法调用语句和方法之间的关系,而动态绑定所谓绑定是指建立方法调用语句和方法之间的关系,而动态绑定所谓绑定是指建立方法调用语句和方法之间的关系,而动态绑定所谓绑定是指建立方法调用语句和方法之间的关系,而动态绑定是指在程序运行时,根据对象的实际类型调用相应的方法。是指在程序运行时,根据对象的实际类型调用相应的方法。是指在程序运行时,根据对象的实际类型

164、调用相应的方法。是指在程序运行时,根据对象的实际类型调用相应的方法。14.14.抽象方法与一般方法有什么不同?抽象方法与一般方法有什么不同?抽象方法与一般方法有什么不同?抽象方法与一般方法有什么不同? 抽象方法只有方法头,没有具体的方法体。抽象方法只有方法头,没有具体的方法体。抽象方法只有方法头,没有具体的方法体。抽象方法只有方法头,没有具体的方法体。 抽象方法使用关键字抽象方法使用关键字抽象方法使用关键字抽象方法使用关键字abstractabstract修饰,隐含为虚拟的方法。修饰,隐含为虚拟的方法。修饰,隐含为虚拟的方法。修饰,隐含为虚拟的方法。 静态方法不能声明为抽象的。静态方法不能声明

165、为抽象的。静态方法不能声明为抽象的。静态方法不能声明为抽象的。 私有方法不能声明为抽象的。私有方法不能声明为抽象的。私有方法不能声明为抽象的。私有方法不能声明为抽象的。 抽象类与一般类有什么不同?抽象类与一般类有什么不同?抽象类与一般类有什么不同?抽象类与一般类有什么不同? 含有抽象方法的类是抽象类,抽象类必须使用关键字含有抽象方法的类是抽象类,抽象类必须使用关键字含有抽象方法的类是抽象类,抽象类必须使用关键字含有抽象方法的类是抽象类,抽象类必须使用关键字abstractabstract修饰。修饰。修饰。修饰。 抽象类只能作为其它类的基类,不能创建一个抽象类抽象类只能作为其它类的基类,不能创建

166、一个抽象类抽象类只能作为其它类的基类,不能创建一个抽象类抽象类只能作为其它类的基类,不能创建一个抽象类的对象。的对象。的对象。的对象。作业按下图的继承关系定义图形类(按下图的继承关系定义图形类(按下图的继承关系定义图形类(按下图的继承关系定义图形类(ShapeShape)为基类,在此基)为基类,在此基)为基类,在此基)为基类,在此基础上派生矩形类(础上派生矩形类(础上派生矩形类(础上派生矩形类(RectangleRectangle)和圆类()和圆类()和圆类()和圆类(CircleCircle)。并进一)。并进一)。并进一)。并进一步定义构造函数、求面积(步定义构造函数、求面积(步定义构造函数、求面积(步定义构造函数、求面积(AreaArea)和周长)和周长)和周长)和周长(C Circumferenceircumference)的方法,编程验证。)的方法,编程验证。)的方法,编程验证。)的方法,编程验证。ShapeCircleRectangle

展开阅读全文
相关资源
正为您匹配相似的精品文档
相关搜索

最新文档


当前位置:首页 > 建筑/环境 > 施工组织

电脑版 |金锄头文库版权所有
经营许可证:蜀ICP备13022795号 | 川公网安备 51140202000112号