为什么一个对象可以用父类或接口声明,却用子类实例化 C#

内容会持续更新,有错误的地方欢迎指正,谢谢!

综述

不管一个对象用 父类还是接口 声明,再用子类实例化,最终目的都只是希望使用到 父类或接口 规定的功能而已,这种写法不获取 继承这个父类或实现这个接口 的子类的其他方法和字段,有效节省空间。

基本概念

以父类为例,用父类声明并用子类实例化,比如:Base b1 = new A(); Base b2 = new B();,这样new出来的对象(比如:b1、b2)都指向Base类,Base的子类(比如:A、B)能override重写父类中用virtual声明的虚方法,执行时,通过 new出来的对象 调用的是子类中重写的方法。
这样做的优点:
1.开发人员可以根据实际情况选择new某一个子类的对象并调用该子类中override重写的虚方法(如本文最后的一个例子);
2.还可以在父类里定义一些实例方法,new出来的对象 可以直接调用这些父类里的实例方法;
3.如果子类中用new覆盖父类中用virtual声明的虚方法时,执行时,通过对象调用的是父类中的虚方法。
在这里插入图片描述

// 以父类为例
public class ParentClass  
{  
    public virtual void ParVirMethod()  
    {  
        Console.WriteLine("父类的方法...");  
    }  
}  

public class ChildClass1 : ParentClass  
{  
    public override void ParVirMethod()  
    {  
        Console.WriteLine("子类1的方法...");  
    }  
}  

public class ChildClass2 : ParentClass  
{  
    public new void ParVirMethod()  
    {  
        Console.WriteLine("子类2的方法...");  
    }  
 
    public void Test()  
    {  
        Console.WriteLine("子类2的其他方法...");  
    }  
}  

执行调用:

ParentClass par = new ChildClass1();  
par.ParVirMethod(); //结果:“子类1的方法”,调用子类的方法,实现了多态
  
par = new ChildClass2();  
par.ParVirMethod();//结果:“父类的方法”,调用父类的方法,没有实现多态

深究其原因,为何两者不同,是因为原理不同:
override是重写,即将父类的方法在子类里直接抹去重新写,故而调用的方法就是子类方法;而new只是将父类的方法在子类里隐藏起来,故而调用的仍旧是父类方法。

而如果是“一个对象用接口声明并用子类实例化”,同理,唯一不同的是:接口只是定义一些协定,没有“一个对象用父类声明并用子类实例化”的第二个优点。举例:https://blog.csdn.net/BillCYJ/article/details/94720506

类型转换

“用子类定义的基类的对象”才能被强转为子类,而基类的对象不能被强转为子类,以ParentClass代表基类,ChildClass代表子类举例:

ParentClass pc1 = new ChildClass();
ChildClass cc1 = (ChildClass)pc1; // 正确

ParentClass pc2 = new ParentClass();
ChildClass cc2 = (ChildClass)pc2; // 错误

子类的对象可直接赋值给基类(不需要强转)

ChildClass cc3 = new ChildClass();
ParentClass pc3 = cc3;//正确

应用举例

比如People类有一个Run方法,Man和Woman这两个类都是继承自People的类,并且都重写(override)了Run这个方法(男人女人跑起步来不一样)。
现在有一群人一起跑步,有男人有女人。
我们可以把这些都装进一个People数组(假设为peoples),然后:

foreach(People p in peoples) // 用父类People声明,peoples中定义的对象有男有女,也就是用于实例化的子类不同。
{
	p.Run(); // 故而,调用的方法也不同,实现了多态
}

由于多态性,在调用p.Run()的时候p对象本身如果是男人就会自动调用男人的Run方法,是女人就会调用女人的Run方法。

依赖倒置原则

依赖倒置原则,DIP,Dependency Inverse Principle DIP的表述是:
1、高层模块不应该依赖于低层模块,二者都应该依赖于抽象。 2、抽象不应该依赖于细节,细节应该依赖于抽象。 这里说的“依赖”是使用的意思,如果你调用了一个类的一个方法,就是依赖这个类,如果你直接调用这个类的方法,就是依赖细节,细节就是具体的类,但如果你调用的是它父类或者接口的方法,就是依赖抽象, 所以DIP就是不要直接使用具体的子类,而是用它的父类的引用去调用子类的方法,这样就是依赖于抽象,不依赖具体。

其实简单的说,DIP的好处就是解除耦合,用了DIP之后,调用者就不知道被调用的代码是什么,因为调用者拿到的是父类的引用,它不知道具体指向哪个子类的实例,更不知道要调用的方法具体是什么,所以,被调用代码被偷偷换成另一个子类之后,调用者不需要做任何修改, 这就是解耦了。

参考

【1】C#中子类对父类中虚方法的处理有重写(override)和覆盖(new),他们有什么区别?
http://blog.csdn.net/strong_wenzi/article/details/51023477
【2】c#中,类的重写中,new和override的区别
http://blog.csdn.net/qq_32623363/article/details/53966755?ref=myread
【3】为什么C#中常常实例化子类,定义却是父类类型
http://www.devexception.com/cSharp/118092.htm

  • 10
    点赞
  • 25
    收藏
    觉得还不错? 一键收藏
  • 4
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值