• 设为首页
  • 点击收藏
  • 手机版
    手机扫一扫访问
    迪恩网络手机版
  • 关注官方公众号
    微信扫一扫关注
    公众号

Delphi-盒子上面看见的一个问题:关于类型转换TypeCast

原作者: [db:作者] 来自: [db:来源] 收藏 邀请

技术交流,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就应该是0,不管我们写没有写F1:=0;
要解释这个就需要用到我们之前的知识了.
正常情况下,A的内存:

偏移 0-3 4-7
内容 TBase的地址 $00000000
正常情况下,B的内存:
偏移 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是下黑手去抢的内存.

从上面我们可以看到直接强制类型转换速度效率会快一些,所以我们在明白这样转换不会出问题就多用这样转换,但是这中间缺少检验的过程,所以有时候转换后结果可能会错误.
所以我们需要注意了:

If Sender Is TButton then
	TButton(Sender).XXX;//别再用Sender As TButton了,都判断过了

好,今天就唠叨到这里,我是DH.


鲜花

握手

雷人

路过

鸡蛋
该文章已有0人参与评论

请发表评论

全部评论

专题导读
上一篇:
[Python-MATLAB] 在Python中调用MATLAB的API发布时间:2022-07-18
下一篇:
灰狼优化算法——MATLAB发布时间:2022-07-18
热门推荐
阅读排行榜

扫描微信二维码

查看手机版网站

随时了解更新最新资讯

139-2527-9053

在线客服(服务时间 9:00~18:00)

在线QQ客服
地址:深圳市南山区西丽大学城创智工业园
电邮:jeky_zhao#qq.com
移动电话:139-2527-9053

Powered by 互联科技 X3.4© 2001-2213 极客世界.|Sitemap