一、继承
在C#语言中实现继承非常容易,只需要用:符号即可完成类之间继承的表示。
表达形式:
访问修饰符classClassA:ClassB{//类成员}
例:
publicclassA:B{intb=0;}
其中:
访问修饰符:包括public、internal。
ClassA:称为子类、派生类,在子类中能直接使用ClassB中的成员。
ClassB:称为父类、基类。
注意:
一个类只能有一个父类,但是一个父类可以有多个子类,并且在C#语言中继承关系具有传递性.
即A类继承B类、C类继承A类,则C类也相当于继承了B类。
二、base关键字:调用父类成员方法
在C#语言中子类中定义的同名方法相当于在子类中重新定义了一个方法,在子类中的对象是调用不到父类中的同名方法的,调用的是子类中的方法。因此也经常说成是将父类中的同名方法隐藏了。
在继承的关系中,子类如果需要调用父类中的成员可以借助base关键字来完成。
表达形式:
base.父类成员
如果在同名的方法中使用base关键字调用父类中的方法,则相当于把父类中的方法内容复制到该方法中。
(总之就是,在继承父类后,如果子类中修改父类的成员,却又想获取父类成员,就使用base.父类成员这个方式调用父类成员)
1.例:
首先编写三个类Person、Teacher以及Student类。
classPerson{publicintId{get;set;}publicvoidPrint(){Console.WriteLine("编号:"+Id);}}classTeacher{publicintId{get;set;}publicvoidPrint(){Console.WriteLine("编号:"+Id);}}classStudent{publicintId{get;set;}publicvoidPrint(){Console.WriteLine("编号:"+Id);}}
然后创建对象并调用一下。(作为对比)
classProgram{staticvoidMain(string[]args){//Personperson=newPerson();Console.WriteLine("Person类的Print方法打印内容");person.Print();//Studentstudent=newStudent();Console.WriteLine("Student类的Print方法打印内容");student.Print();//Teacherteacher=newTeacher();Console.WriteLine("Teacher类的Print方法打印内容");teacher.Print();}}
改写实例1中的Student和Teacher类中同名的Print方法,使用base关键字调用父类中的Print方法。
classPerson{publicintId{get;set;}publicvoidPrint(){Console.WriteLine("编号:"+Id);}}classTeacher:Person{publicintId{get;set;}publicstringTitle{get;set;}publicvoidPrint(){base.Print();Console.WriteLine("职称:你选");}}classStudent:Person{publicintId{get;set;}publicvoidPrint(){base.Print();Console.WriteLine("专业:你看");}}
?
分析:
从整体上感觉很复杂,其主要目的就是:
在你修改同名成员方法时,会把父类的同名方法覆盖掉,而通过使用base.Print();就能把父类的方法中的内容保留,省去重新写了。
主要观察的是第一块和第三块的类,着重看的是类中的Print()方法。
提示:
用户在程序中会遇到this和base关键字,this关键字代表的是当前类的对象,而base关键字代表的是父类中的对象。
也就是说,this是本类中的自己。而base是父类中的内容。
三、virtual关键字
virtual是虚拟的含义。
在C#语言中,默认情况下类中的成员都是非虚拟的,通常将类中的成员定义成虚拟的,表示这些成员将会在继承后重写其中的内容。
virtual关键字能修饰方法、属性、索引器以及事件等,用到父类的成员中。
表达形式:
1)修饰属性publicvirtual数据类型属性名{get;set;}
例:
publicvirtualinta{get;set;}
2)修饰方法访问修饰符virtual返回值类型方法名{语句块;}
例:
publicvirtualvoidA{Console.WriteLine("编号:"+Id);}
总之可以理解成,无论你里面是什么内容,到最后被子类继承后都会被重写。
就当做是用来占位的吧!毕竟还要在子类中重写。
注意:
virtual关键字不能修饰使用static修饰的成员。
virtual关键字既可以添加到访问修饰符的后面,也可以添加到访问修饰符的前面,但实际应用中习惯将该关键字放到访问修饰符的后面。
四、重写override
子类继承父类后能重写父类中的成员,重写的关键字是override。
所谓重写是指子类和父类的成员定义一致,仅在子类中增加了override关键字修饰成员。
表达形式:
publicoverride数据类型方法名(){语句块;return整数类型的值;}
例:
//父类classA{publievirtualintA(intx,inty){returnx*y;}}//子类classB:A{publicoverrideintA(intx,inty){returnx/y;}}
在子类中重写父类中的方法后能改变方法体中的内容,但是方法的定义不能改变。
基本上还看不出有什么特别之处。
1.例
定义一个虚方法,然后再继承重写。
classPerson{publicvirtualvoidPrint(){Console.WriteLine("编号:"+Id);}}classStudent:Person{publicoverridevoidPrint(){Console.WriteLine("姓名:"+Name);}}
分析:
基本上就是追加了override关键字。
2.例
如果能在重写父类方法的同时直接使用父类中已经编写过的内容就会方便很多。在重写Print方法后仍然需要使用base关键字调用父类中的Print方法执行相应的操作。
classStudent:Person{publicoverridevoidPrint(){base.Print();Console.WriteLine("专业:"+Major);Console.WriteLine("年级:"+Grade);}}
分析:
不过重写父类的Print方法里的内容,再追加其他的内容。
不仅减少了代码的冗余,还增强了程序的可读性。
C#提倡在基类中使用virtual来标记要被重写的方法,在子类也就是派生类中用override关键字来修饰重写的方法。
就是用来标记用的,看样子。
五、方法的隐藏New
表达形式:
publicNew数据类型方法名(){语句块;}
例:
publicnewvoidPrint(){Console.WriteLine("B");}
1.例
classA{publicvirtualvoidPrint(){Console.WriteLine("A");}}classB:A{publicnewvoidPrint(){Console.WriteLine("B");}}classProgram{staticvoidMain(string[]args){Aa1=newB();Ba2=newB();a1.Print();a2.Print();}}
分析:
注意上面的第21~22行。
一个是父类A类型创建的对象B,一个是子类B类型创建的对象B。
所以这里进行了一个隐式类型转换。
也就是A类的输出,而这也是方法的隐藏的特性。
不会对父类定义的类型进行改变。
2.例
方法隐藏和重写方法的对比。
classA{publicvirtualvoidPrint(){Console.WriteLine("A");}}//方法的隐藏classB:A{publicnewvoidPrint(){Console.WriteLine("B方法的隐藏");}}//方法的重写classC:A{publicoverridevoidPrint(){Console.WriteLine("C方法的重写");}}
然后进行调用
classProgram{staticvoidMain(string[]args){Aa1=newB();Aa2=newC();a1.Print();a2.Print();Console.Read();}}
分析:
可以看出,这里都是以父类的类型进行定义的变量,结果却是这样。
也就是说,用New标注的,如果以父类类型进行定义声明,那就调出父类的内容。
但用Override标注的,却已经改写。
这里涉及到了多态,后续会接受。
六、强制转换
这里在“Aa1=newB()”语句中A类是父类、B类是子类,相当于将子类转换成父类,即隐式转换。
如果需要将父类转换成子类,则需要强制转换,并且在强制转换前需要先将所需的子类转换成父类,示例代码如下。
Aa2=newC();Cc=(C)a2;c.Print();
分析:
a2是父类对象,将其强制转换后,a2就成了子类对象。
结果一样,但类型变了。
1.例
由于Object类中有ToString方法,所以能直接被类重写。
并返回所需的字符串,通常将其用到类中返回类中属性的值。
classStudent{publicstringMajor{get;set;}publicstringGrade{get;set;}publicvoidPrint(){Console.WriteLine("专业:"+Major);Console.WriteLine("年级:"+Grade);}publicoverridestringToString(){returnMajor+","+Grade;}}
分析:
主要在第10行,即便没有继承,依旧可以改写ToString()方法。
此外,除了ToString方法,在类中也可以重写Equals方法、GetHashCode方法。
因为都是Object类中的方法。
七、abstract:声明抽象类或抽象方法
abstract关键字代表的是抽象的,使用该关键字能修饰类和方法,修饰的方法被称为抽象方法、修饰的类被称为抽象类。
在C#语言中抽象方法是一种不带方法体的方法,仅包含方法的定义。
表达形式如下。
访问修饰符abstract方法返回值类型方法名(参数列表);
例:
publicabstractvoidA();
其中,当abstract用于修饰方法时,也可以将abstract放到访问修饰符的前面。抽象方法定义后面的“;”符号是必须保留的。
需要注意的是,抽象方法必须定义在抽象类中。
抽象类的表达形式:
访问修饰符abstractclass类名{//类成员}
例:
publicabstractclassA{publicabstractvoidA();}
其中“abstract”关键字也可以放到访问修饰符的前面。在抽象类中可以定义抽象方法,也可以定义非抽象方法。通常抽象类会被其他类继承,并重写其中的抽象方法或者虚方法。
此外,尽管在抽象类中仍然能定义构造器,但抽象类不能实例化,即不能使用如下语句。
new抽象类的名称();
1.例
创建抽象类ExamResult,并在类中定义数学(Math)、英语(English)成绩的属性,定义抽象方法计算总成绩。
分别定义数学专业和英语专业的学生类继承抽象类ExamResult,重写计算总成绩的方法并根据科目分数的不同权重计算总成绩。其中,数学专业的数学分数占60%、英语分数占40%;英语专业的数学分数占40%、英语分数占60%。
abstractclassExamResult{//学号publicintId{get;set;}//数学成绩publicdoubleMath{get;set;}//英语成绩publicdoubleEnglish{get;set;}//计算总成绩publicabstractvoidTotal();}classMathMajor:ExamResult{publicoverridevoidTotal(){doubletotal=Math*0.6+English*0.4;Console.WriteLine("学号为"+Id+"数学专业学生的成绩为:"+total);}}classEnglishMajor:ExamResult{publicoverridevoidTotal(){doubletotal=Math*0.4+English*0.6;Console.WriteLine("学号为"+Id+"英语专业学生的成绩为:"+total);}}
分析:
首先是定义一个抽象类,作为父类。
然后创建两个子类,将抽象类重载。
总之可以把抽象类看成,没有语句块的方法。
然后在Main方法中分别创建MathMajor和EnglishMajor类的对象,并调用其中的Total方法,代码如下。
classProgram{staticvoidMain(string[]args){MathMajormathMajor=newMathMajor();mathMajor.Id=1;mathMajor.English=80;mathMajor.Math=90;mathMajor.Total();EnglishMajorenglishMajor=newEnglishMajor();englishMajor.Id=2;englishMajor.English=80;englishMajor.Math=90;englishMajor.Total();}}
分析:
创建两个子类对象,然后进行赋值和输出。
因为采取了get和set访问器,所以可以直接赋值。
而调用方法,也就正常调用。
在实际应用中,子类仅能重写父类中的虚方法或者抽象方法,当不需要使用父类中方法的内容时,将其定义成抽象方法,否则将方法定义成虚方法。
预览时标签不可点收录于话题#个上一篇下一篇