函数重写:被重写的父类函数必须是【虚方法或抽象方法】
函数必须相同(返回值、函数名、参数列表)
重写的函数的修饰符必须等于父类
重写的函数的返回值类型等于父类返回值
构造函数无法重写(因为构造函数无法继承)
虚方法,多态
多态两种 表现形式:用父类做参数;用父类做返回值。
多态就是对象可以表现多个类型的能力。
多态就是指不同对象收到相同消息时,会产生不同行为同一个类在不同的场合下表现出不同的行为特征。
多态的作用:把不同的子类对象都当作父类来看,可以屏蔽不同子类对象之间的差异,写出通用的代码,做出通用的编程,以适应需求的不断变化。
1.Person p=new Person(); Student s=new Student(); 子类对象赋值给父类,是符合里氏替换原则的。(编译的时候,CLR会自动检查看对象s的类是否有继承p对象的类,如果有,则允许赋值,如果没有,则报异常)。
父类对象不能直接赋值给子类(编译的时候CLR检查到p得类没有继承s的类,所以报异常);
从人类的思维的角度看:子类拥有父类所没有的成员,如果将父类转成子类,意味着子类的成员不能从父类获值。
不能用父类来实例化子类的变量的原因:因为声明的子类变量语法上是可以点出子类成员,但是父类对象里没有包含子类成员,那么根本就没法访问了。微软为了杜绝这种情况,直接编译报错。
=右边所创建的成员,少于=左边所允许访问的成员。
指向子类对象的父类变量可以强转成子类变量 通过的原因:尽管p1是父类变量,但是p1里保存的指针指向的堆空间里是子类对象。
=左边:叫声明变量,程序员可以按照变量的类型来写代码(可以.出来)
is和as
is关键字:可以用来判断引用类型的对象,如果是某个类,则返回true,否则返回false;如果用来判断值类型,则永远返回false
as关键字:(一般用来指向子类对象的父类变量转成子类变量)用在引用类型间转换,如果转换失败则返回null,但不会报错。
里氏替换原则 子类可以实例化父类(子类可以替换父类的位置)
讲父类转成子类需要强制转换,强制转换的时候 必须有直接继承关系才能完成强转。否则会出异常
当我们new 一个子类对象时,父类里被重写的方法就不存在了,对象中只有子类的重写方法。
多态:(由 里氏替换原则 和 方法重写 构成)
//父类 p = new 子类();
//多态 :
//1.声明一个父类 变量,不关心 具体创建的 对象 是哪个子类
//2.父类变量 调用 了一个 被子类重写的方法,那么这个方法的调用行为 就叫做多态。
Person duotai = new Girl();
duotai.SayHi();//一种 形态,多种表现形式(具体是通过 子类 重写父类 方法 来实现的)
开闭原则:设计原则。
7.1 对修改关闭:一旦代码“写完”,就不应该再修改源代码。
7.2 对扩展开放:即使代码“写完”,但只要通过修改配置文件,赋值新的程序集到指定位置等方式,就可以 为程序添加新的功能。
抽象方法
1.抽象类与抽象方法用abstract修饰。
2.抽象类和接口不能被new 出来,抽象方法不能有方法体。
3.抽象类和抽象方法存在的意义:
1.向子类形成一个规范(子类必须重写父类的抽象方法,除非子类也是抽象类。)
2.根本目的,是为了实现多态
4.尽管抽象类不能被new 但它也可以有构造函数进行成员变量的初始化,只不过由子类构造函数调用
抽象方法不能使用private,因为抽象类的私有成员既不能被抽象类本身访问(不能new抽象类对象),又不能被子类继承,所以没有存在的价值了。为了避免这种浪费内存的情况,C#规定在抽象类中不能使用private修饰
6.模板模式
模板模式:抽象方法,没有具体的实现,有一个按照流程调用的方法。
虚方法和抽象方法的区别:
1.虚方法必须有实现,抽象方法必须没有实现
2.抽象方法必须在抽象类中声明,虚方法可以出现在抽象类中
3.抽象方法必须在子类中重写,虚方法可以被重写
Sealed密封类:不能被子类继承还可以修饰重写方法。
1.类和类的关系:继承
2.类的继承关系(is a):子类就是父类
隐藏基类:当子类和父类里有同名的,但是没有重写的方法时,那么创建子类时,子类对象中同时包含子类和父类的此同名方法。
1.1此时,如果声明的是子类,就执行子类的同名方法。
1.2此时,如果声明的是子类,就执行父类的同名方法。
2.当子类和父类有同名方法时,默认就是用了隐式隐藏父类方法的new关键字。如果和上面一样
多态表现形式:里氏替换原则,具体的代码使用:
1.方法将父类当成返回值,具体return的是某个子类对象。
2.方法将父类当成形参,具体传入的实参是某个子类对象。
4.常量:1.不能在任何地方修改 2.只能在初始化的时候赋值
只读变量:可以在构造函数被修改