我定义了一个抽象类:
type TAbsClass = class
...
end;有两三个子类继承了这个抽象类:
type ConcreteClass1 = class(TAbsClass)
...
end;type ConcreteClass2 = class(TAbsClass)
...
end;type ConcreteClass3 = class(TAbsClass)
...
end;显然,如下的成立:
ConcreteClass1 a = ConcreateClass1.Create;
TObject b = a;
TAbsClass a = ConcreteClass1(b);  ------------(key1)现在有一个子类对象obj,不知道是ConcreteClass1,ConcreteClass2,ConcreteClass3
中的哪一个,所以我想知道它的类型,这一步我已经解决了,即obj.ClassType,它是TClass型的不仅仅如此,最重要的是:
我要实现(key1)这一步,我用的方法是:
var
classtype:TClass;
begin
  ....
  TObject b = a;  ---------------(a的类型是ConcreteClass1、2、3中的一个,不知道是哪一个)
  classtype:=a.ClassType;
  TAbsClass a = classtype(b);  ------------(key2)
  ....
end;以上代码我想实现的,但(key2)这一步出错了,不知道如何解决,谢谢

解决方案 »

  1.   

    上面地方写错了,应该把(key1)(key2)中a改成c,修改如下:ConcreteClass1 a = ConcreateClass1.Create; 
    TObject b = a; 
    TAbsClass c = ConcreteClass1(b);  ------------(key1) 
    TObject b = a;  ---------------(a的类型是ConcreteClass1、2、3中的一个,不知道是哪一个) 
    classtype:=a.ClassType; 
    TAbsClass c = classtype(b);  ------------(key2) 
      

  2.   

    你这种需求是不存在的。
    如果你这么写TAbsClass c = classtype(b);
    就算classtype是ConcreteClass1,对于你来说也没有用,因为c的类型被定义为TAbsClass,你在后面的代码中仍然只能针对c调用TAbsClass的方法。
      

  3.   

    The is operator
    The is operator, which performs dynamic type checking, is used to verify the actual runtime class of an object. The expressionobject is classreturns True if object is an instance of the class denoted by class or one of its descendants, and False otherwise. (If object is nil, the result is False.) If the declared type of object is unrelated to class--that is, if the types are distinct and one is not an ancestor of the other--a compilation error results. For example,if ActiveControl is TEdit then TEdit(ActiveControl).SelectAll;This statement casts a variable to TEdit after first verifying that the object it references is an instance of TEdit or one of its descendants.
      

  4.   

    你要干嘛? 为了实现什么? 不是为了抽象而抽象吧?
    你这里直接赋值就行了,为何要类型转换(看样子你是想做类型转换)。
    子类赋值给父类是可以直接赋值的,比如:
    TAbsClass a = ConcreateClass1.Create; 如果你的这几个类有公共的行为,单行为具体操作不一样,可以定义为抽象方法,然后各个子类分别重载之。如:
    type TAbsClass = class 
      public 
        procedure LoadData; virtual; abstract;
    end; 
    然后子类可以实现这些方法:
    type ConcreteClass1 = class(TAbsClass) 
      public 
        procedure LoadData; Override;
    end; 调用是,可以
    TAbsClass a = ConcreateClass1.Create; 
    a.LoadData
    即可,无需考虑实际用的是那个子类的实例。
      

  5.   

    楼上,说得通俗点,楼主是想动态转换。
    譬如:AClass: TClass;
    AClass可以使TForm、TButton,楼主他有个对象AContorl
    他想在AClass是TForm的时候就TForm(AControl)来转换为TForm,而在AClass是TButton的时候就TButton(AControl)来转换为TButton。
    于是写法就成了AClass(AControl)
      

  6.   

    5楼说得对,我的意思就是这个,因为有很多的ConcreateClass1,2,3的实例对象,如果要一个个判断再执行相同名字的函数的话,要用n多的if else语句。
      

  7.   

    楼主是不是这个意思
    var
    B:ConcreteClass1;
    C:ConcreteClass2;
    D:ConcreteClass3;begin
    B:=ConcreteClass1.Create;
    C:=ConcreteClass2.Create;
    C.Assign(B); //把C变成B的克隆
    ....这样能不能解决你的问题?
      

  8.   

    不建议再用抽像了, 用接口 interface 代之抽像类的声明都错了type 
    TAbsClass = class 
    protected
      procedure Test; vier abstract;
    end; TConcreteClass1 = class(TAbsClass) 
    protected
      procedure Test; override;
    end;var
      Abs: TAbsClass;
    begin
      Abs := TCocreateClass1.Create;
      Abs.Test;
    end;
     
      

  9.   

    2楼 lake_cx,我试过了,是可以的,可以调用ConcreteClass1,2,3的方法,现在的问题就是我一开始说的方法。10楼 cncharles,其实我一开始用的就是interface,但是http://www.netinter.cn/info/html/chengxusheji/delphi/20080403/53788.html"不能把一个对象引用强制转换成这个引用的类型没有声明实现的接口,即使这个对象实际实现了这个接口(呵呵,优点拗口)"这样怎么实现多态?我的代码:
    Path:THashedStringList;
    eachPath:AbsPath;  Path:=THashedStringList.Create;
      for I := 0 to length(readXML.SearchNetArr) - 1 do
      begin
        eachPath:=readXML.SearchNetArr[i];
        Path.AddObject('sNet'+inttostr(i),eachPath); -----(key)
      end;
    抽象类是Abspath,其子类是SearchNet,OpenNetGroup,LnkpathGroup
    每个searchNetArr[n]是SearchNet型对象,如果abspath是interface型的话,(key)这一句就不能执行,原因是上面
    那句引号中的话。也可以打开那个网址看一下。
      

  10.   

    楼主你的思路实在有点乱,描述个问题都描述不清楚
    你直接说你要实现什么目的吧
    正如你在一楼写的,就算TAbsClass a = classtype(b);能够编译通过
    你想在下面写什么语句呢?a.***(难不成这儿写ConcreteClass1的方法?),显然是不对的。
    如果写的是TAbsClass的方法,那直接用TAbsClass a = b as TAbsClass;不就行了。
      

  11.   

    to 楼主, 我都不知道那篇文章的作者到底会不会用 interface, 现在主流的言语都用接口了, 基本没有人再用 abstract了, 我们常用的TComponent都用到了IInterface, IInterfaceComponentReference 这两个接口, 著名的第三方组件 DevExpress 源代码中 interface 则更多。
      

  12.   

    满足下面其中一个条件的前提下,楼主的问题可以这样解决:1、TAbsClass的构造函数是虚函数,ConcreteClass1、ConcreteClass2、ConcreteClass3的构造函数要更改构造函数的行为时,覆盖TAbsClass中的构造函数。
    2、ConcreteClass1、ConcreteClass2、ConcreteClass3中的构造函数没改动,和TAbsClass一样,那么TAbsClass可以不是虚函数
    type
      TAbsClassClass = class of TAbsClass;var
      c: TAbsClass;
    begin
      //a是ConcreteClass1时,c就是ConcreteClass1;a是ConcreteClass2时,c就是ConcreteClass2…
      c := TAbsClassClass(a.ClassType).Create;
      c.Free;
    end;
    楼主这种做法在克隆对象时会用到的,可以参考RemObjects里面TROComplexType的Clone的实现。楼主出错主要是没有分清楚对象引用和类引用。
      

  13.   

    Interface不能替代abstract,接口和抽象类各有用处。
      

  14.   

    Delphi中的接口是还不够完善
    因为TObject本来没有实现IUnkown,但实际上作者说的第一个问题可以用GetInterface方法解决,事实上,接口转换都是用QueryInterface查询的,而QueryInterface的默认实现一般都是用TObject.GetInterface方法,作者提出这点是没有仔细研究Delphi中的接口实现。
    作者所说的第二点是由于Delphi实现的是COM接口,它是二进制级别的封装,因此从一个模块到另一个模块中没有代码复用,即时将接口转换成原来的对象也没有意义和价值。
    作者所说的第三点仍然是由于Delphi实现的是COM接口,说实话我也比较讨厌这种特点,我压根就不喜欢接口来管理生命周期,因为我的接口很多时候是用对象来管理生命周期的,接口只是对外提供功能而已。不过这一切在.NET和Java中都因为引用计数和垃圾回收而处理得非常漂亮了。如果是接口,楼主你可以这么写
    Path.AddObject('sNet'+inttostr(i),Pointer(eachPath)); -----(key)
    楼主你要看清本质,在Delphi中接口不是对象,因此不能转换,但接口是指针,而对象也是指针,都是四个字节,我们可以抛开对象概念,把他们当数据来存储就行了。
      

  15.   


    "正如你在一楼写的,就算TAbsClass a = classtype(b);能够编译通过,你想在下面写什么语句呢?"这样就可以了,我的目的达到了,下面写什么语句还有什么关系呢?
      

  16.   

    TAbsClass a = classtype(b);
    你下面不写其他语句了,那拿到了这个a干嘛用?