父类强制转换成子类,内部到底做了什么

蹦极的馒头 2014-07-09 11:18:47
例如:A类是基类,B是子类,B继承A

A a=new B();
B b=(B)a;

请问这个(B)a转换到底在底层做了什么,比如指针或者内存方面

我查看IL代码,IL代码中只是简单的castclass一行带过

而用sos.dll查看对象,发现不管是a还是b,指向的都是堆上的同一块内存地址
虽然由此可以得出a和b这两个引用指向的都是内存上同一个对象,但是我真的想知道(B)a这个转换到底在底层做了什么??
谢谢大家

...全文
719 19 打赏 收藏 转发到动态 举报
写回复
用AI写文章
19 条回复
切换为时间正序
请发表友善的回复…
发表回复
仙剑 2014-07-14
  • 打赏
  • 举报
回复
貌似什么都没做呀
  • 打赏
  • 举报
回复
你那种强制类型转换,编译器什么也不做,而且运行时只要.net系统检测到类型兼容,那么直接用变量b引用对象就是了。 但是强制类型转换,在c#编译器中还有另外一种用法。我以前举过一个把香蕉强制转换为马的例子,以及把”主语+谓语“转换为句子的例子。http://bbs.csdn.net/topics/360039451
  • 打赏
  • 举报
回复
引用 5 楼 u010401287 的回复:
[quote=引用 4 楼 tcmakebest 的回复:] 这个问题初学者常会纠结,内部什么都不需要做,只是对一个对象换个称呼而已.
那能解释下 A a = new A(); B b = new B(); b = (B)a; 为何能编译通过,却运行抛出异常,此时运行时(B)a在做什么?为什么会抛出异常[/quote] 强制类型转换,这就是告诉编译器你”强制定义类型“了。这实际上就突破了c#的强类型编程的限制。 但是.net平台是强类型的系统,它会在给变量赋值时自动去检查一下对象的类型,保证声明兼容性。他不会像javascript那类垃圾动态语言那样,仅仅在你的代码已经走到迷宫里、你按照错误的类型而仿问属性或者函数执行时才崩溃,而是会提前在入口处就给你崩溃。
youzelin 2014-07-10
  • 打赏
  • 举报
回复
A a=new B(); 这种情况一般普遍的代码中的情况就是:

ISomeInterface si = new SomeClass(); // SomeClass 实现了 ISomeInterface
// 这样,SomeClass 自己定义的很多东西都被过滤了,si 看不到了。si 只看到自己定义的、以及被 SomeClass 重载的那些东西。
liqiucu 2014-07-09
  • 打赏
  • 举报
回复
引用 5 楼 u010401287 的回复:
[quote=引用 4 楼 tcmakebest 的回复:] 这个问题初学者常会纠结,内部什么都不需要做,只是对一个对象换个称呼而已.
那能解释下 A a = new A(); B b = new B(); b = (B)a; 为何能编译通过,却运行抛出异常,此时运行时(B)a在做什么?为什么会抛出异常[/quote] 因为 a是parent class的instance,b和a都属于A的类型,自然可以编译通过,但是一旦运行, b = (B)a;违反了 设计模式的里氏替换原则(子可以替换父 , 父不可以替换子)
TMajier 2014-07-09
  • 打赏
  • 举报
回复
引用 5 楼 u010401287 的回复:
[quote=引用 4 楼 tcmakebest 的回复:] 这个问题初学者常会纠结,内部什么都不需要做,只是对一个对象换个称呼而已.
那能解释下 A a = new A(); B b = new B(); b = (B)a; 为何能编译通过,却运行抛出异常,此时运行时(B)a在做什么?为什么会抛出异常[/quote] 以内存来说,a和b都是指向同一段内存,这是不会报错,所以你a=b在底层的语法中是没有错误的;报错得是编译器对类型的检测即c#语法,A是B的父类,所以可以定义b;
tinydyw 2014-07-09
  • 打赏
  • 举报
回复
A a=new B();//如果只有这一句代码..虽然a是B类实例.但是假如A类和B类都有hello()方法,那么调用a.hello()执行的是A类的hello()方法, B b=(B)a;//这个b才是真正意义上的B类实例...无论用b去调用什么方法.都是用B类的..
hityct1 2014-07-09
  • 打赏
  • 举报
回复
类是引用,可以理解为指针,指向一段内存,这内存存的是子类实例,强制转换告诉编译器这里存的是子类B
蹦极的馒头 2014-07-09
  • 打赏
  • 举报
回复
引用 4 楼 tcmakebest 的回复:
这个问题初学者常会纠结,内部什么都不需要做,只是对一个对象换个称呼而已.
那能解释下 A a = new A(); B b = new B(); b = (B)a; 为何能编译通过,却运行抛出异常,此时运行时(B)a在做什么?为什么会抛出异常
tcmakebest 2014-07-09
  • 打赏
  • 举报
回复
这个问题初学者常会纠结,内部什么都不需要做,只是对一个对象换个称呼而已.
wanghui0380 2014-07-09
  • 打赏
  • 举报
回复
呵呵,夏天了!你看到满大街的墨镜了把,看见过那种外面加一个黑镜片的墨镜没有 如果里面镜片是基类,外面加的那个是子类。你现在了解俺们在说什么了把,无色变墨镜,墨镜变无色很神奇把,其实不神奇啊。类型转换其实就是把类型方法表那个镜片换来换去滴,红色基类变紫色子类很容易啊,外面加个蓝色镜片就行了,看起来是紫色的子类变红色的基类也很容易啊,把外面那个蓝色的镜片去掉就是了
於黾 2014-07-09
  • 打赏
  • 举报
回复
但是C#是强类型的语言,不强制转换编译不会通过.
於黾 2014-07-09
  • 打赏
  • 举报
回复
A a=new B();//你这里已经指定了用B去实例化a B b=(B)a;//所以这里什么都没做,即使不强制转换,a本身就是B的实例化,而不是基类A
showjim 2014-07-09
  • 打赏
  • 举报
回复
父类转子类,有类型判定操作。 对象是同一个,地址当然一样,只是编译器把它当成目标类型处理而已。
CGabriel 2014-07-09
  • 打赏
  • 举报
回复
如果子类不父类多几个成员变量,则转换之后允许 方位的内存范围大一些。 但是真的要访问子类的独有变量,那样烧香拜佛,祈祷不要出错了。
moonwrite 2014-07-09
  • 打赏
  • 举报
回复
A a=new B(); // 这里真正制造出来的是B,不是A。假设A=哺乳动物,B = 狗。 B b=(B)a; 上帝创建了一个狗,先用哺乳动物表示着,等到有一天,上帝觉得狗这个名称不错,就用狗来表示之前创建的那只 A a = new A();//这里真正制造出来的是A,假设A=哺乳动物,B = 狗。 B b = new B();//这里真正制造出来的是B,假设A=哺乳动物,B = 狗。 b = (B)a;你觉得哺乳动物可以转换成狗么 面向对象是一种用来分析世界的方法~ 你可以多考虑现实中的例子 如果单单看A转B ,B转A的,很难明白了解面向对象的 A a=new B(); B b=(B)a; 这个在内存上是没有变化的~ 只是穿马甲而已~ float f = 10; int i =(int)f;//虽然i也是10,但内存上已经被去掉了很多个bit了~ 当然这是值类型的,像上面的引用类型的~真真正正的父转子是要报错的,
vioalouyang 2014-07-09
  • 打赏
  • 举报
回复
类型转换,如果还有另外一个子类c.子类之间的转换是需要对一下方法表的。
tiannailu 2014-07-09
  • 打赏
  • 举报
回复
学过C++之后很容易明白。 内存是没有变化的。 内存顺序总是先虚函数指针表、父类属、再子类,当把子类地址赋给父类指针时,发现完全可以搞出个父类来。 像“歪”这个字,“不”是父类,“歪”是子类。从上往下找,总是能先找到不,然后找到歪、
jobscq 2014-07-09
  • 打赏
  • 举报
回复
内存地址由16位2进制来表示,分为高8位和低8位 当声明一个类时,高8位指向了这个类叫什么,唯一的ID是什么等类本身的信息,这也是我们能通过反射查找到的部分信息 而低8位指向的是类内部对外部对象的地址引用,即是说低8位指向了类内部的属性和方法的地址集合 而继承,我们可以认为是子类的高8位指向了父类低8位的地址,这样子类就知道了父类所有的属性和方法(这里不讨论private),这些属性和方法的地址也遵循着继承关系,即高8位指向了父类对应属性或方法的地址的低8位 类型转换的过程,我们可以认为是一个内存寻址的过程。当A指向B的时候(即A a= new B()),此时查询B的高8位是不是等于A的低8位,等于则此表达式是成立的。当然这是一个链式反应,如果是A:B:C, 如果A a= new C(), 则会根据链式的规则,向上去查找地址,首先找到B,B的低8位是满足C的高8位的,然后通过B的高8位找到了A的低8位,所以此表达式是正确的。而让B b= nwe A()或者C c= new A(),查找A的高8位地址没有找到任何匹配的地址,则此表达式不成立。 而B b = (B)a,这种叫显示转换,也叫做强制转换,这是C#这类强类型语言独有的方式,这样做是在编译期在语义上能解释,但并验证这种转换是否正确,实际的转换过程是在runtime,显然A的高8位不符合上述的寻址规则,所以报错 当然底层的实现不可能如我所叙述的如此简单,而且语言不同,在寻址方式和地址的使用上也会有区别,但大致就是这么个意思了

110,533

社区成员

发帖
与我相关
我的任务
社区描述
.NET技术 C#
社区管理员
  • C#
  • Web++
  • by_封爱
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告

让您成为最强悍的C#开发者

试试用AI创作助手写篇文章吧