何时应该在Delphi中使用增强记录类型而不是类?

16

Delphi 2006引入了对记录的新功能,使它们更具“面向对象”的特性。

在哪种情况下,使用记录类型比类类型更适合设计?使用这些记录类型有哪些优势?


您可以查看我们的动态数组包装器,它为任何动态数组添加了类似TList的方法。它还能够序列化数组/记录内容。我还发现了Delphi 2010(至少)中一个关于对象的随机错误:有时,引用计数对象未初始化!在这种情况下,您必须使用记录来处理这样的结构。 - Arnaud Bouchez
4个回答

16
你有记录(Records)、对象(Objects)和类(Classes)。
记录自Turbo Pascal 1起就可用。它们轻巧,可以拥有属性和方法,但不支持继承。如果这些记录具有方法,则返回记录的函数有时会导致内部错误。
type
  TRec = record 
    function Method1: Integer;
  end;

function Func: TRec;


procedure Test;
var
  x : TRec;

begin
  Func.Method1; // Sometimes crashes the compiler
  // Circumvention:
  x := Func;
  x.Method1; // Works
end;

如果我没记错的话,对象是在Turbo Pascal 5中引入的。然后它们为Pascal提供了一种面向对象的方法。随着Delphi的引入,它们或多或少已经被弃用,但仍然可以使用。对象可以实现接口。

类是在Delphi 1中引入的,也是最通用的。它们实现接口并支持继承。但是每个类变量都是一个隐藏指针。这意味着类需要在堆上创建。幸运的是,这个过程大部分是隐藏的。

下面是三者之间的差异表格。我加上了接口以完整。

                  |Class|Object|Record|Interface|
------------------|-----------------------------|
Are pointers?     |  y  |  n   |  n   |    y    |
Inheritance       |  y  |  y   |  n   |    y    |
Helpers           |  y  |  n   |  y   |    n    |
Impl. Interface   |  y  |  y   |  n   |    -    |
Visibility        |  y  |  y   |  n   |    n    |
Method            |  y  |  y   |  y   |    y    |
Fields            |  y  |  y   |  y   |    n    | 
Properties        |  y  |  y   |  y   |    y    |
Consts            |  y  |  y   |  y   |    n    |
Types             |  y  |  y   |  y   |    n    |
Variants          |  n  |  n   |  y   |    n    |
Virtual           |  y  |  n   |  y   |    -    |
------------------|-----------------------------|

你能说一下在 Delphi 中对象是否仍然受支持吗?我知道有"procedure xx of object;",但是不记得在其他地方看到过。 - H H
是的,在D2009中仍支持对象。虽然没有对象助手,但对象可以实现接口。 - Toon Krijthe
1
“Object” 的 “procedure xx of Object” 结构用于声明方法的事件签名,据我所知与对象无关。 - Fabricio Araujo
很酷,从来不知道对象可以实现接口。得快速查看一下 FPC 是否支持。 - Marco van de Voort

9
我认为Delphi 8和2005版本也提供了这些功能。
主要准则:如果你有疑问,使用类。
对于其余部分,您需要了解主要区别:类对象始终通过引用使用,并通过调用构造函数创建。
记录的内存管理和分配与基本类型(例如整数、双精度)相同。这意味着它们按值传递给方法(除非使用var)。此外,您不需要释放记录,这就是它们支持运算符重载的原因。但是没有继承或虚方法等。新记录可以有一个构造函数,但它的使用有点可选。
使用记录的主要领域和标准:
- 处理来自Win32 API的结构体时 - 当类型没有身份时(因为赋值意味着复制) - 当实例不太大时(复制大型记录变得昂贵) - 构建应模仿数字类型行为的值类型。例如DateTime、复数、向量等。然后运算符重载是一个很好的特性,但不要将其作为决定因素。
就效率而言,不要过度使用以下内容:
- 对于经常放入数组中的较小类型。
最后,使用类或记录的规则与Delphi早期版本没有真正改变。

它们可用于Delphi.NET平台,但直到2007年才能用于win32 Delphi。 - DiGi
mjustin没有具体说明D2005/win32有哪些功能,但是属性、方法和公共/私有都是存在的。 - H H

6
除了其他答案(运算符重载,轻量级值类型)之外,将枚举器设为记录而不是类的好主意。由于它们分配在堆栈上,因此无需构造和销毁它们,这也消除了编译器在类类型枚举器周围放置的隐藏try..finally块的需要。
有关更多信息,请参见http://hallvards.blogspot.com/2007/10/more-fun-with-enumerators.html

1

您可以使用运算符重载(例如隐式转换)。这在Delphi 2007+或2006.NET上也可以对对象进行操作,但仅限于2006 win32上的这些记录。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接