new、vitual、override之间那点事
来源:互联网 发布:知己知彼软件怎么样 编辑:程序博客网 时间:2024/06/06 05:14
转载From : http://blog.csdn.net/lastBeachhead/archive/2008/11/29/3402257.aspx
1)第一种情况:子类某个方法使用new修饰,但父类中并没有该方法。
- using System;
- using System.Collections.Generic;
- using System.Linq;
- using System.Text;
- namespace NewVituslOverride
- {
- public class Father
- {
- public void Say()
- {
- Console.WriteLine("Father.Say()");
- }
- }
- public class Son : Father
- {
- new public void SonSay()
- {
- Console.WriteLine("Son.SonSay()");
- }
- }
- class Program
- {
- static void Main(string[] args)
- {
- Father father = new Father();
- Son son = new Son();
- father.Say();
- son.SonSay();
- Console.ReadLine();
- }
- }
- }
Son类继承自Father,Father类中并没有SonSay()这个方法,在Son类中定义SonSay()方法,并且定义为new的,结果会怎么样呢?
运行结果:
Father.Say()
Son.SonSay()
即运行结果没问题,但编译器会提出一个警告:子类Son中的方法SonSay()在父类中并不存在,没必要使用new关键字。
2)第二种情况:父类中有一个方法,子类中也有一个同样签名的方法,但父类中该方法没有使用使用virtual、override、abstract修饰,子类中该方法也没有使用new或者override修饰。
- using System;
- using System.Collections.Generic;
- using System.Linq;
- using System.Text;
- namespace NewVituslOverride
- {
- public class Father
- {
- public void Say()
- {
- Console.WriteLine("Father.Say()");
- }
- }
- public class Son : Father
- {
- public void Say()
- {
- Console.WriteLine("Son.Say()");
- }
- }
- class Program
- {
- static void Main(string[] args)
- {
- Father[] persons = new Father[2];
- persons[0] = new Father();
- persons[1] = new Son();
- persons[0].Say();
- persons[1].Say();
- Console.ReadLine();
- }
- }
- }
运行结果:
Father.Say()
Father.Say()
为什么persons[1].Say()的运行结果也是Father.Say()呢?person[1]的实例类型明明是Son啊。因为在c#中,如果子类中的方法签名如果和父类中的方法签名一致而不是override的(名字相同,参数格式和类型也一致,跟返回值没关),那么就自动隐式的标记为new的方法了。而new出来的方法是不支持运行时绑定的,它是编译时绑定,即跟声明时类型有关,而跟运行时该对象的实际类型无关,即编译时已经确定是调用父类的还是子类的方法了。
另外编译器会给出一个警告:该方法签名跟父类的一样,如果是有意new的话,请加上new关键字。
3)第三种情况:子类的某个方法直接标识为override的,而父类该方法并没有声明为vitual、abstract或者override的。
- using System;
- using System.Collections.Generic;
- using System.Linq;
- using System.Text;
- namespace NewVituslOverride
- {
- public class Father
- {
- public void Say()
- {
- Console.WriteLine("Father.Say()");
- }
- }
- public class Son : Father
- {
- public override void Say()
- {
- Console.WriteLine("Son.Say()");
- }
- }
- class Program
- {
- static void Main(string[] args)
- {
- Father[] persons = new Father[2];
- persons[0] = new Father();
- persons[1] = new Son();
- persons[0].Say();
- persons[1].Say();
- Console.ReadLine();
- }
- }
- }
'NewVituslOverride.Son.Say()': cannot override inherited member 'NewVituslOverride.Father.Say()' because it is not marked virtual, abstract, or override。
编译错误内容很清楚,我就不解释了。
本例子说明override不是随便用的,必须父类的方法、属性、索引、事件是abstract、vitual或者override的时候,子类才能override它。
4)第四种情况:子类new父类中的方法。
- using System;
- using System.Collections.Generic;
- using System.Linq;
- using System.Text;
- namespace NewVituslOverride
- {
- public class Father
- {
- public void Say()
- {
- Console.WriteLine("Father.Say()");
- }
- }
- public class Son : Father
- {
- public new void Say()
- {
- Console.WriteLine("Son.Say()");
- }
- }
- class Program
- {
- static void Main(string[] args)
- {
- Father[] persons = new Father[2];
- persons[0] = new Father();
- persons[1] = new Son();
- persons[0].Say();
- persons[1].Say();
- Console.ReadLine();
- }
- }
- }
Father.Say()
Father.Say()
如果第二种情况看懂了,就知道这个例子的运行结果和第二种情况一样的。只是这次代码用new把意思说的明明白白,子类我就是要隐藏父类的方法Say()。由于person[1]的声明类型是Father(虽然实际类型是Son),所以还是因为编译时绑定的原因,person[1].Say()跑出来的结果还是Father.Say()。
5)父类方法使用vitual,子类使用override重写
- using System;
- using System.Collections.Generic;
- using System.Linq;
- using System.Text;
- namespace NewVituslOverride
- {
- public class Father
- {
- public virtual void Say()
- {
- Console.WriteLine("Father.Say()");
- }
- }
- public class Son : Father
- {
- public override void Say()
- {
- Console.WriteLine("Son.Say()");
- }
- }
- class Program
- {
- static void Main(string[] args)
- {
- Father[] persons = new Father[2];
- persons[0] = new Father();
- persons[1] = new Son();
- persons[0].Say();
- persons[1].Say();
- Console.ReadLine();
- }
- }
- }
运行结果:
Father.Say()
Son.Say()
这次虽然persons[1]的声明类型是Father,但因为Say()是vitual的,需要运行时根据对象的实际类型来调用,因为运行时person[1]的实际类型是Son,所以运行的是Son的Say()。
我们来仔细看下这个例子生成的IL代码:
Father类:
- .class public auto ansi beforefieldinit Father
- extends [mscorlib]System.Object
- {
- .method public hidebysig specialname rtspecialname instance void .ctor() cil managed
- {
- .maxstack 8
- L_0000: ldarg.0
- L_0001: call instance void [mscorlib]System.Object::.ctor()
- L_0006: ret
- }
- .method public hidebysig newslot virtual instance void Say() cil managed
- {
- .maxstack 8
- L_0000: nop
- L_0001: ldstr "Father.Say()"
- L_0006: call void [mscorlib]System.Console::WriteLine(string)
- L_000b: nop
- L_000c: ret
- }
- }
从里面可以看出Father类的Say()方法,被标识为newslot virtual的了。
我们接着来看Son类的IL代码:
- .class public auto ansi beforefieldinit Son
- extends NewVituslOverride.Father
- {
- .method public hidebysig specialname rtspecialname instance void .ctor() cil managed
- {
- .maxstack 8
- L_0000: ldarg.0
- L_0001: call instance void NewVituslOverride.Father::.ctor()
- L_0006: ret
- }
- .method public hidebysig virtual instance void Say() cil managed
- {
- .maxstack 8
- L_0000: nop
- L_0001: ldstr "Son.Say()"
- L_0006: call void [mscorlib]System.Console::WriteLine(string)
- L_000b: nop
- L_000c: ret
- }
- }
从Son的IL代码中我们可以看出来,虽然我们在c#代码中声明Son类的Say()方法为override的,但实际上转换为IL代码后,该方法在Son类中是virtual的。
接着我们来看下Program类的IL代码:
- .class private auto ansi beforefieldinit Program
- extends [mscorlib]System.Object
- {
- .method public hidebysig specialname rtspecialname instance void .ctor() cil managed
- {
- .maxstack 8
- L_0000: ldarg.0
- L_0001: call instance void [mscorlib]System.Object::.ctor()
- L_0006: ret
- }
- .method private hidebysig static void Main(string[] args) cil managed
- {
- .entrypoint
- .maxstack 3
- .locals init (
- [0] class NewVituslOverride.Father[] persons)
- L_0000: nop
- L_0001: ldc.i4.2
- L_0002: newarr NewVituslOverride.Father
- L_0007: stloc.0
- L_0008: ldloc.0
- L_0009: ldc.i4.0
- L_000a: newobj instance void NewVituslOverride.Father::.ctor()
- L_000f: stelem.ref
- L_0010: ldloc.0
- L_0011: ldc.i4.1
- L_0012: newobj instance void NewVituslOverride.Son::.ctor()
- L_0017: stelem.ref
- L_0018: ldloc.0
- L_0019: ldc.i4.0
- L_001a: ldelem.ref
- L_001b: callvirt instance void NewVituslOverride.Father::Say()
- L_0020: nop
- L_0021: ldloc.0
- L_0022: ldc.i4.1
- L_0023: ldelem.ref
- L_0024: callvirt instance void NewVituslOverride.Father::Say()
- L_0029: nop
- L_002a: call string [mscorlib]System.Console::ReadLine()
- L_002f: pop
- L_0030: ret
- }
- }
构造函数就不用看了,主要是看Main函数及其里面的执行顺序。
在Main函数中,先声明了一个Father[]数组,接着设置该数组的长度为2,接着创建了一个Father对象和一个Son对象。
关键是这两个对象调用Say()方法。我们可以看到是使用callvirl命令的,而不是call命令,使用callvirl命令就要求运行时检查对象的实际类型,然后调用该类型的对应方法。
- new、vitual、override之间那点事
- new、vitual、override之间那点事
- 重写(override)那点事
- Fragment,Activity,FragmentManager之间那点事
- sizeof与数组之间那点事
- C# new virtual override 之间的区别
- 析构函数和Finalize()之间的那点事
- 你可以知道,智能设备之间那点事
- 游标、事务并发和锁三者之间的那点事
- struts2校验与 ajax之间的那点事
- UML和RUP之间的那点事
- 游标、事务并发和锁三者之间的那点事
- 浅谈Swift和Objective-C之间的那点事。。。
- Lock和synchronized之间的那点事
- Jquery中attr()和prop()之间的那点事
- new override
- override?new
- 面试那点事
- StarUML---推荐一款UML工具(很好很强大)
- 自动生成 makefile 文件 以及 用objcopy 生成bin文件
- MySQL 转换 Oracle 的七大注意事项
- linux操作系统原理与应用-读书笔记(2)-进程(1)
- 计算一个语句产生的undo
- new、vitual、override之间那点事
- 郁闷了,硬件和软件
- inet_ntoa 连续使用 注意事项
- "合成聚合复用原则" (转http://www.cnblogs.com/supertbt/archive/2007/03/07/666319.html)
- 安全保密级别高的环境下部署Silverlight应用程序
- Hibernate数据不能插入同时也没有报错
- 母版页中引用图片、外部js、css文件的路径问题
- 错误提示:ORA-01747: user.table.column, table.column 或列说明无效
- 个人能力