【问题标题】:Problem with Delphi 2009 and old-style object typeDelphi 2009 和旧式对象类型的问题
【发布时间】:2009-06-18 15:48:31
【问题描述】:

我有很多使用旧式pascal 对象类型的旧代码,我试图在Delphi 2009 中工作。它可以编译,但处理虚拟方法似乎存在一些问题。此问题似乎已在 Quality Central 上报告:

http://qc.embarcadero.com/wc/qcmain.aspx?d=71723

我希望任何仍在使用这些的人(也许是 PatrickvL?)可以提供更多信息。我们有很多使用对象的代码,如果不能解决这个问题,我们就会陷入困境。提前致谢!

【问题讨论】:

    标签: delphi object delphi-2009


    【解决方案1】:

    如果您使用虚拟方法,那么您显然是通过引用访问对象,而不是通过值。这就是类在 Delphi 中的工作方式,因此切换到类应该不会太难。

    对于任何具有虚方法的对象类型,您应该能够将它们转换为记录。现在允许记录具有方法以及可见性说明符。不过,不支持继承。

    自 1994 年 2 月 14 日(即 Delphi 第一个版本的发布日期)起,旧式对象已被弃用。从那以后,它们一直在恶化。几年前你就应该远离他们了。

    【讨论】:

    • 是的,我意识到将所有内容转换为类都可以,不幸的是,鉴于我们的代码状态,这样做是一项艰巨的任务。是的,我同意我们应该在几年前离开他们,但这不是我的决定。我希望看到我们将它们全部转换为类,但到目前为止它们工作得很好,所以为什么要改变它们,对吧?也许这将成为促使我们转变他们的催化剂。
    • 次要 nit:1995 ;-) 相信我。我的妻子永远不会让我忘记那个日期。
    • @Allen,旧式对象是不是就像在 Embarcadero 内部对待 BDE 一样已经死了(“即使你在 QC 上获得一千票,我们也绝不会在 BDE 的开发上投入一秒钟” - 我是通过阅读 Codegear 员工对新闻组问题的回复得知的)还是有一些希望?
    • @Allen Bauer,1995 年你和帕斯卡之间发生了什么事,让你的妻子对她仍然没有原谅你感到非常沮丧? :-)
    【解决方案2】:

    我必须承认我有几杯啤酒在看这个,只是为了挑战:) 你需要一些神奇的字节。根据传说,如果您使用任何虚拟方法,旧样式对象只会为指针创建空间。没有虚拟方法没有 VMT。

    VMT 指针总是在新样式对象的前面,因为它们都声明了虚拟方法。似乎有人忘记了旧式对象的 VMT 可以稍后出现。所以假设它只有一个指针,这使它可以在我的 D2009 上工作。我不喜欢编译器,一个叫 Dave Jewell 的人曾经为 PC pro 写过代码,他可能会证实这将是稳定的......

    Type
      PObject1 = ^TObject1;
      TObject1 = Object
        Magic: Array[0..3] of Byte; //or integer or whatever I was playing with the size
        FCount     : Integer;
        Constructor Init;
        Procedure Add; virtual; 
        Procedure Deduct; virtual; 
        end;
    
    Type
      PObject2   = ^TObject2;
      TObject2   = Object(TObject1)
        Constructor Init;
        end;
    

    然后在构建这些工作之后:

    .
    .
    .
    Object2^.Add;
    Object2^.Deduct;
    

    我得到了适当的控制台输出

    我添加了一个额外的过程只是为了确保它适用于 2 个虚拟 :)

    顺便说一句,无论您是否输入 ^,它们都可以工作 2009 知道您的意思:(

    缺乏来自 embracodeland 的适当修复 您可能仍然需要更改每个 BASE 对象定义。希望您可以使用 find 和 insert/replace 或 Grep...祝您好运。

    【讨论】:

    • 不幸的是,这对我不起作用。尝试在您的后代类(作为虚拟)中再次定义 Add 或 Deduct 方法......这应该会崩溃。我认为您可能走在正确的轨道上。在我的情况下,后代对象是在另一个单元中定义的。我注意到,如果我从基础对象中删除所有变量,它似乎工作正常。或者,如果我在与基础对象相同的单元中声明后代对象,即使使用在基础对象中声明的变量,它也可以正常工作。非常感谢您花时间看这个,我很感激!
    【解决方案3】:

    好的 - 完成了 - 我不能让它失败.... 您的 D2009 是否已完全修补? 项目/编译器选项?

    为了绝对确定和比较,这里是我的单位:

    ---------------项目文件

    program testD2009;
    
    {$APPTYPE CONSOLE}
    
    uses
      SysUtils,
      Object1U in 'Object1U.pas',
      Object2U in 'Object2U.pas';
    
    
    Var
      Object1 : PObject1;
      Object2 : PObject2;
    begin
      try
        Object1 := New(PObject1,Init);
        Object1^.Add;
        Object1^.Deduct;
    
        Object2 := New(PObject2,Init);
        Object2^.Add;
        Object2^.Deduct;
        readln;
      except
        on E:Exception do
          Writeln(E.Classname, ': ', E.Message);
      end;
    end.
    

    -------------Object1 单位

    unit Object1U;
    
    interface
    
    uses SysUtils;
    
    Type
      PObject1 = ^TObject1;
      TObject1 = Object
        Magic: Array[0..3] of Byte;
        FCount     : Integer;
        Constructor Init;
        Procedure Add; virtual; { removing virtual allows the program to run }
        Procedure Deduct; virtual; { removing virtual allows the program to run }
        end;
    
    implementation
    
    
    Procedure TObject1.Add;
    begin
      Writeln('Object1 Add');
    end;
    
    procedure TObject1.Deduct;
    begin
      Writeln('Object1 Deduct');
    end;
    
    Constructor TObject1.Init;
    begin
      inherited;
      FCount      := 0;
      Writeln('TObject1 Init');
    end;
    
    end.
    

    ----------------对象2单元

    unit Object2U;
    
    interface
    
    uses Object1U;
    
    Type
      PObject2   = ^TObject2;
      TObject2   = Object(TObject1)
        Constructor Init;
        Procedure Add; virtual; { removing virtual allows the program to run }
        Procedure Deduct; virtual; { removing virtual allows the program to run }
       end;
    
    implementation
    
    procedure TObject2.Add;
    begin
      Writeln('Object2 Add');
      inherited;
    end;
    
    procedure TObject2.Deduct;
    begin
      Writeln('Object2 Deduct');
      inherited;
    end;
    
    Constructor TObject2.Init;
    begin
      Inherited Init;
      fCount := 1;
      Writeln('TObject2:Init');
    end;
    
    end.
    

    ----------------程序输出:

    TObject1 初始化 对象 1 添加 对象1扣除 TObject1 初始化 TObject2:初始化 对象 2 添加 对象 1 添加 对象2扣除 对象1扣除

    我很困惑:)。

    【讨论】:

    • Tim- 我知道为什么我的崩溃了而你的没有。试试这个...在你的 TObject2 后代对象中注释掉你的 Init 构造函数(我的后代对象中没有定义一个)。然后从基础对象 (TObject1) 的 Init 构造函数中调用 Add。理论上这应该调用 TObject2.Add,但会崩溃。我在 Delphi 2006 中测试了完全相同的应用程序,它正确调用了 TObjec2.Add 方法而不会崩溃。
    • @Martin:这似乎是 QC 需要考虑的事情,即使旧对象已被弃用,也许他们可以恢复它。
    • @Argalatyr:我原来的问题有 QC 报告的链接。
    【解决方案4】:

    我就这个问题向 Embarcadero 的当地代表发送了一封电子邮件,并让他们参考 Quality Central 上的报告。他们基本上告诉我们将所有对象移动到类,所以我猜他们不打算修复这个......永远。我想我们已经基本接受了,如果我们想继续前进,这是我们必须走的路,所以现在我们只需要安排好这项工作,然后才能继续升级到 Delphi 2009。

    只是想感谢所有试图提供帮助的人,但我相信在这一点上这是一个失败的原因:-(

    【讨论】:

    • 是的 - 这是正确的做法。依靠魔法带有“不要惹恼巫师......警告:(祝你好运 - 你可能会发现你想象的更容易。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-03-22
    • 1970-01-01
    • 1970-01-01
    • 2012-01-02
    相关资源
    最近更新 更多