-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

2 つの異なるローカル変数の位置を比較しているため、常に true と評価されます。

b.MYType.AsDer.a

AsDerのインスタンスを返さないため、実行時エラーですTDer。したがって、書き込みを試みるとa、実行時エラーが発生します。これは、あなたが参照しているためでSelfあり、それがこのコードが失敗する理由ですが、以前の呼び出しはそうでSay2はありません。


ここで何をしようとしているのかよくわかりませんが、すべて間違っているようです。クラス メソッドではなくインスタンス メソッドを使用している場合でも、基本クラスのインスタンスを派生クラスのインスタンスに大文字小文字を区別するのは単純に間違っています。何かが間違ったタイプである場合、いくらキャストしても正しいタイプにはなりません。

TBaseさらに、型であると仮定する方法を持つコードを書くべきではありませんTDerived。基本クラスは、その派生クラスについてまったく何も知らない必要があります。これは、OOP 設計の非常に基本的な原則の 1 つです。

于 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 に答える