继承之---对象用父类声明,用子类实例化
为什么一个对象可以用父类声明,却用子类实例化
这个实例是子类的,但是因为你声明时是用父类声明的,所以你用正常的办法访问不到子类自己的成员,只能访问到从父类继承来的成员。
在子类中用 override 重写父类中用 virtual 申明的虚方法时,实例化父类调用该方法,执行时调用的是子类中重写的方法;
如果子类中用 new 覆盖父类中用 virtual 申明的虚方法时,实例化父类调用该方法,执行时调用的是父类中的虚方法;
1 /// <summary> 2 /// 父类 3 /// </summary> 4 public class ParentClass 5 { 6 public virtual void ParVirMethod() 7 { 8 Console.WriteLine("父类的方法..."); 9 } 10 } 11 12 /// <summary> 13 /// 子类1 14 /// </summary> 15 public class ChildClass1 : ParentClass 16 { 17 public override void ParVirMethod() 18 { 19 Console.WriteLine("子类1的方法..."); 20 } 21 } 22 23 /// <summary> 24 /// 子类2 25 /// </summary> 26 public class ChildClass2 : ParentClass 27 { 28 public new void ParVirMethod() 29 { 30 Console.WriteLine("子类2的方法..."); 31 } 32 33 public void Test() 34 { 35 Console.WriteLine("子类2的其他方法..."); 36 } 37 }
执行调用:
ParentClass par = new ChildClass1();
par.ParVirMethod(); //结果:"子类1的方法",调用子类的方法,实现了多态
par = new ChildClass2();
par.ParVirMethod(); //结果:"父类的方法",调用父类的方法,没有实现多态
深究其原因,为何两者不同,是因为原理不同:
override是重写,即将基类的方法在派生类里直接抹去重新写,故而调用的方法就是子类方法;而new只是将基类的方法在派生类里隐藏起来,故而调用的仍旧是基类方法。
应用举例
有这样的需要的,比如 People 类有一个 Run 方法,Man 和 Woman 这两个类都是继承自 People 的类,并且都重写(override)了 Run 这个方法(男人女人跑起步来不一样)。
现在有一群人一起跑步,有男人有女人。
我们可以把这些都装进一个People数组(假设为peoples)。
然后:
1 foreach(People p in peoples) // peoples中对象不同(即有男有女),用于实例化的子类就不同。 2 { 3 p.Run(); // 故而,调用的方法也不同,实现了多态 4 }
由于多态性,在调用 p.Run() 的时候 p 对象本身如果是男人就会自动调用男人的 Run 方法,是女人就会调用女人的 Run 方法。
依赖倒置原则
依赖倒置原则,DIP,Dependency Inverse Principle DIP的表述是:
1、高层模块不应该依赖于低层模块, 二者都应该依赖于抽象。
2、抽象不应该依赖于细节,细节应该依赖于抽象。
这里说的“依赖”是使用的意思,如果你调用了一个类的一个方法,就是依赖这个类,如果你直接调用这个类的方法,就是依赖细节,细节就是具体的类,但如果你调用的是它父类或者接口的方法,就是依赖抽象, 所以 DIP 说白了就是不要直接使用具体的子类,而是用它的父类的引用去调用子类的方法,这样就是依赖于抽象,不依赖具体。
其实简单的说,DIP 的好处就是解除耦合,用了 DIP 之后,调用者就不知道被调用的代码是什么,因为调用者拿到的是父类的引用,它不知道具体指向哪个子类的实例,更不知道要调用的方法具体是什么,所以,被调用代码被偷偷换成另一个子类之后,调用者不需要做任何修改, 这就是解耦了。