1.override
在C#中override可以叫重写或覆盖。意思就是覆盖了父类中跟子类中签名相同的虚方法。
public class A { public A() { Console.WriteLine('A'); } public virtual void Fun() { Console.WriteLine("A.Fun()"); } } public class B : A { public B() { Console.WriteLine('B'); } public override void Fun() { Console.WriteLine("B.Fun()"); } }
a).声明B类型的对象:
B test = new B();
test.Fun();
输出结果是:
A
B
B.Fun()
该结果中,先输出A,在输出B,说明实例化子类的对象时,先调用父类的构造函数,再调用子类的构造函数。
b.)声明父类的引用指向子类的对象:
A test = new B();
test.Fun();
运行结果:
A
B
B.Fun()
输出结果和刚才一样。
当使用override时,父类的虚函数完全被子类的函数给“覆盖”了。
c.) 声明父类的对象:
A a = new A();
a.Fun();
输出结果:
A
A.Fun()
此时调用的是父类中的虚方法。
总结:如果在子类中没有override父类的虚方法。则调用父类中的方法。如果子类override了父类的虚方法,则子类的对象使用子类中定义的方法。父类的虚方法被重写或者说覆盖了。
2.new
在子类中创建一个新的和父类中同名的属性或方法。在子类中隐藏了父类中的属性或方法。
public class A { public A() { Console.WriteLine('A'); } public virtual void Fun() { Console.WriteLine("A.Fun()"); } } public class B : A { public B() { Console.WriteLine('B'); } public new void Fun() { Console.WriteLine("B.Fun()"); } }
声明B类型的对象:
B test = new B();
test.Fun();
输出结果是:
A
B
B.Fun() ----此时与override的效果相同
声明A类型的对象:
A test = new B();
test.Fun();
运行结果:
A
B
A.Fun() ----此时,与override的情况不一样了。。。
结论:
1.new声明的方法,当使用子类的类型来调用的时候,它会运行子类中的函数,当类型是基类的话 ,则使用基类的函数来执行,可以简单的记忆:
override--覆盖(父类的没了,始终是儿子),new--新的(父子共存)
PS:只有使用virtual定义基类中的函数,并使用override标记子类的函数,才可以达到多态类----始终调用子类的方法
2.子类中override父类的方法,父类的方法一定要是virtual,而在子类中new父类的方法,父类的方法不一定要是virtual
3.抽象类中的抽象方法,必须要被子类override,不能new
4.override可以与sealed关键词连用: sealed override void F(),而new不行。被sealed修饰过的方法,不能再被子类重写。
再来一道复杂点的网上看到的面试题:
public class A { public virtual void Fun1(int i) { Console.WriteLine(i); } public void Fun2(A a) { a.Fun1(1); Fun1(5); } }public class B : A { public override void Fun1(int i) { base.Fun1(i + 1); } }
B b = new B();
A a = new A();
a.Fun2(b);
b.Fun2(a);
运行上面语句,执行结果是什么?
先分析a.Fun2(b):传入的参数是B类型的,因此a.Fun1(1)执行的是B类型对象的Fun1方法,运行结果是2
然后执行Fun1(5),由于运行的是A类型对象的Fun2方法,Fun1自然就是A中的Fun1,运行结果是5
再分析b.Fun2(a):传入的参数是A类型的,因此a.Fun1(1)执行的是A类型对象的Fun1方法,运行结果是1
然后运行Fun1(5),由于运行的是B类型对象的Fun2方法,此时的Fun1已经被B覆盖掉了,因此执行的是被覆盖后的方法,运行结果是6
那么如果把B类中的override改成new,情况会是什么样呢?
由于public void Fun2(A a)的参数类型始终是A类型(当传入B类型时,会转成A类型,相当于A a = new B()的效果),而用new不会覆盖父类的方法,因此结果是:
1
5
1
5