-1

我想使用类函数进行类型转换。我有基础(TBase)、派生(TDer)和类型转换(TMyType)类。

版本:德尔福 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;

你有什么主意吗?

4

2 回答 2

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

总是评估为真,因为您正在比较两个不同局部变量的位置。

b.MYType.AsDer.a

是运行时错误,因为AsDer不返回TDer. 因此,当您尝试写入时,a您会遇到运行时错误。这是因为您指的是Self,这就是该代码失败的原因,但之前的调用Say2没有。


我不太确定你想在这里做什么,但它看起来全错了。即使您使用的是实例方法而不是类方法,将基类实例大小写为派生类实例也是错误的。如果某样东西是错误的类型,再多的转换也不会将它变成正确的类型。

此外,您永远不应该编写具有TBase假设它是 type的方法的代码TDerived。基类应该完全不知道它的派生类。这是 OOP 设计的基本原则之一。

于 2012-05-13T14:37:06.977 回答
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;
于 2012-05-14T05:06:19.117 回答