




版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领
文档简介
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 继承简介,继承是软件复用的一种形式。采用这种形式,可吸收现有类的数据和行为,为其赋予新功能,从而创建出新类。软件复用节省了程序开发时间。它还鼓励人们重用经过实践检验和调试的高质量软件,使系统能高效地实现。,父类,子类,动物,6.1 继承简介(续),继承是从一个类派生出
2、一个新类的过程。 通过继承,可以让一个类拥有另一个现有类的全部成员,也即让一个类继承另一个现有类的全部成员。 继承的类可以使用另一个现有类的所有功能,并在无需重新编写原来的类的情况下对这些功能进行扩展。 使用继承而产生的类被称为派生类或者子类,而被继承的类则称为基类、超类或父类。,6.1 继承简介(续),客观世界中的许多事物之间往往都是具有相同的特征,具有继承的特点。 如,一个Rectangle(矩形)类“属于”四边形(正方形、平行四边形和梯形同样是四边形)。也可以说,Rectangle(矩形类)是从Quadrilateral(四边形)类继承而来的。 Quadrilateral类是基类, Re
3、ctangle类是派生类。 再如,教师类和学生类可以由大学成员类派生,讲师、教授又可以由教师类派生,毕业生和在校生又可以由学生类派生。,6.1 继承简介(续),四边形,矩形,梯形,正方形,大学成员,教师,学生,讲师,教授,在校生,毕业生,6.1 继承简介(续),单继承是指从一个基类派生出一个派生类的过程,而多继承是指从一个以上的基类派生出一个派生类的过程。 C#语言仅支持单继承,其多继承只能通过接口等间接实现。,计算机,台式机,便携机,硬盘,输入设备,输出设备,6.2 基类与派生类,6.2.1 继承的语法 6.2.2 派生类的构造函数 6.2.3 结构与继承,6.2.1 继承的语法,一般语法如
4、下: 访问权限 class 派生类名 :基类名 定义派生类新成员 访问权限可以是public和internal(默认的) 派生类名就是通过继承派生的类的名称 基类名指明了这个派生类的基类 派生时,基类的访问权限不能小于派生类,6.2.1 继承的语法(续),例:派生时,基类的访问权限不能小于派生类 class A public class B class C:A/ class D:B/ public class E:A/ public class F:B/,正确,正确,正确,错误,Class Base / 成员变量 int basevar; / 成员函数 public Base_fun1() /
5、 定义 . .,Class Derived : Base / 成员变量 int derivedvars; / 成员函数 Derived_fun1() / 定义 . .,基类,void Main() Derived dr_obj = new Derived() ; dr_obj.Base_fun1(); ,无需重新编写代码,派生类,例6-1 派生类的定义,/Cat.cs using System; public class Animal private int weight; private int age; public int Age get return age; set age = (v
6、alue = 0) ? value : 0); public int Weight get return weight; set weight = (value = 0) ? value : 0); ,例6-1 派生类的定义(续),public class Cat : Animal public void Meow() Console.WriteLine(Meow.); public static void Main() Cat c = new Cat(); c.Age = 2; /使用基类的公有属性 c.Weight = 5; /使用基类的公有属性 Console.WriteLine(CAT
7、); c.Meow(); Console.WriteLine(Age=0,tWeight=1, c.Age, c.Weight); ,6.2.1 继承的语法(续),派生类自动获取基类的除构造函数和析构函数外的所有成员。 基类的public成员被派生类继承后在派生类中可以直接访问,也可以在程序的任何地方通过派生类的对象或派生类名访问; 基类的private成员不能在派生类中访问,也不能通过派生类的对象或派生类名访问; 基类的protected成员只能在基类和派生类中访问,不过在派生类中不能通过基类的对象访问。,6.2.1 继承的语法(续),思考题: using System; class A p
8、rivate int i=0; protected int j=0; public int k=0; protected static int 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、/错误,在所属类外不能访问私有成员 2、/正确,派生类中可以直接访问基类的保护成员 3、/正确,派生类中可以直接访问基类的公共成员 4、/正
9、确,派生类中可以直接访问基类的保护成员 5、/错误,派生类中不能通过基类对象访问基类的保护成员 6、 /正确,派生类中可以通过该类对象访问基类的保护成员 7、 /正确,派生类中可以通过基类名访问基类的静态保护成员 8、/正确,派生类中可以通过该类的类名访问基类的静态保护成员,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、正确,公共成员可以在任何地
10、方访问,6.2.1 继承的语法(续),当派生类与基类的定义在同一程序集时 基类的internal成员和基类的public成员类似 基类的protected internal成员与基类的protected成员的类似 当派生类与基类的定义不在同一程序集时 基类的internal成员不能在位于另一个程序集的派生类中访问,也不能通过该派生类的对象或派生类名访问; 基类的protected internal成员只能在所属程序集及所属类的派生类中访问,不能通过位于另一个程序集的派生类对象或派生名在派生类外访问,也不能在位于另一个程序集的派生类中通过基类对象访问。,6.2.2 派生类的构造函数,派生类不能继
11、承基类的构造函数。因此,创建派生类对象时,为了初始化从基类中继承来的字段,系统需要调用其基类构造函数。 例6-2 调用基类的默认构造函数,源代码,运 行,/例6-2 调用基类的默认构造函数,using System; public class People public People() Console.WriteLine(调用People的构造函数); public class Teacher : People public Teacher() Console.WriteLine(调用Teacher的构造函数); ,public class Professor : Teacher publi
12、c Professor() Console.WriteLine(调用Professor的构造函数); public static void Main() Professor p = new Professor(); ,6.2.2 派生类的构造函数(续),C#编译器虽然会自动在派生类构造函数中插入对基类构造函数的调用,但它调用的是基类的默认构造函数。 如果基类中没有默认构造函数或者希望调用带参数的基类构造函数,就要使用关键字base来显式调用基类构造函数。语法如下: base(参数); 例6-3 显式调用基类的构造函数,using System; public class Airplane pr
13、ivate int speed; public Airplane(int s) speed = s; Console.WriteLine(调用构造函数Airplane(int s); public class Warplane : Airplane public Warplane() : base(600) Console.WriteLine(调用构造函数Warplane(); public Warplane(int s) : base(s) Console.WriteLine(调用构造函数Warplane(int s); ,public class Fighter : Warplane pu
14、blic Fighter() : base() /可省略base() Console.WriteLine(调用构造函数Fighter(); public Fighter(int s) : base(s) Console.WriteLine(调用构造函数Fighter(int s); public static void Main() Console.WriteLine(创建对象:Fighter f1=new Fighter(); Fighter f1 = new Fighter(); Console.WriteLine(n创建对象:Fighter f2=new Fighter(500); Fi
15、ghter f2 = new Fighter(500); ,6.2.2 派生类的构造函数(续),使用关键字base调用基类构造函数的调用表达式只允许出现在构造函数的函数头之后,不能出现在函数体内。 例: public Fighter(int s) base(s); /错误 Console.WriteLine( 调用构造函数Fighter(int s) ); ,6.2.2 派生类的构造函数(续),调用基类构造函数时传递的参数不能是关键字this或当前对象的非静态成员,因为此时当前对象还没有创建完成。 例: public class A private int i; public A(int a)
16、 i = a; public class B : A private int j; public B(): base(j) /错误 j = 10; ,6.2.3 结构与继承,结构不支持继承,但可以实现接口。 所有的结构都是隐式从ValueType类直接或间接派生出来的,而ValueType类又是从Object类派生出来的。但C#语言不允许程序员声明一个继承于结构的类,也不允许声明一个继承于结构的结构或继承于类的结构。 结构成员不能用protected internal和protected修饰。,6.3 重写与隐藏,派生时,如果某个基类成员不能满足派生类的需要,可以在派生类中改写。C#语言中,基
17、类成员的改写有重写与隐藏两种方式。 6.3.1 重写基类成员 6.3.2 隐藏基类成员,6.3.1 重写基类成员,只有虚拟方法成员可以重写。 要将某个方法显式声明为虚拟方法需要使用关键字virtual,而要重写某个虚拟方法则必须使用关键字override显式声明。 方法重写时,派生类中的方法应该与基类中被重写的方法有相同的方法名、返回值类型、参数列表和访问权限。,6.3.1 重写基类成员(续),如果某个类中的一个方法是其基类的重写方法,那么该方法也就隐式成为一个虚拟方法(该方法不能使用关键字 virtual 显式声明)。 例: class A public virtual void Metho
18、d() class B:A public override void Method() /隐式成为一个虚拟方法 class C:B public override void Method(),6.3.1 重写基类成员(续),派生类无法调用基类的私有方法,也就没有所谓的派生类对基类私有方法的重写,因此,类的私有方法不能声明为虚拟的。 类的静态方法不能声明为虚拟的。 例6-4 重写虚拟方法,/TestOverride.cs using System; public class A private int i; public virtual int I/虚拟方法 getreturn i; seti=
19、value; ,public virtual void Method() /虚拟方法 Console.WriteLine(Method() in A); Console.WriteLine(i=0, i); public virtual void Method(int i) /虚拟方法 Console.WriteLine(Method(int i) in A); Console.WriteLine(i=0, i); ,public class B:A private int i; public override int I/重写方法 getreturn i; seti=value; publi
20、c override void Method()/重写方法 Console.WriteLine(Method() in B); Console.WriteLine(i=0,i); ,public void Print() base.I = 10;/使用基类的属性 I = 20; base.Method(); /调用基类的方法 Method(); base.Method(30); /调用基类的方法 Method(30); public static void Main() B b = new B(); b.Print(); ,6.3.2 隐藏基类成员,如果没有使用关键字overridie,只是在
21、派生类中定义一个与基类同名的方法,派生类中的方法将隐藏基类的中的同名方法。例: public class A public virtual void Method() / public void Method() Console.WriteLine(“Method() in A”); public class B:A public void Method() Console.WriteLine(“Method() in B”); 编译器会给出警告信息.,6.3.2 隐藏基类成员,成员隐藏并不局限于方法成员,它也能用于数据成员和内部数据类型。 使用关键字new隐藏基类成员时并不要求基类中的成员是
22、虚拟的。它通常用于改写基类中的非虚拟方法。 例6-5 隐藏基类成员,源代码,运 行,例6-5 隐藏基类成员,/TestNew.cs using System; public class A public int I; public void Method() Console.WriteLine(Method() in A); Console.WriteLine(I=0, I); ,public class B:A public new int I; /使用关键字new隐藏基类成员 public new void Method() /使用关键字new隐藏基类成员 Console.WriteLin
23、e(Method() in B); Console.WriteLine(I=0,I); ,public void Print() base.I = 10; I = 20; base.Method(); Method(); public static void Main() B b = new B(); b.Print(); ,6.3.2 隐藏基类成员(续),关键字base代表的是当前派生类对象中的基类子对象,因此,通过它可以访问基类成员。不过,与关键字this相同,关键字base只能用在实例方法中。,6.4 引用类型转换,一个类的对象在一定条件下可以转换成继承链中的另一个类的对象: 一个派生类
24、对象的类型可以向上转换成它的基类类型,这种转换是安全的,C#编译器能隐式进行。 一个基类对象的类型一般不能向下转换成它的派生类类型。但有一种情况除外,如果一个基类对象引用实际引用的是一个派生类对象,就可以使用显式转换将这个基类对象转换成派生类类型。,6.4 引用类型转换(续),显式引用类型转换的一般语法形式与数值类型相同。 例: class A class B:A class C:B A a1=new B(); /隐式转换 A a2=new C(); /隐式转换 B b1=(B)a1; /显式转换 B b2=(B)a2; /显式转换 C c1=(C)a1;/错误,不能转换,否则引发异常 C c
25、2=(C)a2; /显式转换 ,6.4 引用类型转换(续),将一个基类对象的类型转换成它的派生类类型时,必须确保其引用实际引用是该派生类的一个对象,否则会引发异常。为了防止这种情况发生,可以使用运算符is或as。,6.4 引用类型转换(续),运算符is的作用是检查某个表达式值的实际类型是否是某个指定的值类型、引用类型,或者派生于某个指定的类、实现了某个指定的接口,又或者由某个指定值类型装箱而来。如果是,且该对象不为null,则返回true,否则返回false。其语法形式如下: 表达式 is 数据类型 例: b1 is A/true a1 is B /true a1 is C/false 5 i
26、s int /true,6.4 引用类型转换(续),使用运算符as可以将某个表达式的值转换成指定的引用类型,而且转换时,自动完成运算符is所作的检查。如果运算符as检测到不能进行转换,表达式的结果就为null,不会引发异常。其语法形式如下: 表达式 as 数据类型 运算符as不能用于将某个表达式的值转换为值类型。 例: C c1=a1 as C; /正确 int i= 2.4 as int; /错误,例6-6 引用类型转换,/TestObjectCast.cs using System; class Airplane private int speed = 500; public int Sp
27、eed get return speed; set speed = value; ,class Warplane : Airplane private int missileNumber = 8; public int MissileNumber get return missileNumber; set missileNumber = value; class Fighter : Warplane public void Print() Console.WriteLine(It is a fighter!); ,class TestObjectCast public static void
28、Main() Airplane p1 = new Warplane(); Airplane p2 = new Fighter(); Warplane w1, w2; Fighter f1, f2; p2.Speed = 600; if (p1 is Warplane) Console.WriteLine(p1引用的是一个Warplane对象); w1 = (Warplane)p1; Console.WriteLine(w1.speed=0tw1.missileNumber=1n,w1.Speed, w1.MissileNumber); else Console.WriteLine(p1引用的不
29、是一个Warplane对象n);,if (p2 is Warplane) Console.WriteLine(p2 引用的是一个Warplane对象); w2 = (Warplane)p2; w2.MissileNumber = 12; Console.WriteLine(w2.speed=0tw2.missileNumber=1n,w2.Speed, w2.MissileNumber); else Console.WriteLine(p2引用的不是一个Warplane对象n); if (f1 = p1 as Fighter) != null) Console.WriteLine(p1引用的是
30、一个Fighter对象); f1.Print(); Console.WriteLine(); else Console.WriteLine(p1引用的不是一个Fighter对象n);,if (f2 = p2 as Fighter) != null) Console.WriteLine(p2引用的是一个Fighter对象); f2.Print(); else Console.WriteLine(p2引用的不是一个Fighter对象); ,6.5 多态与动态绑定,通过方法重写可以在具有继承关系的多个类中定义名称相同但操作不同的多个方法,多态指的正是程序运行时判断执行其中哪个方法代码的能力。 例6-
31、7 多态,源代码,运 行,例6-7 多态,using System; public class Animal public virtual void Speak() Console.WriteLine(Animal speak.); public class Dog : Animal public override void Speak() Console.WriteLine(Bowwow.); ,public class Cat : Animal public override void Speak() Console.WriteLine(Meow.); public class TestP
32、olymorphism public static void MakeSpeak(Animal a) a.Speak(); public static void Main() Cat c = new Cat(); Dog d = new Dog(); MakeSpeak(c); MakeSpeak(d); ,6.5 多态与动态绑定(续),C#语言的多态性是通过动态绑定实现的。所谓绑定是指建立方法调用语句和方法之间的关系,而动态绑定是指在程序运行时,根据对象的实际类型调用相应的方法。 应用多态,可使程序具有良好的可扩充性。,6.5 多态与动态绑定(续),C#语言中,所有方法默认都是非虚拟的。非虚
33、拟方法的调用在编译时绑定(即静态绑定),因此,调用非虚拟方法时,实际执行的总是用于调用的对象引用类型中定义(或其从基类继承来的)的方法。 虚拟方法的调用是动态绑定的,当通过某个对象引用调用一个虚拟方法时,程序运行时会根据该引用实际引用的对象类型,按继承链从对象引用类型到实际对象类型顺序搜索其重写方法,最终执行的是最后找到的重写方法。,6.5 多态与动态绑定(续),成员隐藏不支持多态。 静态方法不能声明为虚拟的,静态方法也不能是重写的。 重写方法不能同时是隐藏方法。不过,虚拟方法可以同时是隐藏方法,虚拟的隐藏方法允许在派生类中重写。 例6-8 方法隐藏与多态,源代码,运 行,例6-8 方法隐藏与
34、多态,using System; class A public virtual void Method() Console.WriteLine(Method in A); class B : A public override void Method() Console.WriteLine(Method in B); class C : B public new void Method() Console.WriteLine(Method in C); ,class TestNew1 public static void Main() A a1 = new A(); A a2 = new B(
35、); A a3 = new C(); a1.Method(); a2.Method(); a3.Method(); ,6.6 抽象类和抽象方法,抽象方法一种虚拟方法。 抽象方法只有方法头,没有具体的方法体。定义抽象普通方法的语法形式为: abstract 返回值类型 方法名(形式参数); 定义属性等特殊方法为抽象方法的语法为: abstract 返回值类型 属性名 get; set; ,6.6 抽象类和抽象方法,其中abstract是声明抽象方法的关键字 例: abstract void Method(); abstract int Weight get; set; ,6.6 抽象类和抽象方法
36、(续),含有抽象方法的类是抽象类,抽象类必须使用关键字abstract修饰。不过,一个抽象类并不一定拥有抽象方法。 例: abstract class A public void Method() 注意:抽象类只能用作其他类的基类,不能创建其对象。,6.6 抽象类和抽象方法(续),继承于抽象类的类一般应该实现抽象类中的所有抽象方法(重写)。 如果没有,那么该派生类也就成为抽象类,必须使用关键字abstract修饰。,6.6 抽象类和抽象方法(续),abstract class A public abstract void MethodA(); class B : A/错误,B或声明为抽象的,或
37、实现A类的抽象方法 public void MethodB() class C : A public override void MethodA() ,6.6 抽象类和抽象方法(续),静态方法不能声明为抽象的。 私有方法不能声明为抽象的。 例6-9 抽象类和抽象方法,源代码,运 行,例6-9 抽象类和抽象方法,using System; public abstract class Animal public abstract void Speak(); public class Dog : Animal public override void Speak() Console.WriteLin
38、e(Bowwow.); public class Cat : Animal public override void Speak() Console.WriteLine(Meow.); ,public class AbstractClassMethod public static void MakeSpeak(Animal a) a.Speak(); public static void Main() Cat c = new Cat(); Dog d = new Dog(); MakeSpeak(c); MakeSpeak(d); ,6.7 密封类、密封方法和静态类,用关键字sealed修饰的
39、类为密封类。 密封类不能被其他类继承。 例 sealed class A class B : A /错误 因为密封类不能被继承,因此,其中的方法不能声明为虚拟或抽象的,否则就违背了声明密封类的初衷。,6.7 密封类、密封方法和静态类(续),用关键字sealed修饰的方法就是密封方法。 密封方法不能在派生类重写。 将某个方法声明为密封的是为了说明该方法不能被重写,因此,密封方法应该同时是一个重写方法,关键字sealed必须和override在方法声明时同时出现。,6.7 密封类、密封方法和静态类(续),public abstract class A public abstract void Me
40、thod(); class B:A public sealed override void Method() Console.WriteLine(在类B中重写); ,6.7 密封类、密封方法和静态类(续),class C:B public override void Method()/错误,不能重写 Console.WriteLine(在类C中重写); public new void Method()/正确,可以隐藏 Console.WriteLine(在类C中重写); ,6.7 密封类、密封方法和静态类(续),静态类既不能被继承,也不能创建其对象,其中所有成员都应是静态的。 static c
41、lass A public static int i; public void Method() /错误,6.8 接 口,接口是一种抽象的数据类型,可以把每个接口都理解为是一个契约,其中约定了实现接口的对象必须实现的方法,其目的就是让这些方法可以作为接口实例被引用。 利用接口,可以间接实现多继承。 6.8.1 定义接口 6.8.2 实现接口 6.8.3 显式实现接口,6.8.1 定义接口,接口中定义的成员可以是方法、属性、索引器和事件,但不能是字段、常量、构造函数、析构函数、运算符和内部数据类型,而且不能包含任何静态成员。 接口本身并不提供它所定义成员的具体实现,它只是指定了实现该接口的类或结
42、构必须实现的成员。,6.8.1 定义接口(续),接口定义的一般语法: interface ITest int X get; set; void Method(); ,6.8.1 定义接口(续),接口中定义的成员的访问权限总是公共的,不过接口成员前一般不能有任何修饰符。但如果一个接口是另一接口的派生接口时,成员前可以使用关键字new显式声明某成员隐藏了基接口中的成员。 通过继承,可以在现有接口的基础上定义派生接口。不过,与类不同,一个接口可以同时继承多个接口。,6.8.1 定义接口(续),例: public interface IA void Method1(); public interfac
43、e IB void Method2(); public interface IC : IA void Method3(); public interface ID : IB,IC void Method4(); new void Method3();/隐藏 ,6.8.1 定义接口(续),除内部接口外,接口的访问权限只能是public或internal(默认)。内部接口的访问权限则可以是public、internal、protected internal 、protected 或private(默认)。 可以将接口想像成一个更纯粹的抽象类,不过,抽象类中还可以包含字段和具体方法等。在使用上,接口
44、与抽象类有许多相似之处。比如,不能创建接口的对象,可以用作变量的数据类型,可以用作对象转换的类型,等等。,6.8.2 实现接口,接口中的所有方法都要靠使用接口的类或结构实现。但是与抽象方法不同,接口中的方法并不是虚拟方法,实现时不能使用关键字override。不过,它同样具有多态性。 例6-10 实现接口,源代码,运 行,using System; public interface IAnimal int Age get; set; void Speak(); public class Cat : IAnimal/实现接口 private int age; public int Age/实现接
45、口中的属性 get return age; set age = value; 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
46、) a.Speak(); 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 实现接口(续),如果一个类实现了某个接口,这个接口就相当于它的基类,派生类对象类型和接口类型可以相互转换。 实现接口中的方法时,必须用public修饰。 接口中的方法不是虚拟方法,实现时不能使用关键字override。因此,实现接口的类被继承时,默认情况下,派生类中不能重写该类中
47、实现的接口成员。如果希望这个类中实现的某个接口成员可以被重写,应该将它显式声明为虚拟的。 当然,如果是一个结构实现某接口,其中实现的方法就不能使用virtual修饰,因为结构不能被继承。,6.8.2 实现接口(续),如果某个接口方法没有被实现,实现类中必须将它声明为抽象的,该类当然也必须声明为抽象的。例: interface IMsg void Message(); public abstract class MyClass : IMsg public abstract void Message(); 注意:使用结构实现接口时,结构必须实现接口中所有方法,6.8.2 实现接口(续),C#语言中
48、,为了得到多继承的效果,允许在一个类中实现多个接口,甚至,还允许同时继承一个类。 例6-11 间接多继承,源代码,运 行,using System; interface IA void Method1(); interface IB void Method2(); class C public virtual void Method3() Console.WriteLine(Method3() in C); ,class D : C, IA, IB public void Method1() Console.WriteLine(Method1() in D); public void Meth
49、od2() Console.WriteLine(Method2() in D); public override void Method3() Console.WriteLine(Method3() in D); ,public class MultiExtends static void RunMethod1(IA a) a.Method1(); static void RunMethod2(IB b) b.Method2(); static void RunMethod3(C c) c.Method3(); public static void Main() D d = new D();
50、RunMethod1(d);/自动类型转换,多态 RunMethod2(d);/自动类型转换,多态 RunMethod3(d);/自动类型转换,多态 ,6.8.2 实现接口(续),在间接实现多继承时,可能遇到下列问题 interface IA void Method(); interface IB int Method(int i); class C public void Method() class D : C, IA,IB public int Method(int i) return i; ,6.8.2 实现接口(续),在类D中 接口IA中的方法void Method()由继承过来的类
51、C的public void Method()实现,当然也可在类D中重新定义方法隐藏它。 接口IB中的方法void Method(int i)直接实现。,6.8.2 实现接口(续),要同时实现下述接口必须使用显式方式 interface IA void Method(); interface IB int Method(); ,6.8.3 显式实现接口,一个实现接口的类也可以显式实现接口中的方法。 例: interface IA void Method(); interface IB int Method(); class C : IA,IB int IB.Method() return 0;
52、void IA.Method() ,6.8.3 显式实现接口(续),显式实现接口方法时,方法名前必须使用接口名限定,而且该方法一定是公共的,不需要也不能使用任何访问权限修饰符修饰。 显式实现的方法被排除在类的公共成员之外,不能通过类的对象调用,必须通过相应接口的对象调用。 显式实现的方法不能声明为虚拟的。,6.8.3 显式实现接口(续),例: interface IA int Sum(int x1,int x2); class B:IA int IA.Sum(int x1,int x2) return x1+x2; class TestB static void Main() B b1 = n
53、ew B(); int sum1=b1.Sum(2,5); /错误,显式实现的方法不能通过类对象调用 IA ia = new B(); int sum2=ia.Sum(2,5); /正确,显式实现的方法必须通过接口对象调用 ,6.8.3 显式实现接口(续),显式接口成员没被声明为public,这是因为这些方法都有着双重的身份。当在一个类中使用显式接口成员时,该方法被认为是私有方法,因此不能用类的实例调用它。但是,当将类的引用转型为接口引用时,接口中定义的方法就可以被调用,这时它又成为了一个公有方法。,课堂练习:输出结果,using System; public interface IPartA
54、 void SetDataA(string dataA); public interface IPartB:IPartA void SetDataB(string dataB); ,public class SharedClass :IPartB private string DataA; private string DataB; public void SetDataA(string dataA) DataA = dataA; Console.WriteLine(0, DataA); public void SetDataB(string dataB) DataB = dataB; Con
55、sole.WriteLine(0, DataB); ,class test static void Main() SharedClass a = new SharedClass(); a.SetDataA(interface IPartA); a.SetDataB(interface IPartB); ,6.9 Object类,System.Object类是.NET框架的根类,C#语言中,所有的类或结构都直接或间接继承于它。 6.9.1 Equals方法 6.9.2 ToString方法,6.9.1 Equals方法,用于比较两个对象是否相等,它有两种定义形式: public virtual
56、bool Equals (Object obj) /判断指定的obj对象是否等于当前对象 public static bool Equals (Object objA, Object objB) /判断指定的objA 和objB对象是否相等 说明: 静态方法Equals(object objA,object objB)首先检查两个对象objA和objB是否都为null,如果是则返回true,否则进行objA.Equals(objB)调用并返回其值。 实例方法Equals(object obj) 缺省的实现其实就是return this= =obj;也就是判断两个对象是否引用相等。,6.9.1
57、Equals方法,对于值类型,Equals方法判断对象所包含的值是否相等。 对于引用类型,Equals方法默认情况下支持引用相等。如果需要使用Equals方法判断两个引用类型对象是否值相等,必须在派生类中重写上述虚拟Equals方法。 需要注意的是如果我们重写了某类型的实例方法Equals(object obj),也应该重写实例方法GetHashCode()。否则可能引发异常。,6.9.1 Equals方法(续),重写Equals方法时应该保证: x.Equals(x) 都返回true。 x.Equals(y) 返回与 y.Equals(x) 相同的值。 如果 (x.Equals(y) struct Point1 int x, y; public Point1(int x, int y) this.x = x; this.y = y; class Point2 int x, y; public Point2(int x, int y) thi
温馨提示
- 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
- 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
- 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
- 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
- 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
- 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
- 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。
最新文档
- 涂料运输安全代理合同
- 生产运作诊断
- 二零二五年度信息安全人工费用咨询与风险防范合同
- 2024深圳市新鹏职业高级中学工作人员招聘考试及答案
- 2024济宁市兖州区职业中等专业学校工作人员招聘考试及答案
- 2024湖南省茶陵县职业中等专业学校工作人员招聘考试及答案
- 餐饮店铺租房合同
- 管理学讲座直播课件
- 房屋转租合同标准版
- 计算机配件采购协议合同
- 2025年从大模型、智能体到复杂AI应用系统的构建报告-以产业大脑为例-浙江大学(肖俊)
- 厂房电费收租合同范例
- 2024年南京市事业单位专项招聘退役大学生士兵笔试真题
- 2025年浙江省金华市中考一模数学模拟试题(含答案)
- 外研版(2025新版)七年级下册英语期中复习:Unit 1~3+期中共4套学情调研测试卷(含答案)
- MOOC 计算机组成与CPU设计实验-江苏大学 中国大学慕课答案
- 第一次月考测试卷(试题)-2023-2024学年人教版六年级数学下册
- 生产车间5S稽核评分表
- (高清正版)T_CAGHP 066—2019危岩落石柔性防护网工程技术规范(试行)
- 超星尔雅学习通《婚恋职场人格(武汉理工大学)》章节测试附答案
- 家庭卫士使用说明书智能插座
评论
0/150
提交评论