我正在练习 Delphi 跟踪,并遵循 Delphi 如何为表单生成代码,回答了如下基本问题之一:
unit uLeap;
interface
type
TSYear = class
public
{ public declarations here }
function isLeap(y: integer): boolean;
end;
var
TYear: TSYear;
implementation
function TSYear.isLeap(y: integer): boolean;
begin
result := ((y mod 4) = 0) and (((y mod 400) = 0) or ((y mod 100) <> 0));
end;
end.
Run Code Online (Sandbox Code Playgroud)
代码编译时没有任何抱怨,我可以逐步运行它,并且“isLeap”函数以这种方式从另一个单元多次调用:
procedure YearTest.year_divisible_by_4_not_divisible_by_100_leap_year;
begin
assert.IsTrue(TYear.IsLeap(1996), 'Expected ''true'', 1996 is a leap year.');
end;
...
Run Code Online (Sandbox Code Playgroud)
我从来没有明确地创建过这个类的实例,但似乎 Delphi 正在某处做它,也许是在声明 TYear 时?这是一种有效的方式吗?
尽管通过了所有测试,代码还是被拒绝了,因为它不是以传统方式完成的。我肯定会最终以不同的方式接受它,但是,除了糟糕的命名之外,为什么这有效?这段代码会在这个简单的例子中我看不到的地方引起问题吗?
And*_*and 10
我从来没有明确地创建过这个类的实例,但似乎 Delphi 正在某处做它,也许是在声明 TYear 时?
不,Delphi 不会自动创建您的实例。当您声明一个类类型的变量时,它只是一个可以指向有效实例的指针变量。但是您必须始终自己创建此实例,并将指针保存在变量中:
SYear := TSYear.Create; // create a `TSYear` object and save its address in `SYear`
Run Code Online (Sandbox Code Playgroud)
这是一种有效的方式吗?
不。
[W] 为什么这有效?
因为您很幸运:该isLeap函数不会访问类实例上的任何字段。
这段代码会在这个简单的例子中我看不到的地方引起问题吗?
如果该函数一直在使用类实例中的任何字段,那么如果幸运的话,您最终会得到一个 AV,而如果不幸的话,您会得到内存损坏。
解决方案是创建一个实例并使用它:
SYear := TSYear.Create;
try
ShowMessage(BoolToStr(SYear.IsLeap(2000), True));
finally
SYear.Free;
end;
Run Code Online (Sandbox Code Playgroud)
或者,由于您显然不需要任何实例变量来确定年份是否为闰年,因此最好将此class方法设为:
SYear := TSYear.Create; // create a `TSYear` object and save its address in `SYear`
Run Code Online (Sandbox Code Playgroud)
这样,它可以在没有任何类实例的情况下被调用:TSYear.IsLeap(2000)。请注意,这TSYear是类(类型)名称,而不是该类型的变量。
有关所有这些概念的概念介绍,请参阅文档。
| 归档时间: |
|
| 查看次数: |
104 次 |
| 最近记录: |