c#中父类引用指向子类对象问题深究:
答案:5 悬赏:0 手机版
解决时间 2021-04-02 00:05
- 提问者网友:温旧梦泪无声
- 2021-04-01 07:29
c#中父类引用指向子类对象问题深究:
最佳答案
- 五星知识达人网友:酒醒三更
- 2021-04-01 08:28
你的问题非常的好。
你加进集合中的的确是子类的实例,关键是你用什么类型的引用指向这个子类的实例。关于你调用子类的属性或者方法是要和它的引用类型吻合的,并不是子类实例的所有东西都一定能够调用到。这个是面向对象的一个重要的特性。
举个例子:
接口IA里有方法: fa()
接口IB里有方法: fb()
子类C实现(继承)了接口IA,IB,并且子类自己定义了个方法fc(),则子类C就有:fa(),fb(),fc()三个方法
当子类C的实例objC被IA类型的引用指向的时候[IA objC = new C()或者(IA)objC],你可以调用到的是fa(),通俗的说objC这里是IA类型的,而并不是C类型的,所以只能调IA的fa()
当子类C的实例objC被IB类型的引用指向的时候[IB objC = new C()或者(IB)objC],你可以调用到的是fb(),通俗的说objC这里是IA类型的,而并不是C类型的,所以只能调IB的fb()
当子类C的实例objC被C类型的引用指向的时候[C objC = new C()或者(C)objC],你可以调用到的是fa(),fb(),fc()
这个其实就是面向接口或者说是面向对象编程的一个内容
你加进集合中的的确是子类的实例,关键是你用什么类型的引用指向这个子类的实例。关于你调用子类的属性或者方法是要和它的引用类型吻合的,并不是子类实例的所有东西都一定能够调用到。这个是面向对象的一个重要的特性。
举个例子:
接口IA里有方法: fa()
接口IB里有方法: fb()
子类C实现(继承)了接口IA,IB,并且子类自己定义了个方法fc(),则子类C就有:fa(),fb(),fc()三个方法
当子类C的实例objC被IA类型的引用指向的时候[IA objC = new C()或者(IA)objC],你可以调用到的是fa(),通俗的说objC这里是IA类型的,而并不是C类型的,所以只能调IA的fa()
当子类C的实例objC被IB类型的引用指向的时候[IB objC = new C()或者(IB)objC],你可以调用到的是fb(),通俗的说objC这里是IA类型的,而并不是C类型的,所以只能调IB的fb()
当子类C的实例objC被C类型的引用指向的时候[C objC = new C()或者(C)objC],你可以调用到的是fa(),fb(),fc()
这个其实就是面向接口或者说是面向对象编程的一个内容
全部回答
- 1楼网友:青灯有味
- 2021-04-01 10:49
好抽象啊,大哥给个程序啊。
- 2楼网友:青尢
- 2021-04-01 10:41
其实父类引用指向子类的时候,只要稍作调试就会知道是怎么回事。
第一父类对象引用子类的时候父类对象只是一个说明,而真正实例化得则是子类对象,这就好比经纪人和歌手的关系,经纪人接到命令,真正干活的是歌手一样
第一父类对象引用子类的时候父类对象只是一个说明,而真正实例化得则是子类对象,这就好比经纪人和歌手的关系,经纪人接到命令,真正干活的是歌手一样
- 3楼网友:患得患失的劫
- 2021-04-01 10:13
哈哈,你想知道底层的东西么?那我就告诉你,在底层中,一个变量是有类型的,而一个对象呢,也差不多算有类型的,在进行变量赋值的时候,CLR会检查是否可以允许赋值,如果是子类赋值给父类,或者子类给所实现接口类赋值的话,就可以。
当使用父类变量实际操作子类的时候,赋值字段其实在底层上和直接操作子类变量没区别,而调用方法则会使用callvirtual调用,这样CLR会根据实际情况调用父类或者子类方法(这情况讲起来挺复杂的)
想彻底的了解这个东西,你需要学的还很多很多很多,我都是学了将近两年才逐渐理解的,别着急,慢慢来。
回答补充:
这就是说,其实对象在内存中是不会考虑什么类型的,他有什么字段就是有什么字段,但是对象类型和变量类型是两码事,你不敢保证你的变量拥有什么别的方法,比如汽车类,那么轿车对象和卡车对象都可以赋给汽车的变量,但是你在写代码的时候敢保证他一定就是卡车,一定就有载货这个方法么?也许你敢保证,但是C#编译器不敢,所以点不出来
我建议你学学反射,会让你知道其实对象不管赋给什么类型的变量,其实本身没有变化,都是那个对象,只不过你看到的,你能用到的,所谓的广义的接口,是不同的。
当使用父类变量实际操作子类的时候,赋值字段其实在底层上和直接操作子类变量没区别,而调用方法则会使用callvirtual调用,这样CLR会根据实际情况调用父类或者子类方法(这情况讲起来挺复杂的)
想彻底的了解这个东西,你需要学的还很多很多很多,我都是学了将近两年才逐渐理解的,别着急,慢慢来。
回答补充:
这就是说,其实对象在内存中是不会考虑什么类型的,他有什么字段就是有什么字段,但是对象类型和变量类型是两码事,你不敢保证你的变量拥有什么别的方法,比如汽车类,那么轿车对象和卡车对象都可以赋给汽车的变量,但是你在写代码的时候敢保证他一定就是卡车,一定就有载货这个方法么?也许你敢保证,但是C#编译器不敢,所以点不出来
我建议你学学反射,会让你知道其实对象不管赋给什么类型的变量,其实本身没有变化,都是那个对象,只不过你看到的,你能用到的,所谓的广义的接口,是不同的。
- 4楼网友:蓝房子
- 2021-04-01 09:45
【当用父类引用进行“.”操作的时候只能显示出来父类的字段值(也就是存储在内存中子类对象的值),这样理解对吗?】
不对,父类引用子类的实例,其实这个对象属于子类的类型,但编译器会误认为这个对象是父类的类型(因为编译器只看它的申明类型),所以“.”操作仍然会调用父类的方法和属性,这一过程在编译时就已经完成了绑定,
但是如果这个方法是虚方法(用virtual修饰),情况就不一样了,编译的时候CLR如果判断该方法是虚方法,就会等到运行时才去晚绑定,所以在运行时这个类型该是什么类型就会调用相应的方法,
不对,父类引用子类的实例,其实这个对象属于子类的类型,但编译器会误认为这个对象是父类的类型(因为编译器只看它的申明类型),所以“.”操作仍然会调用父类的方法和属性,这一过程在编译时就已经完成了绑定,
但是如果这个方法是虚方法(用virtual修饰),情况就不一样了,编译的时候CLR如果判断该方法是虚方法,就会等到运行时才去晚绑定,所以在运行时这个类型该是什么类型就会调用相应的方法,
我要举报
如以上问答信息为低俗、色情、不良、暴力、侵权、涉及违法等信息,可以点下面链接进行举报!
大家都在看
推荐资讯