Delphi - 盒子上面看见的一个问题:关于类型转换Type Cast
技术交流,DH讲解.
问题如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 | TBase = class end ; TChild = class (TBase) public F1: Integer ; procedure Say; end ; implementation {$R *.dfm} procedure TForm3 . FormCreate(Sender: TObject); var A:TBase; B:TChild; begin A:=TBase . Create; try B:=A as TChild; //编译成功,但是运行报错 B . Say; finally A . Free; end ; end ; { TChild } procedure TChild . Say; begin ShowMessage( '%D' ,[F1]); end ; |
我们看看As 是怎么实现的?
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 | function _AsClass(Child: TObject; Parent: TClass): TObject; {$IFDEF PUREPASCAL} begin Result := Child; if not (Child is Parent) then Error(reInvalidCast); // loses return address end ; { $ELSE } asm { -> EAX left operand (class) } { EDX VMT of right operand } { <- EAX if left is derived from right, else runtime error } TEST EAX,EAX //如果对象是Nil就退出 JE @@exit MOV ECX,EAX @@loop: MOV ECX,[ECX] //获取自己的类型 CMP ECX,EDX //与要转换的类型进行比较 JE @@exit //一样就退出 MOV ECX,[ECX].vmtParent //不一样就取父类来比较 TEST ECX,ECX //判断父类是否为空. JNE @@loop { do runtime error } MOV AL,reInvalidCast //如果都不能匹配就报错 JMP Error @@exit: end ; { $ENDIF } |
如果我们把代码改一下用强制类型转换看看:
1 2 3 4 5 6 7 8 9 10 11 12 13 | procedure TForm3 . FormCreate(Sender: TObject); var A:TBase; B:TChild; begin A:=TBase . Create; try B:=TChild(A); //没有错误 B . Say; //但是 弹出来的数据非0 finally A . Free; end ; end ; |
现在运行不会错了,但是弹出来的数据却不是0,为什么?成员变量会初始化的,那么如果创建一个TChild对象的话,
F1就应该是0,不管我们写没有写F1:=0;
要解释这个就需要用到我们之前的知识了.
正常情况下,A的内存:
偏移 | 0-3 | 4-7 |
内容 | TBase的地址 | $00000000 |
偏移 | 0-3 | 4-7 | 8-B |
内容 | TChild地址 | $00000000 | F1变量的值 |
也就是F1位于对象地址后面8个字节处.
那么上面的代码中,我们TChild.Say; 会用到F1,而我们把A当成TChild的实例了,是吧?那么去找F1,它就会跑到A+8的地方去,
但是我们看见实际A+8的地方不属于A管,所以这4个字节是未知的,没有被初始化成0,所以报出来也不太可能是0了.
谁叫A是下黑手去抢的内存.
从上面我们可以看到直接强制类型转换速度效率会快一些,所以我们在明白这样转换不会出问题就多用这样转换,但是这中间缺少检验的过程,所以有时候转换后结果可能会错误.
所以我们需要注意了:
1 2 | If Sender Is TButton then TButton(Sender).XXX; //别再用Sender As TButton了,都判断过了 |
好,今天就唠叨到这里,我是DH.
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】凌霞软件回馈社区,博客园 & 1Panel & Halo 联合会员上线
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步