在线时间:8:00-16:00
迪恩网络APP
随时随地掌握行业动态
扫描二维码
关注迪恩网络微信公众号
技术交流,DH讲解. 问题如下: 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 是怎么实现的? 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}可以看到As会对类型进行一些列要求,而且是必须的. 如果我们把代码改一下用强制类型转换看看: 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位于对象地址后面8个字节处. 从上面我们可以看到直接强制类型转换速度效率会快一些,所以我们在明白这样转换不会出问题就多用这样转换,但是这中间缺少检验的过程,所以有时候转换后结果可能会错误. If Sender Is TButton then TButton(Sender).XXX;//别再用Sender As TButton了,都判断过了 好,今天就唠叨到这里,我是DH. |
2023-10-27
2022-08-15
2022-08-17
2022-09-23
2022-08-13
请发表评论