我想要使用类函数进行类型转换。 我有基(TBase),派生(TDer)和类型转换(TMyType)类。
Ver:Delphi 7
TBase = class;
TDer = class;
TMyType = class;
TBase = class
function Say : String;
class function MYType:TMyType;
end;
TDer = class(TBase)
a: string;
b: string;
function Say2 : String;
end;
TMyType=class(TBase)
class function AsDer:TDer;
end;
{ TBase }
class function TBase.MYType: TMyType;
begin
Result:=TMyType(Self);
end;
function TBase.Say: String;
begin
Result:='TBase';
end;
{ TDer }
function TDer.Say2: String;
begin
Result:='TDer';
end;
{ TMyType }
class function TMyType.AsDer: TDer;
begin
Assert(Assigned(Self));
Result := TDer(Self) ;
end;
示例用法如下,它是调用方法,但是当设置/获取字段的引发错误时。
procedure TForm1.Button1Click(Sender: TObject);
var
b,c:TBase;
begin
b:=TDer.Create;
c:=b.MYType.AsDer;
ShowMessage(b.MYType.AsDer.Say2); // OK. Running
if (@b<>@c) then ShowMessage('Not Equal'); // Shows message, Why ?
b.MYType.AsDer.a:='hey'; // Error
FreeAndNil(b);
end;
你有什么想法吗?
答案 0 :(得分:6)
根本问题在于:
class function TBase.MYType: TMyType;
begin
Result:=TMyType(Self);
end;
这是一种类方法,因此Self
指的是类,而不是实例。将它作为一个实例进行转换并不是这样。您的AsDer
类函数中出现了完全相同的错误。
查看细节,调用
b.MYType.AsDer.Say2
是良性的,似乎工作正常,因为它没有引用Self
。您可以同样编写TDer(nil).Say2
并且该代码也可以正常工作。现在,如果函数Say2
引用Self
,即引用实例,则会出现运行时错误。
@b<>@c
总是计算为true,因为您正在比较两个不同局部变量的位置。
b.MYType.AsDer.a
是运行时错误,因为AsDer
未返回TDer
的实例。因此,当您尝试写入a
时,您会遇到运行时错误。这是因为您指的是Self
,这就是为什么此代码失败,但之前对Say2
的调用没有。
我不确定你在这里要做什么,但看起来都错了。即使您使用的是实例方法而不是类方法,将基类实例用于派生类实例也是错误的。如果某些东西是错误的类型,那么任何数量的铸造都不会将它变成正确的类型。
此外,您永远不应该编写方法为TBase
的代码,假设它是TDerived
类型。基类应该完全不知道它的派生类。这是OOP设计的基本原则之一。
答案 1 :(得分:0)
以下是编辑的新版本:
TBase = class;
TDer = class;
TMyType = class;
TBase = class
MYType:TMyType;
constructor Create;
destructor Destroy;
function Say : String;
end;
TDer = class(TBase)
a: string;
b: string;
function Say2 : String;
end;
TMyType=class
public
T: TObject;
function AsDer:TDer;
end;
{ TBase }
constructor TBase.Create;
begin
MYType:=TMYType.Create;
MYType.T:=TObject(Self);
end;
destructor TBase.Destroy;
begin
MYType.Free;
end;
function TBase.Say: String;
begin
Result:='TBase';
end;
{ TDer }
function TDer.Say2: String;
begin
Result:='TDer';
end;
{ TMyType }
function TMyType.AsDer: TDer;
begin
Result := TDer(T) ;
end;
procedure TForm1.Button1Click(Sender: TObject);
var
b:TBase;
c:TDer;
begin
b:=TDer.Create;
TDer(b).a:='a';
c:=b.MYType.AsDer;
ShowMessage('b.MYType.AsDer='+b.MYType.AsDer.a+', c.a ='+ c.a); // OK. Running
FreeAndNil(b);
end;