《定义类-继承》PPT课件.ppt
第九章 定义类,继承专题,课程回顾,类的定义方法类的定义方法同结构体类似,只是类是使用class关键字进行定义的。,class 类型名 成员名1;类型名 成员名2;返回值类型 成员函数名(参数列表)/.,课程回顾,类的使用在 C#中,我们使用 new 运算符来创建类的对象。,类名 对象名=new 类名();,课程回顾,构造函数构造函数是指在创建类的对象时自动执行的函数,由它负责对类的对象进行初始化。构造函数其实就是定义这样的函数,它的名字与类的名字相同,并且不用定义返回类型,因为构造函数是不能返回值的。构造函数是一种强制性的约定,在创建类的对象时会自动调用它。,课程回顾,构造函数的定义,class(参数列表)/在这里初始化类的对象!,课程回顾,构造函数定义示例,class MyClass public MyClass()Console.WriteLine(“MyClass created!”);class Program static void Main(string args)MyClass myClass=new MyClass();,MyClass created!,课程回顾,带参数的构造函数,class MyClass public MyClass(string name)Console.WriteLine(“Hello,0!”,name);class Program static void Main(string args)MyClass myClass=new MyClass(“somebody”);,Hello,somebody!,课程回顾,构造函数的重载,class MyClass public MyClass()Console.WriteLine(“Hello!”);public MyClass(string name)Console.WriteLine(“Hello,0!”,name);class Program static void Main(string args)MyClass myClass=new MyClass();MyClass myClass=new MyClass(“somebody”);,Hello!Hello,somebody!,课程回顾,构造函数的强制性如果类中定义了构造函数,就必需在创建类的对象时使用适当的参数来调用它。,class MyClass public MyClass(string name)Console.WriteLine(“Hello,0!”,name);class Program static void Main(string args)/!MyClass myClass=new MyClass();,课程回顾,构造函数的强制性如果类中定义了构造函数,就必需在创建类的对象时使用适当的参数来调用它。,class MyClass public MyClass(string name)Console.WriteLine(“Hello,0!”,name);class Program static void Main(string args)MyClass myClass=new MyClass(“test”);,课程回顾,构造函数总结 C#中如果没有定义构造函数则系统会提供一个缺省构造函数,但一旦类中提供了自定义的构造函数,则缺省构造函数将不会被提供,这一点要注意。,面向对象的关键特性继承,“继承”这个词的字面含义是:按照法律或遵照遗嘱接受死者的财产、职务、头衔、地位等。面向对象方法中的继承与现实世界中的继承的意义基本相同,是指一个类完全继承了另一个类的所有内容(除私有成员),如字段、成员函数等。继承是一种父母与孩子的关系,孩子从父母那继承了一些父母的特点,并也有着与父母的不同之处。,课程内容回顾,继承关系中各类的地位和名称,父类、超类、基类,子类、派生类,我们通常把被继承的类称作基类,而把从基类继承出的新类称作派生类。,面向对象的关键特性继承,继承示例人与学生、教师、士兵之间的继承关系,父类、超类、基类,子类、派生类,课程内容回顾,继承的用法,class/父类定义class:/子类的定义,在定义派生类时,直接在派生类名字的后面跟上冒号并在其后写上基类的名字即可。,课程内容回顾,继承使用示例,class Base public string BaseString;class Derive:Base public string DeriveString;,在这个例子中,基类Base中有一个名为BaseString的字段,而派生类Derive中除含有其自身定义的DeriveString外,还包含从基类中继承来的BaseString字段。,课程内容回顾,继承使用示例,Base baseObj=new Base();baseObj.BaseString=“SomeString”;Derive deriveObj=new Derive();deriveObj.DeriveString=“SomeString”;/在这里还可以访问基类中定义的字段和方法deriveObj.BaseString=“Some”;Console.WriteLine(0,deriveObj.BaseString);Console.WriteLine(0,baseObj.BaseString);,注:父类对象却不能调用子类中新增的字段和方法,课程内容回顾,什么是继承继承是指子类自动共享父类的字段和方法的机制,这是类之间的一种关系。在定义和实现一个类的时候,可以在一个已经存在的类的基础之上来进行,把这个已经存在的类所定义的内容作为自己的内容,并加入若干新的内容。派生类从基类继承后,将通过类的继承关系,使基类的公共的特性能够被派生类所共享,提高了软件的重用性。,继承,面向对象的关键特性继承,继承的使用示例,class 人 public string 姓名;public string 年龄;public void 吃饭(食物 食物表)/.class 学生:人 public string 年级;public void 学习(string 书名)/.class 教师:人 public string 所在学校;pu blic void 授课(string 课程名)/.,面向对象的关键特性继承,继承的使用示例,class Program static void Main(string args)人 张三=new 人();张三.姓名=“张三”;张三.吃饭(new 食物/.);学生 李四=new 学生();李四.姓名=“李四”;李四.年级=“大二”;李四.吃饭(new 食物/.);,面向对象的关键特性继承,继承的使用示例(2),class 灯 public bool 打开的;public void 开()this.打开的=true;public void 关()this.打开的=false;class 可调亮台灯:灯 public int 亮度;pu blic void 调亮()this.亮度+;pu blic void 调暗()this.亮度-;,面向对象的关键特性继承,继承的使用示例(2),class Program static void Main(string args)灯 普通灯=new 灯();普通灯.开();可调亮台灯 台灯=new 可调亮台灯();台灯.开();台灯.调亮();,class A public int i,j;public void showij()Console.WriteLine(i and j:0 1,i,j);class B:A public int k;public void showk()Console.WriteLine(k:0,k);public void sum()Console.WriteLine(i+j+k:0,i+j+k);,static void Main(string args)A superOb=new A();B subOb=new B();superOb.i=10;superOb.j=20;Console.WriteLine(父类的i和j为:);superOb.showij();subOb.i=7;subOb.j=8;subOb.k=9;Console.WriteLine(子类的i和j为:);subOb.showij();subOb.showk();Console.WriteLine(子类中i,j,k的和为:);subOb.sum();,子类B包括它的父类A中的所有成员。这就是为什么subOb 可以获取i和j 以及调用showij()方法的原因。同样,sum()内部,i和j可以被直接引用。,继承的更多内容,找出下例中的问题,class Base public string BaseString;public Base(string baseString)BaseString=baseString;class Derive:Base public Derive()Console.WriteLine(“Create a Derive class instance!”);,继承的更多内容,错误原因分析,子类在创建对象执行构造函数之前会先执行父类中与之匹配的构造函数 在本例中 public Derive()/子类构造函数 与之匹配的基本构造函数应该是:public Base()而程序中只有public Base(string baseString)this.BaseString=baseString;所以错了,修改方法,class Program static void Main(string args)Derive cc=new Derive();class Base public string BaseString;public Base()public Base(string baseString)this.BaseString=baseString;class Derive:Base public Derive()Console.WriteLine(Create a Derive class instance!);,继承的更多内容,在哪调用基类Base的构造函数?使用base关键字调用基类的构造函数,如下:,class public()class:public():base(),继承的更多内容,使用base关键字解决之前的问题:,class Base public string BaseString;public Base(string baseString)this.BaseString=baseString;class Derive:Base public Derive():base(“someString”)Console.WriteLine(“Create a Derive class instance!”);,继承的更多内容,在构造基类时,也可以使用派生类构造函数的参数来调用基类的构造函数如:,class Base public string BaseString;public Base(string baseString)this.BaseString=baseString;class Derive:Base public Derive(string theString):base(theString)Console.WriteLine(“Create a Derive class instance!”);,继承的更多内容,static void Main(string args)string TheString=df;TheClass c=new TheClass(TheString);Console.WriteLine(0,c.TheString);class TheClass public string TheString;public TheClass(string TheString)TheString=TheString;,this的用法,this 关键字用来引用类的当前实例。也就是说,在建立对象后,我们就可以使用this来存取此对象。this的作用1、可以用来解决名称相同的问题。(限定被相似的名称隐藏的成员)2、将对象作为参数传递到其他方法3、在重载构造函数时,可使用this关键字来调用已有的构造函数,public class Employee public string name;public string alias;public double salary=3000.00;public Employee(string name,string alias)this.name=name;this.alias=alias;public void printEmployee()Tax t=new Tax();Console.WriteLine(Name:0nAlias:1,name,alias);Console.WriteLine(Taxes:0:C,t.CalcTax(this);,public class Tax public double CalcTax(Employee E)return(0.08*(E.salary);Main()Employee emp=new Employee(“jack”,”manager”);emp.printEmployee();,继承的更多内容,重载构造函数的相互调用在重载构造函数时,可使用this关键字来调用其他已有的构造函数(注:两个构造函数都会执行)用法如下:,class public()public():this(),继承的更多内容,重载构造函数的相互调用在重载构造函数相互调用示例,class TheClass public string TheString;public TheClass(string theString)this.TheString=theString;public():this(“none”),继承的更多内容,class Program static void Main(string args)student stu=new student();class student public string name;public int age;public student():this(jack,19)public student(string name,int age)this.name=name;this.age=age;Console.WriteLine(0,1,this.name,this.age);,占位符,在现实的生活中有时候需要特殊的表示字符,例如表示货币,时间,那该怎么办呢?不用担心,C#中有格式化标识符C或c Currency 货币格式 D或d Decimal 十进制格式(十进制整数,不要和.Net的Decimal数据类型混淆了)E或e Exponent 指数格式,占位符,F或f Fixed point 固定精度格式 G或g General 常用格式 N或n 用逗号分割千位的数字,比如1234将会被变成1,234 P或p Percentage 百分符号格式 R或r Round-trip 圆整(只用于浮点数)保证一个数字被转化成字符串以后可以再被转回成同样的数字 X或x Hex 16进制格式,占位符,static void Main(string args)int i=12345;Console.WriteLine(0:C,i);/货币 Console.WriteLine(0:D,i);/十进制数 Console.WriteLine(0:E,i);/科学技术法 Console.WriteLine(0:F,i);/浮点数表示法 Console.WriteLine(0:G,i);/G或g General 常用格式 Console.WriteLine(0:N,i);/N或n 用逗号分割千位的数字 Console.WriteLine(0:X,i);Console.WriteLine(0:P,i);,继承的更多内容,类型转换上传到基类对已有基类Base和派生类Derive,可以很容易的把Derive类型转换成Base类型,即可以把Derive类的对象当作Base类的对象来处理,我们称这种转换为上传,转换方法为:,派生类对象=new();基类对象=派生类对象;,Derive deriveObj=new Derive();Base baseObj=deriveObj;,在这里,由于派生类同时具有基类所有的特性和行为,所以在这里可以直接进行隐式的类型转换。,析构函数,析构函数(destructor)与构造函数相反,当对象脱离其作用域时(例如对象所在的函数已调用完毕),系统自动执行析构函数。析构函数往往用来做“清理善后”的工作(例如在建立对象时用new开辟了一片内存空间,应在退出前在析构函数中用delete释放)。,析构函数的特点,只能对类使用析构函数。一个类只能有一个析构函数。无法重载析构函数。无法调用析构函数。它们是被自动调用执行的。析构函数既没有修饰符,也没有参数。注意:构造函数和析构函数,在继承问题上,执行顺序正好相反,析构函数的声明,类 Car 的析构函数的声明class Car Car()/destructor/cleanup statements.,程序运行时,有继承关系的类的析构函数将自动被调用,并且是按照从派生程度最大的到派生程度最小的次序调用class First First()System.Console.WriteLine(Firsts destructor is called);class Second:First Second()System.Console.WriteLine(Seconds destructor is called);,class Third:Second Third()System.Console.WriteLine(Thirds destructor is called);class TestDestructors static void Main()Third t=new Third();,C#修饰符,C#修饰符 访问控制修饰符:指定类成员的可访问性。public:存取不受限制.private:只有包含该成员的类可以存取.internal:只有当前工程可以存取.protected:只有包含该成员的类以及继承的类可以存取.,C#修饰符,相关概念程序集 其实简单地说,程序集就是我们运行编译后产生的dll文件或者exe文件。它里面所包含的MSIL中间代码会在执行的时候,被CLR的JIT编译器根据本特定机器的实际情况进行特定的进一步优化,从而编译成相应的机器码。一个解决方案包括多个项目,一个项目包括多个文件。项目是跟程序集相对应的,一个项目就是一个程序集。,访问控制修饰符,访问控制修饰符用来控制类成员的访问级别类成员的访问级别是用来实现面向对象方法中的类的封装性的机制,可用其来隐藏类的内部细节。通过类成员的访问级别,可精确的控制字段或成员函数能被哪些代码所访问。类成员的访问级别有:public(公有的)private(私有的)protected(保护的)internal(内部的),类定义的更多内容,类成员的访问级别public(公有的)可访问级别为公有的属性或成员函数能被任意代码所访问,没有任何限制。,class MyClass public string Name;public void PrintName()Console.WriteLine(“Hello,0!”,Name);class Program static void Main(string args)MyClass myClass=new MyClass();myClass.Name=“Sombody”;myClass.PrintName();,类定义的更多内容,类成员的访问级别private(私有的)可访问级别为私有的属性或成员函数只能被该类的成员函数所访问。,class MyClass private string Name;private void PrintName()Console.WriteLine(“Hello,0!”,Name);class Program static void Main(string args)MyClass myClass=new MyClass();/!myClass.Name=“Sombody”;/!myClass.PrintName();,类定义的更多内容,类成员的访问级别protected(保护的)可访问级别为保护的属性或成员函数只能被该类的成员函数或子类所访问。,class Program static void Main(string args)SubClass myClass=new SubClass();/myClass.Name=Sombody;myClass.Test();/myClass.PrintName();class Base protected string Name;private void PrintName()Console.WriteLine(Hello,0!,Name);class SubClass:Base public void Test()Name=保护成员;Console.WriteLine(0在子类中,Name);/PrintName();,类定义的更多内容,类成员的访问级别internal 类型和类型成员的访问修饰符。只有在同一程序集的文件中,内部类型或成员才是可访问的。,public class Program static void Main(string args)SubClass myClass=new SubClass();/myClass.Name=Sombody;myClass.intel=internal成员变量可以在类外部使用;myClass.Test();myClass.PrintName();Console.WriteLine(myClass.intel);public class Base protected string Name;internal string intel;public void PrintName()Console.WriteLine(0在类的内部使用!,Name);public class SubClass:Base public void Test()Name=保护成员;Console.WriteLine(Name);/PrintName();,类定义的更多内容,static 使用 static 修饰符声明属于类本身而不是属于特定对象的静态成员。static 修饰符可用于类、方法、属性、运算符、事件和构造函数,但不能用于析构函数或类以外的类型。特点:1、不能通过实例引用静态成员。然而,可以通过类名引用它 static void Main(string args)Console.WriteLine(MyBaseC.x);public class MyBaseC public static int x=100;,2、不可以使用 this 来引用静态方法或属性。3、如果对类应用 static 关键字,则该类的所有成员都必须是静态的。4、类和静态类可以有静态构造函数。静态构造函数在程序开始和类实例化之间的某个时刻调用。,2、不可以使用 this 来引用静态方法或属性。static void Main(string args)MyBaseC c=new MyBaseC();Console.WriteLine(MyBaseC.x);c.sum();public class MyBaseC public static int x=100;public int y=90;public void sum()int z=this.y;Console.WriteLine(z);,3、如果对类应用 static 关键字,则该类的所有成员都必须是静态的。static void Main(string args)Console.WriteLine(MyBaseC.x);MyBaseC.sum();public static class MyBaseC public static int x=100;public static int y=90;public static void sum()int z=y;Console.WriteLine(z);,有一个表示公司雇员的类。假设该类包含雇员的基本信息和一个对雇员计数的方法和一个存储雇员总人数的字段。该方法和字段都不属于任何实例雇员,而是属于公司类。因此,应该将它们声明为此类的静态成员。此示例读取新雇员的姓名和 ID,将雇员计数器加一,并显示新雇员的信息和新的雇员总人数。为简单起见,该程序从键盘读取当前的雇员数。,public class Employee public string id;public string name;public Employee()public Employee(string name,string id)this.name=name;this.id=id;public static int employeeCounter;/雇员总人数 public static int AddEmployee()/计算雇员总人数 return+employeeCounter;,class program static void Main()Console.Write(Enter the employees name:);string name=Console.ReadLine();Console.Write(Enter the employees ID:);string id=Console.ReadLine();Employee e=new Employee(name,id);Console.Write(Enter the current number of employees:);string n=Console.ReadLine();Employee.employeeCounter=Int32.Parse(n);Employee.AddEmployee();Console.WriteLine(Name:0,e.name);Console.WriteLine(ID:0,e.id);Console.WriteLine(New Number of Employees:0,Employee.employeeCounter);,abstract abstract 修饰符可以和类、方法、属性、索引器及事件一起使用。在类声明中使用 abstract 修饰符以指示某个类只能是其他类的基类。标记为抽象或包含在抽象类中的成员必须通过从抽象类派生的类来实现。,抽象类:abstract 修饰类 如果一个类不与具体的事物相联系,而只是表达一种抽象的概念,仅仅是作为派生类的一个基类,这样的类就是抽象类,public abstract class oneClass public int i;public void denylau(),C#修饰符,抽象类与非抽象类(一般的类)的主要区别:抽象类不能直接被实例化抽象类中可以包含抽象成员,但非抽象类中不可以包含抽象成员抽象类不能被密封,当抽象类派生出子类(非抽象类)时,这些子类(非抽象类)必须具体实现所继承的所有抽象成员(重写抽象成员),C#修饰符,抽象方法 在抽象类中声明方法时,如果加上abstract时就是抽象方法特点:1、抽象方法必须声明在抽象类中 2、声明抽象方法时,不能使用virtual、static、private修饰符。3、在抽象类中抽象方法不提供实现。,abstract class ShapesClass abstract public int Area();class Square:ShapesClass int side=0;public Square(int n)side=n;public override int Area()return side*side;,static void Main(string args)Square sq=new Square(12);Console.WriteLine(Area of the square=0,sq.Area();,抽象类的作用,打个比方吧,定义一个平面图形类,他的面积是一个方法,但是因为不知道图形具体的样子(三角形,长方形,圆形),所以不能具体写出他的面积实现方法,就只能用抽象方法,具体实现交给子类(三角形,长方形,圆形)具体去实现,父类需要取值时直接找对应的子类就可以,提高了通用性,方便维护软件和减少代码的重复量,abstract class ShapesClass abstract public double Area();class Square:ShapesClass int side=0;public Square(int n)side=n;public override double Area()return side*side;,class 圆形:ShapesClass int r=0;public 圆形(int n)r=n;public override double Area()return 3.14*r*r;static void Main(string args)Square sq=new Square(12);Console.WriteLine(Area of the square=0,sq.Area();圆形 cir=new 圆形(3);Console.WriteLine(Area of the 圆形=0,cir.Area();,假如很多人要买水果吃,吃的动作只有一个,但是有的人要用现金买,有的人用信用卡,有的人赊帐。要为每个人定义一个类,就要定义多个相同的吃的方法。如果定义一个抽象类,在里面实现吃的方法,再做一个买的抽象方法。那每个人的类都从这个抽象类派生下来,只要实现买的方法即可,吃的方法就可以直接用父类的方法了。如果要改吃的方法就不用改多个,只要改这个抽象类里的就行了。,抽象类的作用,C#修饰符,override 提供从基类继承的虚拟成员的新实现。要扩展或修改继承的方法、属性、索引器或事件的抽象实现或虚实现,必须使用 override 修饰符。,C#修饰符,virtual 在派生类中声明其实现可由重写成员更改的方法或访问器。virtual 关键字用于修饰方法、属性、索引器或事件声明,并且允许在派生类中重写这些对象。调用虚方法时,将为重写成员检查该对象的运行时类型。将调用大部分派生类中的该重写成员,如果没有派生类重写该成员,则它可能是原始成员。默认情况下,方法是非虚拟的。不能重写非虚方法。virtual 修饰符不能与 static、abstract 和 override 修饰符一起使用。除了声明和调用语法不同外,虚拟属性的行为与抽象方法一样。在静态属性上使用 virtual 修饰符是错误的。通过包括使用 override 修饰符的属性声明,可在派生类中重写虚拟继承属性,继承:注意要点,public,internal,protected修饰的字段或方法都将被派生类继承,private不被继承只能从一个类中继承,不能同时从多个类继承。不过,继承可传递,也就是派生类也可以作为基类被其他类继承。构造函数和析构函数不能被继承。,静态,msdn,重写,