面试的时候经常会被问到一个弱智题:面向对象的三个基本特征是什么?
这时候你完全可以以请教的口气优雅的反问一道题,看看ta对“继承”的理解(不过这驳考官面子的后果可得想清楚哦!):
classFather{publicvirtualvoidfun(){Console.WriteLine("你好!");}} classSon:Father{publicoverridevoidfun(){Console.WriteLine("Hello!");}} 上面两个类是继承关系吗?谈谈你对继承的理解,并用面向对象的思想改写代码。
好了,先卖个关子不说答案是,先来看看什么是里氏替换原则。
里氏替换原则
定义:如果对每一个类型为T1的对象o1,都有类型为T2的对象o2,使得以T1定义的所有程序P在所有的对象o1都换成o2时,程序P的行为没有变化,那么类型T2是类型T1的子类型。
通俗的定义:所有引用基类的地方必须能透明地使用其子类的对象。
按照我的理解就是:父亲能干是事情,儿子都能干;父亲干不了的,儿子也能干;所有父亲要干的事情,都可以让儿子去干。
(所以对于上面的问题,我的回答是:这算不上继承,因为父亲说的是汉语,但是儿子只会说英语,我们是心中有对象的人,这违背了里氏替换原则,应该将子类的override换乘new)
第三只眼:
abstractclassPerson{//也可以不加virtual,但无virtual的情况下派生类能可以被覆盖,但不可以被重写。//更多virtual和override的区别略...publicvirtualvoidDoSomething(){Console.WriteLine("制造劳动工具!");//这是人和动物的基本区别}}
//***************************************************************************
classWoman:Person{overridepublicvoidDoSomething(){Console.WriteLine("生小孩!");}}
//***************************************************************************
classPRogram{staticvoidMain(string[]args){Personp=newWoman();//用子类去替换父类p.DoSomething(); Womanw=newWoman();w.DoSomething();Console.ReadKey();}}
运行结果:(人) 生小孩!
(女人)生小孩!
不是人人都能生小孩的,用子类替换父类后,这明显违背了常理,这也违背了里氏替换原则的“子类可以实现父类的抽象方法,但是不能覆盖父类的非抽象方法”的思想。
这时候我们可以用new去隐藏父类的方法,让person继续干person的事,把生小孩的事情留给woman:
classWoman:Person{newpublicvoidDoSomething()//或publicnewvoidDoSomething(){Console.WriteLine("生小孩!");}}
在思考一个关于女孩与女人的问题:
按照常规思维,女孩属于女人,所以女孩继承自女人。
接着上面…
classGirl:Woman{publicvoidSing(){Console.WriteLine("唱歌");}}
女孩对女人这个类进行了扩展,但是问题就出来了,这时候女孩就有了生小孩的能力,如果女人再有个大姨妈,难道女孩也要继承?
这时如果让女人继承自女孩好像更妥,女孩可以唱歌,而女人可以唱歌、生小孩、来个例假什么的。。。
虽然这没有违背面向对象继承的任何原则,但却不适合用常规思维去定义面向对象的类。
总结:被override重写的类最好是sealed类,即该类不能再派生子类。
不要用感性的常规思维去理解面向对象的继承,对于类的定义与继承一定要准确且不违背常理。
欢迎指点,扔便便。。。 QQ:498576940
新闻热点
疑难解答