虚方法virtual和抽象方法abstract以及多态的研究<14/10/2017>
虚方法virtual定义:
当类中的方法声明前加上了 virtual 修饰符,我们称之为虚方法,反之为非虚。
使用了 virtual 修饰符后,不允许再有 static , abstract 或override 修饰符(必须是 Public )。
为了实现多态,父类里面的方法用虚方法,子类里面可以对该方法重写,也可以不重写,当我们创建了一个子类 的对象并把它转换成了父类的类型后,如果子类里面没有重写父类里面的虚方法,则直接调用父类的方法,如果子类 里面重写了虚方法,则调用子类时面重写后的方法。
虚方法和非虚方法什么区别呢?
对于非虚的方法,无论被其所在类的实例调用,还是被这个类的派生类的实例调用,方法的执行方式不变。而对于虚方法,它的执行方式可以被派生类改变,这种改变是通过方法的重载来实现的。举个例子(简单的代码):
class A
{
public void F() { Console.WriteLine("A.F"); }
public virtual void G() { Console.WriteLine("A.G"); } //定义虚方法
}
class B : A
{
new public void F() { Console.WriteLine("B.F"); } //这里的方法则不能重写,因为基类中的F()方法不是虚方法。
public override void G() { Console.WriteLine("B.G"); } //重写虚方法
}
static void Main(string[] args)
{
B b = new B();
A a = b; //A对象指向B对象
b.F(); //显示结果B.F a(基)父b(派)子
a.F(); //显示结果A.F
b.G(); //显示结果B.G
a.G(); //显示结果B.G 实际这里调用的是不是基类中的G方法,而是派生类中重写过的G方法。
Console.ReadKey();
}
结果是:
B.F
A.F
B.G
B.G//***重点:当基类对象指向派生类对象时,基类的虚方法被重写,函数执行的是派生类方法。不是虚方法调用的是基类方法***//
a.G()的结果是B.G。这里了可以得出结论,当基类对象指向派生类对象时,基类的虚方法被重写,函数执行的是派生类方法。不是虚方法调用的是基类方法。
非虚拟方法的实现是不变的:无论是在声明它的类的实例上调用该方法还是在派生类的实例上调用,实现都是相同的。与此相反,虚拟方法的实现可以由派生类取代。取代所继承的虚拟方法之实现的过程称为重写方法
这里的new 是在子类对父类方法的一种替换,不写会有警告;
与抽象方法什么区别呢?
4、任何一个非抽象子类必须要重写父类的抽象方法。
这两者都是多态的范畴,多态怎么理解?
重写的概念:
是子类(即派生类)的方法覆盖父类(即基类)的虚方法。
重写的要求:
1、三相同:
(1)方法名称相同
(2)参数列表相同
(3)返回值类型相同
一句话,只需重写代码体的内容!
2、重写声明不能更改虚方法的可访问性:重写方法和虚方法必须具有相同的访问级修饰符。例如:虚方法为public的,重新方法也必须是public的。
3、可以重写基方法:必须是虚拟的(virtual)、抽象的(abstract)或重写的(override)。(非虚方法或静态方法是不可以重写的)。
4、不能使用下列修饰符修改重写(override)方法(即该方法中含有override关键字):new、static、virtual、abstract
如:new public override void outwork () //这样写是不可以的
{
MessageBox.Show("子类的子类(override)下班");
}
5、重写属性:重写的属性必须与继承属性有完全相同的访问修饰符、类型和属性名,并且重写属性必须是虚拟的(virtual)、抽象的(abstract)或是重写的(override)。
6、new关键字和override关键字比较:(***概念也很重要***)
如果使用override重写xx方法,通过父类引用一样只能看到重写后的方法;override重写的是虚方法,那么就只剩下重写以后的方法,原来的方法被覆盖了。如果使用new隐藏xx方法,父类子类引用各自对应方法;new隐藏基类的方法,那么基类的方法和当前类的方法同时存在只是被隐藏了。
总结:override可以覆盖基类的方法,让基类的方法以子类的内容实现,而new不用来覆盖基类的方法,而是全新定义一个子类的方法,这个方法只属于子类,与基类的方法无关,只是名字上相同而已。