如何在Pascal的元类引用TList中正确访问类变量?
问题原因
Object Pascal中的class var定义的类变量属于静态绑定成员,不具备多态特性。编译器会根据变量声明时的静态类型解析成员地址,而非运行时的实际类型:
- 遍历用的循环变量
cipher静态类型是TCipherClass(基类元类),所以编译阶段cipher.sDisplayName就被绑定到了TCipher的类变量上,运行时即使实际指向TCaesar的元类,也只会返回基类的值。 - 直接写
TCaesar.sDisplayName时,编译器明确知道静态类型是TCaesar,所以会正确解析到子类的类变量。
解决方案
推荐使用虚类方法替代直接暴露类变量,虚类方法支持动态绑定,会根据运行时的实际元类类型调用对应实现,修改代码如下:
类定义修改
type TCipher = class private // 把类变量改为私有,不对外直接暴露 class var FsName: String; FsDisplayName: String; public function Encrypt(sText: String; Key: TObject): String; virtual; abstract; function Decrypt(sText: String; Key: TObject): String; virtual; abstract; // 新增虚类方法用于获取属性 class function GetName: String; virtual; class function GetDisplayName: String; virtual; end; TCipherClass = class of TCipher; TCaesar = class(TCipher) private // 子类同名类变量也改为私有 class var FsName: String; FsDisplayName: String; public function Encrypt(sText: String; Key: TObject): String; override; function Decrypt(sText: String; Key: TObject): String; override; // 重写基类的虚类方法 class function GetName: String; override; class function GetDisplayName: String; override; end; implementation // 基类方法实现 class function TCipher.GetName: String; begin Result := FsName; end; class function TCipher.GetDisplayName: String; begin Result := FsDisplayName; end; // 子类方法实现 class function TCaesar.GetName: String; begin Result := FsName; end; class function TCaesar.GetDisplayName: String; begin Result := FsDisplayName; end; // 原有初始化逻辑保持不变 initialization TCipher.FsName := 'defaultName'; TCipher.FsDisplayName := 'defaultDisplay'; ShowMessage(TCipher.GetName + ' ' + TCipher.GetDisplayName); TCaesar.FsName := 'caesar'; TCaesar.FsDisplayName := 'Caesar Cipher'; ShowMessage(TCaesar.GetName + ' ' + TCaesar.GetDisplayName);
遍历逻辑修改
调用虚类方法即可正确获取对应子类的属性值:
var lstCiphers: TList<TCipherClass>; cipher: TCipherClass; begin lstCiphers := TList<TCipherClass>.Create; lstCiphers.AddRange([TCaesar]); for cipher in lstCiphers do ShowMessage('In list: ' + cipher.ClassName + ' . ' + cipher.GetDisplayName); end;
内容的提问来源于stack exchange,提问作者user15400843
相关产品推荐
相关产品推荐

