gpt4 book ai didi

delphi - 从 Delphi 中的类引用变量访问类常量

转载 作者:行者123 更新时间:2023-12-03 14:47:48 25 4
gpt4 key购买 nike

我正在使用 Delphi 2007 维护一个旧项目,我在从类引用变量访问类常量时遇到问题,我始终获得父类常量而不是子类常量。

假设有一个父类、一些子类、一个类引用,最后有一个 const 数组来存储用于循环目的的类引用。

看一下下面的简单程序:

program TestClassConst;

{$APPTYPE CONSOLE}

uses
SysUtils;

type

TParent = class
const
ClassConst = 'BASE CLASS';
end;

TChild1 = class(TParent)
const
ClassConst = 'CHILD 1';
end;

TChild2 = class(TParent)
const
ClassConst = 'CHILD 2';
end;

TParentClass = class of TParent;
TChildClasses = array[0..1] of TParentClass;

const
ChildClasses: TChildClasses = (TChild1, TChild2);

var
i: integer;
c: TParentClass;
s: string;

begin
try
writeln;

writeln('looping through class reference array');
for i := low(ChildClasses) to high(ChildClasses) do begin
c := ChildClasses[i];
writeln(c.ClassName, ' -> ', c.ClassConst);
end;

writeln;

writeln('accessing classes directly');
writeln(TChild1.ClassName, ' -> ', TChild1.ClassConst);
writeln(TChild2.ClassName, ' -> ', TChild2.ClassConst);

except
on E: Exception do
Writeln(E.Classname, ': ', E.Message);
end;
end.

当它运行时我得到:

looping through class reference array
TChild1 -> BASE CLASS
TChild2 -> BASE CLASS

accessing classes directly
TChild1 -> CHILD 1
TChild2 -> CHILD 2

我希望在数组循环中看到“CHILD 1”和“CHILD 2”!

谁能解释一下为什么它不适用于类引用?

最佳答案

无类型类常量是添加了一些作用域的普通常量。
类型化类常量实际上是无法更改的类变量。
问题是类变量不是虚拟的。

Hallvard Vassbotn 在此撰写了有关此问题的文章:Part 1 , Part 2

您无法从类引用访问类变量和类常量,因为该语言不支持虚拟类变量。
当您说 s:= TClass1.SomeConst 时,编译器会将其转换为 s:= SomeGlobalButHiddenConst,然后再继续进行其余的编译。

class varclass const 只不过是语法糖。
因此,class var/const 和实际类之间的链接仅在编译时存在,它在运行时被破坏,就像 Java 中的类型删除一样。

RTTI 也没有帮助:Get constant fields from a class using RTTI
我想如果您使用 D2007,您唯一的选择是声明一个返回您想要的常量的虚函数:

D2010 之前的选项:虚拟方法

TParent = class
class function Name: string; virtual;
end;

TChild1 = class(TParent)
class function name: string; override;
....
class function TParent.name: string;
begin
Result:= Self.ClassConst;
end;

class function TChild1.name: string;
begin
Result:= Self.ClassConst; //Silly copy paste solution
end;

这是一个令人悲伤的情况,但我看不到其他选择。

<强> From Delphi 2010 onwards :使用attributes
更好的选择是使用属性,您可以使用 RTTI 访问这些属性。 :

以下代码有效:

program TestClassConst;

{$APPTYPE CONSOLE}

uses
SysUtils, rtti;

type

NameAttribute = class(TCustomAttribute)
private
Fname: string;
public
constructor Create(const Name: string);
property Name: string read Fname;
end;

[Name('Base class')]
TParent = class
const
ClassConst = 'BASE CLASS';
private
public
class function Name: string;
end;

[Name('Child 1')]
TChild1 = class(TParent)
const
ClassConst = 'CHILD 1';
end;

[Name('Child 2')]
TChild2 = class(TParent)
const
ClassConst = 'CHILD 2';
end;

TParentClass = class of TParent;
TChildClasses = array[0..1] of TParentClass;

const
ChildClasses: TChildClasses = (TChild1, TChild2);

var
i: integer;
c: TParentClass;
s: string;

{ TParent }

class function TParent.Name: string;
var
Context: TRttiContext;
ClassData: TRttiType;
Attr: TCustomAttribute;
begin
Context:= TRttiContext.Create;
ClassData:= Context.GetType(Self);
try
for Attr in ClassData.GetAttributes do begin
if Attr is NameAttribute then Result:= NameAttribute(Attr).Name;
end;
finally
ClassData.Free;
end;
end;

{ NameAttribute }

constructor NameAttribute.Create(const Name: string);
begin
inherited Create;
FName:= name;
end;

begin
writeln;

writeln('looping through class reference array');
for i := low(ChildClasses) to high(ChildClasses) do begin
c := ChildClasses[i];
writeln(c.ClassName, ' -> ', c.Name);
end;

writeln;

writeln('accessing classes directly');
writeln(TChild1.ClassName, ' -> ', TChild1.Name);
writeln(TChild2.ClassName, ' -> ', TChild2.Name);
readln;
end.

关于delphi - 从 Delphi 中的类引用变量访问类常量,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/37750107/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com