Delphi编译bug还是我的错误?

时间:2012-02-28 16:31:55

标签: delphi

以下项目无法以“访问冲突”错误运行。我使用Delphi XE2 Update 3。

program Project1;

{$APPTYPE CONSOLE}

type
  TTestClass = class
  public
    class procedure Test;
  end;

var
  TestClass: TTestClass;

class procedure TTestClass.Test;
begin
end;

begin
  TestClass.Test;
end.

如果我将class procedure Test标记为“静态”,则没有问题。这是'设计'吗?

P.S。:这是我的错,对我感到羞耻。

5 个答案:

答案 0 :(得分:7)

是的,你目睹的是正确的。

非静态类方法与实例方法一样,具有隐藏的Self参数。对于类方法,它引用类引用。这就像编译器将您的方法转换为:

type
  TTestClassClass = class of TTestClass;

procedure TTestClass_Test(Self: TTestClassClass);

当您在非类接收器(即对象引用)上调用类方法时,编译器会插入对ClassType的调用,以使用运行时对象的类型,如下所示:

TTestClass_Test(TestClass.ClassType);

ClassType方法获取对象的VMT的地址,但您的变量不引用任何VMT。您的变量是空指针或未初始化,因此如果您很幸运,尝试取消引用它以读取VMT地址会导致访问冲突。 (如果你运气不好,它会取消引用地址,并且地址恰好位于程序地址空间的其他位置,并且结果被解释为VMT指针,即使它不是。)

仅对类引用或有效对象引用调用类方法。

TTestClass.Test;

如上所述在类引用“literal”上调用它时,编译器已经知道第一个参数的值并转换调用,如下所示:

TTestClass_Test(TTestClass);

答案 1 :(得分:2)

听起来很合理。 TestClass是零。您不能在非实例上调用非静态类方法:

'可以通过类引用或对象引用来调用类方法。当通过对象引用调用它时,对象的类变为Self'的值 - 没有对象,没有类。

'类静态方法可以在没有对象引用的情况下访问' - 由于对类方法的直接静态调用,与TestClass实例无关。

答案 2 :(得分:1)

您正在调用nil引用上的方法。甚至类方法使用它们被调用的对象来确定运行时变量的实际类型。你必须这样做

TestClass := TTestClass.Create;

要实际创建该类的实例,那么

FreeAndNil(TestClass);

解除分配。

如果你这样做

TTestClass.Test;

然后在编译时解析调用,因为它不依赖于变量的类型,所以它可以工作。

答案 3 :(得分:0)

问题是,虽然你有一个TTestClass的声明变量,但你没有实例化。您需要在使用Test方法之前调用Create,否则它将失败(除了静态,不需要实例化整个类)。所以你的主要代码是

begin  
  TestClass := TTestClass.Create;  
  TestClass.Test;  
  TestClass.Free;  
end.

答案 4 :(得分:0)

以下在XE中完美运行,它似乎是你的Delphi版本中的一个错误,你的代码是正确的,只要它不在类中调用“私有”变量而不是实例,但我认为你已经明白了。

program Project1;

{$APPTYPE CONSOLE}

uses
  SysUtils;

type
  TTest = class
  public
    class procedure test;
  end;

{ TTest }

class procedure TTest.test;
begin
  Writeln('hello');
end;

begin
  try
    TTest.test;
    Readln;
  except
    on E: Exception do
      Writeln(E.ClassName, ': ', E.Message);
  end;
end.