面向对象三大特征:封装、继承、多态
多态 通过继承实现的不同对象调用相同的方法,表现出不同的行为,称之为多态。
c#的多态性主要体现在类的继承上: 子类继承父类的时候,可能出现同名但方法定义不同的情况, 所以在子类中会将原方法覆盖,实现自身的要求
什么是方法签名?
方法签名由方法名称和一个参数列表(方法的参数顺序和类型)组成。并没有返回值和访问修饰符。
一、抽象类和抽象方法
抽象类:用关键字abstract来修饰的类称为抽象类;
作用:实现多态
总结:
1、抽象类中的方法不可以有方法体。
2、抽象类不能被实例化(不能new)
3、抽象方法不能被private修饰
4、有抽象方法或抽象属性的类一定是抽象类,抽象类中的属性或方法不一定都是抽象的
5、非抽象子类继承抽象类一定要重写父类中包含的所有抽象方法和抽象属性
6、抽象子类继承抽象类不一定要重写父类中包含的所有抽象方法和抽象属性
二、虚函数 关键字 virtual
虚方法:若一个实例方法声明前带有virtual关键字,那么这个方法就是虚方法
作用:虚方法就是可以被子类重写的方法,如果子类重写了虚方法,那么运行时将使用重写后的逻辑,如果没有重写,则使用父类中虚方法的逻辑,把一个基类函数声明为virtual,
该函数就可以在派生类中重写了:
总结:
1、虚方法的类可以被实例化
2、虚方法可以有方法体(抽象方法可以看成是一个没有方法体的虚方法)
三、接口
接口:接口是引用类型的,类似于类,interface修饰
(1) 接口不能被实例化
(2) 接口只能包含方法声明
(3) 接口的成员包括方法、属性、索引器、事件
(4) 接口中不能包含常量、字段(域)、构造函数、析构函数、静态成员
接口与抽象类两者的语法区别:
1.抽象类可以有构造方法,接口中不能有构造方法。
2.抽象类中可以有普通成员变量,接口中没有普通成员变量
3.抽象类中可以包含非抽象的普通方法,接口中的所有方法必须都是抽象的,不能有非抽象的普通方法。
4. 抽象类中的抽象方法的访问类型可以是public,protected,但接口中的抽象方法只能是public类型的,并且默认即为public abstract类型。
5. 抽象类中可以包含静态方法,接口中不能包含静态方法
6. 抽象类和接口中都可以包含静态成员变量,抽象类中的静态成员变量的访问类型可以任意,但接口中定义的变量只能是public static final类型,并且默认即为public static final类型。
7. 一个类可以实现多个接口,但只能继承一个抽象类。
8.接口可以用于支持回调,而继承并不具备这个特点. 9.抽象类实现的具体方法默认为虚的,但实现接口的类中的接口方法却默认为非虚的,当然您也可以声明为虚的.
抽象类和接口的使用:
1.如果预计要创建组件的多个版本,则创建抽象类。抽象类提供简单的方法来控制组件版本。 2.如果创建的功能将在大范围的全异对象间使用,则使用接口。如果要设计小而简练的功能块,则使用接口。 3.如果要设计大的功能单元,则使用抽象类.如果要在组件的所有实现间提供通用的已实现功能,则使用抽象类。 4.抽象类主要用于关系密切的对象;而接口适合为不相关的类提供通用功能。
5.好的接口定义应该是具有专一功能性的,而不是多功能的,否则造成接口污染。如果一个类只是实现了这个接口的中一个功能,而不得不去实现接口中的其他方法,就叫接口污染。
四、重写与重载
overload:重载指的是同一个类中有两个或多个名字相同但是参数不同的方法,(注:返回值不能区别函数是否重载),重载没有关键字。
override:重写是指子类对父类中虚函数或抽象函数的“覆盖”(这也就是有些书将过载翻译为覆盖的原因),但是这种“覆盖”和用new关键字来覆盖是有区别的。,关键字override
new:覆盖指的是不同类中(基类或派生类)有两个或多个返回类型、方法名、参数都相同,但是方法体不同的方法。
但是这种覆盖是一种表面上的覆盖,所以也叫隐藏,被覆盖的父类方法是可以调用得到的。
重载覆盖的发生条件:
重载,必然发生在一个类中,函数名相同,参数类型或者顺序不同构成重载,与返回类型无关
重写,必然发生在基类和派生类中,其类函数用virtual修饰,派生类用override修饰
覆盖,在子类中写一个和基类一样名字(参数不同也算)的非虚函数,会让基类中的函数被隐藏,编译后会提示要求使用New关键字
重载特征:
1、方法名必须相同
2、参数列表必须不相同,与参数列表的顺序无关
3、返回值类型可以不相同
重写特征:
1、由 override 声明重写的方法称为重写基方法,重写的基方法必须与 override 方法具有相同的方法名,与参数无关。
2、重写的基方法必须是 virtual、abstract 或 override 的,不能重写非虚方法或静态方法。
3、override的方法和virtual的方法必须具有相同的访问级别修饰符,不能更改 virtual 方法的可访问性。
4、不能使用new、static 或 virtual 修饰符来修改 override 方法。
5、重写属性声明必须指定与继承属性完全相同的访问修饰符、类型和名称,并且被重写的属性必须是virtual、abstract 或 override 的。
//抽象类
abstract class Eat { public abstract void see();//抽象方法 }
抽象类中的方法不可以有方法体。
//必须写成 public abstract void fly(); public abstract void fly(){};//报错 public abstract void fly(){ Console.WriteLine("Eat");};//报错
抽象类不能被实例化(不能new)
abstract class Eat { public abstract void see();//抽象方法 } Eat a = new Eat();//报错
抽象类中的属性或方法不一定都是抽象的
abstract class Eat { public abstract void see();//抽象方法 public abstract float Price { get; } //抽象属性 public string vendor { get; set; } //public void kill()//不加virtual 子类继承重写时会报错 // { // Console.WriteLine("kill"); // } public virtual void kill() { Console.WriteLine("kill"); } }
非抽象子类继承抽象类一定要重写父类中包含的所有抽象方法和抽象属性
abstract class Eat { public abstract void see();//抽象方法 public abstract float Price { get; } //抽象属性 public string vendor { get; set; } //public void kill()//不加virtual 子类继承重写时会报错 // { // Console.WriteLine("kill"); // } public virtual void kill() { Console.WriteLine("kill"); } } class A : Eat { public override void see() { Console.WriteLine("A"); } public override float Price { get { if (vendor == "抽象") return 1; else return 0; } } }