中医专治白癜风医院 https://baike.baidu.com/item/%E5%8C%97%E4%BA%AC%E4%B8%AD%E7%A7%91%E7%99%BD%E7%99%9C%E9%A3%8E%E5%8C%BB%E9%99%A2/9728824 今天一朋友问我,c#中new与override有什么区别? 刚看到这个问题,其实我有点懵,因为我对这两个关键字的研究也没有花太多心思,虽然知道一些区别,但并不是非常确信。 所以,趁着这次机会,自己也学习一下。 首先,原问题中的示例代码给了我非常好的参考。这段代码可以非常直观的展示出new和override的区别。 下面是我略加整理的测试代码: new修饰符代码publicclassFatherNew{protectedvoidDoConsole(){Console.WriteLine("FatherNew");}publicvoidConsoleFather(){DoConsole();}}publicclassChildNew:FatherNew{protectednewvoidDoConsole(){Console.WriteLine("ChildNew");}} //客户端调用varcn=newChildNew();cn.ConsoleFather();运行结果 代码中,我们使用new隐藏了父类(FatherNew)的DoConsole方法。 看看此时的输出结果吧: 那么问题来了:我们明明把Father的DoConsole方法覆盖掉了,理论上ConsoleFather()执行的时候应该调用新的DoConsole呀,这样的话,应该输出"ChildNew"才对呀。 这个疑惑咱们先放放,先看一下override的代码及结果咱们再统一总结。 override修饰符代码publicclassFatherOverride{publicvirtualvoidDoConsole(){Console.WriteLine("FatherOverride");}publicvoidConsoleFather(){DoConsole();}}publicclassChildOverride:FatherOverride{publicoverridevoidDoConsole(){Console.WriteLine("ChildOverride");}} varco=newChildOverride();co.ConsoleFather(); 就像new里的代码一样,我们重写了父类(FatherOverride)的DoConsole,只不过这次是用override修饰符。 看看运行结果吧: 这个还算符合预期,既然我重写了DoConsole,那么执行时,就应该执行调用新的DoConsole才对嘛。 结论new修饰符定义的新方法,在同一派生类调用时,的确会调用这个新的方法,但在其基类中调用时,依旧是调用基类中的原始的那个方法。 override修饰符重写的方法,只要是通过派生类实例调用,哪怕是间接调用(比如像示例代码中,派生类的示例,调用父类中的ConsoleFather方法),都会调用新的使用override重写的那个方法。 之所以出现这种情况,是因为在编译时,它们就已经有了差异: 普通成员在编译时,其引用的相对地址就已经被程序确定好了。因此程序运行时,将会直接根据该地址调用该成员。即:在编译时,FatherNew的ConsoleFather方法中,就已经把DoConsole方法的引用确定好了(也就是FatherNew的DoConsole方法的引用)。 而虚成员在编译时,并没有将其引用固定写在程序的执行文件中。因此程序运行时,才会检查当前对象(也就是类的实例)到底是什么类型。当该对象调用虚成员时,会发现该成员是虚成员,然后就会查找它的重写成员。从该实例的类开始,一层一层地向上(即其父类)查找,找到后就会执行。即:ChildOverride实例化后,调用其基类中的ConsoleFather时,程序还不知道DoConsole的具体引用地址。查找后发现这个虚方法的第一个重写就是ChildOverride中的DoConsole,因此,就执行它了。 声明:发布此文是出于传递更多知识以供交流学习之目的。若有来源标注错误或侵犯了您的合法权益,请作者持权属证明与我们联系,我们将及时更正、删除,谢谢。 作者:迷鹿 来源:segmentfault.
|