请问什么时候使用as关键字来进行强制类型转换?
我在书上看到下面这个例题:
   procedure Foo(Anobject:TObject);1、(Foo as TEdit).Text:='Hello World';
    这里是否可以用TEdit(Foo).Text:='Hello World';?
2、if (Foo is TEdit) then
       TEdit(Foo).Text:='Hello World';
    [在书上讲到:这个例子中不能用as进行强制类型转换。]
    但这是为什么呢?为什么不可以用(Foo as TEdit).Text:='Hello World'; ?

解决方案 »

  1.   

    不理解啊,Foo 是一个过程,怎么能强制类型转换为一个类呢?书上写错了吧。我猜你问这个问题的意思是你不知道TEdit(xx) 和 xx as TEdit 的区别是吧?实际上,TEdit(xx) 是静态的类型强制转换,假如转换失败并不会报错,总之它可以返回一个什么东西,但是你要是真的拿这个返回的东西来用,就不知道会出什么事情了。举个例子:
    var
        ch: Char;TEdit(ch).Caption = '';这样的代码是可以通过编译的但是跑起来就要出内存引用错误。而as 则是动态的类型转换,主要用于接口的转换,把一个接口转换为另外一个接口。假如转换失败,会抛出异常。另外,像ch as TButton 这样的转换是不会被编译器通过的,因为它认为这样的转换类型不符。
      

  2.   

    哦,是书上印错了,我敲上来的时候忘了改正。请问什么时候使用as关键字来进行强制类型转换?
    我在书上看到下面这个例题:
       procedure Foo(Anobject:TObject);1、(Anobject as TEdit).Text:='Hello World';
        这里是否可以用TEdit(Anobject).Text:='Hello World';?2、if (Anobject is TEdit) then
           TEdit(Anobject).Text:='Hello World';
        [在书上讲到:这个例子中不能用as进行强制类型转换。]
        但这是为什么呢?
        为什么不可以用(Anobject as TEdit).Text:='Hello World'; ?楼上Spacesoft(暗夜狂沙),我看了您的回答还是有点糊涂,难道(Anobject as TEdit)与TEdit(Anobject)区别单单就是是否在编译时会抛出异常吗?还请指点,谢谢!
      

  3.   

    补充以下
    不光是抛出异常的问题,如果as转换的不合理,根本就编译不过去。如
    var frm:TForm;如果用 (frm As Tbutton).catipn 则编译时出错。
    而TButton(frm)是强类型转化。在运行时可能产生想不到的错误。
    看下一个例子,可以成功运行
    var i:longint;btn:TButton;
    begin
      btn:=Tbutton.create(self);
      i:=Longint(btn);
      TButton(i).Parent:=self;
      TButton(i).Caption:='强类型转换';
      TBUtton(i).Visible:=true;
    end;
      

  4.   

    rockswj(石头) ,你好!我将你写的代码:
          TButton(i).parent:=self;
     改成 (i as TButton).parent:=self;
    在编译时,提示错误:
        Operator not applicable to this operand type.但后来我用as另写了一段代码:
    var
       i:TObject;
    begin
       i:=TObject.Create;
      (i as TButton).Parent:=self;
      (i as TButton).Caption:='强类型转换2';
      (i as TButton).Visible:=true;
    end;
    如果i是等于TObject.create,程序编译可以通过,但运行时会报错:
                   Invalid class typecast如果i改写成i:=TButton.create(self),编译和运行都可以通过,程序不会报错。另外如果在上面的基础上将(i as TButton).Parent:=self;改成TButton(i).parent:=self;也可以通过呀。对这两者的区别有点糊涂了,是不是as只是用在类方面的转换?只是将一个类的对象转换成它的派生类型,并且只能转换成它的派生类,不能像TButton(i)这种方式可以将变量强制转换言之成任何类型。还请各位高手指点!谢谢!
      

  5.   

    i:=TObject.Create;
      (i as TButton).Parent:=self;
      (i as TButton).Caption:='强类型转换2';
      (i as TButton).Visible:=true;这样子的转换语法上是正确的,因为TButton 确实是一个TObject,打个比方:人也是一种动物,所以你把一种动物当成人看,语法上是不错的。因为(TAnimal as THuman),这个Animal可能可以跟人一样Eat(),也可能跟人一样Run(),这些都是动物可以作的,所以假如禁止这样的转换明显是不合理的。但是,假如你调用的是THuman 特有的方法呢,比如Talk(),那么就不一定可以了。这样编译期看来“不一定”的东西倒不如将他放倒运行期,跑不了就报错,这样不是更好吗?因为理智的程序员肯定不会犯((TDog as TAnimal) as THuman).Talk(); 这样的错误。
        一般来说,从子类向父类转换时不会出什么问题,父类向子类转换的时候就要小心。    关于接口的问题,我一般理解接口为Delphi 的interface ,但是在这个问题里面就把我说的接口当成interface 也许不是很确切。
      

  6.   

    首先,楼主看的那本书不太好,建议看看就行了,不要太当真,还要多参考一下其他资料。
    其中提到的
    if (Anobject is TEdit) then
      TEdit(Anobject).Text:='Hello World';
    [在书上讲到:这个例子中不能用as进行强制类型转换。]
    这个说法是错误的,可能书里的意思是在这里不用as转换也是安全的,因为前面已经用is判断过一道。正确的做法是,无用何时在进行向下转换是都应该采用as 而不是强制类型转换。向下转换是指把一个对象从父类型向子类型转换,as操作会判断这个对象是不是具体的子类型(或子类型的子类)然后转换,如果不行则会抛出异常。比如:
    var
      aEdit: TObject;
      aBtn: TObject;
      i: Integer;
    begin
      aEdit := TEdit.Create(nil); //因为TEdit是一个TObject的子类,所以可以直接赋值给一个TObject对象
      aBtn := TButton.Create(nil);
      (aEdit as TEdit).Text := 'OK'; //正常运行,因为aEdit是一个TEdit的对象
      (aBtn as TEdit).Text := 'error'; //抛出异常,因为aBtn不是TEdit对象
      (i as TEdit).Text := 'error';  //无法编译通过,不合法的转换
    end;而强制转换一般是用来对基本类型进行转换的,比如:
    var
      s: string;
    begin
      s := 'ok'
      MessageBox(0, nil, PChar(s), nil, 0);
    end;
    编译器会根据转换的类型的大小和具体情况决定是否可以转换,转换的规则等。而所有的对象对于编译器而言都是一个对象引用(可以近似的认为是一个指针),在两个对象引用之间进行强制转换,就是把一个地址的内容认为是转换到的类型的布局,这个转换是很不安全的,可能引发不能预测的问题。
    比如,TEdit在内存中可能以这样的一张表保存(只是示例,具体的对象在内存的保存方式请查相关资料)
        起始地址:  Name: XXXXXXXX
        偏移10字节:Text:XXXXXXXX
        ……………………
    而TBtn可能是这样:
        起始地址:   Name: XXXXXXXX
        偏移5字节: Caption:XXXXXX
        ……………………
    TEdit(aBtn).Text := 'OK';执行的结果就是,在aBtn的偏移10字节处写下了'OK'的内容,然而这个操作的后果却无法预知。可能会内存越界,也可能改写了根本无意改动的数据。因此,对于对象而言,永远不要用强制转换。