12.3 类引用
在了解了与方法相关的几个主题后,我们现在可以转向类引用的主题,并进一步扩展我们动态创建组件的示例。首先要记住的一点是,类引用不是一个类,不是一个对象,也不是一个对象引用;它只是对类类型的引用。换句话说,类引用数据类型的变量以类为值。
类引用类型决定了类引用变量的类型。听起来很费解?几行代码可能会让你更清楚。假设你已经定义了类 TMyClass。现在可以定义一个与该类相关的新的类引用类型:
type
TMyClassRef = class of TMyClass;
现在你可以声明两种类型的变量。第一个变量指向一个对象,第二个变量指向一个类:
var
AClassRef: TMyClassRef;
AnObject: TMyClass;
begin
AClassRef := TMyClass;
AnObject := TMyClass.Create;
你可能想知道类引用有什么用。一般来说,类引用允许你在运行时操控类的数据类型。在任何可以合法使用数据类型的表达式中,都可以使用类引用。实际上,这样的表达式并不多,但为数不多的几种情况却很有趣。最简单的情况是创建对象。我们可以将上面两行重写如下:
AClassRef := TMyClass;
AnObject := AClassRef.Create;
这次我将 Create 构造函数应用于类引用,而不是实际的类;我使用类引用创建了该类的一个对象。
类引用与其他 OOP 语言中的元类概念类似。然而,在 Object Pascal 中,类引用本身并不是一个类,而只是一个定义类类型数据引用的特定类型。因此,与元类(描述其他类的类)的类比有点误导。实际上,TMetaclass 也是 C++Builder 中使用的数据类型。
当你有一个类引用时,你可以访问该类的任何类方法。因此,如果 TMyClass 有一个名为 Foo 的类方法,你就可以编写以下任一代码:
TMyClass.Foo;
AClassRef.Foo;
如果类引用不支持与类类型相同的类型兼容性规则,那么这就不是很有用了。当你声明一个类引用变量时,比如上面的 MyClassRef,你就可以将特定的类和任何子类赋值给它。因此,如果 MyNewClass 是我们编写的类的子类,也可以写成
AClassRef := MyNewClass;
要理解为什么这样做会很有趣,你必须记住,你可以为类引用调用的类方法可以是Virtual类型,因此特定的子类可以覆盖它们。使用类引用和Virtual类方法,你可以在类方法级别实现一种形式的多态性,而其他静态 OOP 语言很少(如果有的话)支持这种多态性。此外,考虑到每个类都继承自 TObject,因此您可以在每个类引用中应用 TObject 的某些方法,包括 InstanceSize、ClassName、ParentClass 和 InheritsFrom。我将在第 17 章讨论这些类方法和 TObject 类的其他方法。