Oop 更改继承类中类字段的类型
我正在使用最新的Delphi 10.3.3 我有几个主要的类,它们是从相同的父类扩展而来的,还有一些反射类,我们称之为反射类,它们也有相同的父类。我希望main类的实例具有到相应反射实例的链接,但我遇到了这个问题(我将其简化为本例): 主要类别:Oop 更改继承类中类字段的类型,oop,delphi,pascal,Oop,Delphi,Pascal,我正在使用最新的Delphi 10.3.3 我有几个主要的类,它们是从相同的父类扩展而来的,还有一些反射类,我们称之为反射类,它们也有相同的父类。我希望main类的实例具有到相应反射实例的链接,但我遇到了这个问题(我将其简化为本例): 主要类别: TMainClass = class Link: TReflectionClass; end; TCarMainClass = class(TMainClass) Link: TCarReflectionClass; end; TReflec
TMainClass = class
Link: TReflectionClass;
end;
TCarMainClass = class(TMainClass)
Link: TCarReflectionClass;
end;
TReflectionClass = class;
TCarReflectionClass = class(TReflectionClass);
反射类:
TMainClass = class
Link: TReflectionClass;
end;
TCarMainClass = class(TMainClass)
Link: TCarReflectionClass;
end;
TReflectionClass = class;
TCarReflectionClass = class(TReflectionClass);
问题在于链接字段。我希望将TCarMainClass中的链接字段直接定义为TCarReflectionClass,以避免在许多代码段上进行类型转换(也有可能出现一些错误),但是,如果我这样定义类,TCarMainClass.Link只会隐藏TMainClass.Link-它被定义为具有相同名称的不同字段。这并不好,因为它会消耗额外的内存,而且主要是我无法从父类访问该字段,而我需要父类(作为指向泛型实例的指针)
当然,我可以通过将字段设置为公共类型的私有字段并定义属性setter/getter来解决这个问题,该属性setter/getter处理每个类中的重新类型。但这对于这些类来说是很多额外的代码,而且由于调用getter/setter方法,每个get/set都会有开销
我的问题是——我是否错过了一些简单的技巧,告诉编译器我希望子类中的字段和父类中的某个字段占用相同的内存位置
谢谢
主要是我无法从父类访问该字段
虽然父类确实无法访问子类的字段,但没有任何东西阻止您同步2
procedure TCarMainClass.SetLink(const Value : TCarReflectionClass);
begin
FLink := Value;
TMainClass(Self).FLink := Value;
end;
现在,如果您绝对不需要额外的内存使用和设置程序,那么剩下的唯一选项(我现在可以想到)就是GolezTrol建议的泛型
TMainClass<T : TReflectionClass> = class
Link: T;
end;
TCarMainClass = class(TMainClass<TCarReflectionClass>)
end;
TMainClass=class
链接:T;
结束;
TCarMainClass=类别(TMainClass)
结束;
但这可能会破坏您的设计,因为TCarMainClass将与
tmainlass
不兼容。(如果您想了解原因,请搜索术语协方差/逆变)。不确定Delphi的具体情况,但一般来说,您要做的不是类型安全的,因为字段是可变的。如果有人持有对基类实例的引用,并且编译时类型是基类的,那么他们可以使用基类的属性类型设置其属性值。该更改将通过其他引用可见,包括编译时类型承诺同一属性将具有比刚刚设置的更严格的类型的引用。因此,这种改变首先是不被允许的;你应该只对不可变的字段这样做。你会想到各种各样的解决方案,包括泛型和接口,但这两者都不会使它变得更轻,它们是否适用完全取决于你将如何使用它。你的问题在这方面有点含糊。不过,我对您的性能要求很好奇,若您想在这里避免添加getter和setter(OOP良好实践)。@kaya3实际上,这种情况是类型安全的,因为TCarReflectionClass也是从TrefllectionClass继承的,TrefllectionClass是另一个父类的类型。然而,这是真的(除非Delphi对这种情况进行特殊检查),它也允许不安全的强制转换。但是Delphi不太关心类型安全,它不像C#那样管理,所以它允许手动将任何类重新类型到任何类,在最坏的情况下会导致运行时错误。所以我的问题更多的是关于如何告诉编译器该做什么(如果可能的话),而不是如果可能的话-因为手动强制转换现在对我来说很好,这很烦人。@GolezTrol我在处理过程中经常访问这些链接,比如每秒数千万次。当我写一个像TCarReflectionClass(Obj.Link).DoSomething这样的代码时,它基本上是零成本转换——它只是告诉编译器我知道我在做什么,并且不会发出警告,但这个转换不会输出任何代码。当我使用getter时,它将需要调用过程,该过程将只执行这个虚拟的重新类型,并基本上转换为函数,结果为:=A;然而,这远远不是零成本,它对性能有点影响。基本上,我只想避免在代码中一直编写TCarReflectionClass(Obj.Link)。我想让编译器知道,若Obj是TCarMainClass,那个么Link不是TReflectionClass,而是tcarrefectionclass。我在一个代码和不同的类上使用了很多,并且使用了很多这样的强制转换,这确实降低了代码的可读性。