配列を戻り値にして参照・代入するには?

解決


ふみと  2004-01-13 05:29:49  No: 6671

はじめまして、最近delphiをはじめました。
が、DOSのC言語以来なので、今ひとつよくわかりません。
よろしければ、教えていただけるとありがたいです。

クラスのフィールドになっている配列を、
外部から参照および代入等をしたいのですが、
どうすればいいでしょうか?

Work := Test.ReadWork(0);

などとして、

Work[0] := 1;
Work[1] := Work[0] + 2;

のように、参照・代入等をしたいのですが¨

ソースはだいたい下記のような感じです。
(デストラクタ等は省略してます。)

いろいろ調べてみたのですが、
配列、引数等、ポインタ等がなんだかわけがわからなくなってます。
よろしくお願いします。

-------------------------------------------------------
  type
    TClass1 = class
  public
    Fwork: array of integer;
    constructor Create(Work: Integer);
  end;

  constructor TClass1.Create(Work: Integer);
  begin
    SetLength(Fwork, Work);
  end;

--------------------------------------------------
  
  type
    TWork = array of Integer;

  type
    TClass2 = class
  protected
    Field: array of TClass1;
  public
  constructor Create(Max: Integer; WorkSize: Integer);
  function ReadWork(Number: Integer): TWork;
  end;

  constructor TClass2.Create(Max: Integer; WorkSize: Integer);
  var
    I: Integer;
  begin
    SetLength(Field, Max);

    for I := 0 to Max - 1 do
        Field[I] := TClass1.Create(WorkSize);
  end;

  function TClass2.ReadWork(Number: Integer): TWork;
  begin
    Result := @Field[Number].Fwork;
  end;

-------------------------------------------

  procedure TForm1.FormCreate(Sender: TObject);
  begin
    var Work: TWork;
    var Test: TClass2;

    Test := TClass2.Create;
    Work := Test.ReadWork(1); 
  end;

----------------------------------------------------------


にしの  2004-01-13 06:40:27  No: 6672

C言語ではどのように書きますか?
ほぼ同じように書けます。
C言語の場合、int*を戻り値にすると思いますが、同じようにする場合、array of integerではなく、PIntegerにします。
使いにくい場合は、やはりC言語と同じように引数から取得します。
まずは、C言語でどのように書くか考えてみてください。


jok  2004-01-13 06:51:23  No: 6673

type
    TWork = array of Integer; // これを最初に宣言しておく

  type
    TClass1 = class
  public
    Fwork:TWork;
    constructor Create(Work: Integer);
  end;

  type
    TClass2 = class
  protected
    Field: array of TClass1;
  public
  constructor Create(Max: Integer; WorkSize: Integer);
  destructor Destroy;override; // 忘れないこと!!
  function ReadWork(Number: Integer): TWork;
  end;

var
  Form1: TForm1;

implementation

{$R *.DFM}

  constructor TClass1.Create(Work: Integer);
  begin
    SetLength(Fwork, Work);
  end;

  constructor TClass2.Create(Max: Integer; WorkSize: Integer);
  var
    I: Integer;
  begin
    SetLength(Field, Max);

    for I := 0 to Max - 1 do
        Field[I] := TClass1.Create(WorkSize);
  end;

  destructor TClass2.Destroy;
  var
    I: Integer;
  begin
    for I := 0 to High(Field) do
        Field[I].Free;
  end;

  function TClass2.ReadWork(Number: Integer): TWork;
  begin
    Result := Field[Number].FWork;
  end;

var
  Work: TWork;
  Test: TClass2;

procedure TForm1.FormCreate(Sender: TObject);
begin
  Test := TClass2.Create(2,3);
  Work := Test.ReadWork(1);
  Work[0] := 1234;
  Work[1] := 9876;
end;

procedure TForm1.Button1Click(Sender: TObject);
begin
  Label1.Caption := IntToStr(Test.ReadWork(1)[1]);
end;

procedure TForm1.FormDestroy(Sender: TObject);
begin
  Test.Free;
end;


ふみと  2004-01-13 07:41:50  No: 6674

レスありがとうございます。

PIntegerですでに試したのですが、うまくいきません。

-------------------------------------------

function TTask.test(N: Integer): PInteger;
begin
  Result := @FTCB[N].Fwork;
end;

procedure TForm1.FormCreate(Sender: TObject);
var
  Work: PInteger;
  Test: TClass2;
begin
  Test := TClass2.Create(2,3);
  Work := Test.ReadWork(1);
end;

----------------------------------------------

ReadWork(1)でField[Number].FWorkのアドレスをWorkに代入、
のところまではうまくいきますが、
Workから配列Fworkの要素を参照する方法がわかりません。
Work[0]、ではエラーがでて参照できません。
ヘルプをひくと、動的配列は逆参照ができない、というのが出てきましたが、
関係あるのでしょうか?

ちなみに、jokさんのコードでも、

>  function TClass2.ReadWork(Number: Integer): TWork;
>  begin
>    Result := Field[Number].FWork;  ←ここ
>  end;

の部分で「互換性のない型です」とエラーが出て、
コンパイルできないのですが…。


jok  2004-01-13 07:43:47  No: 6675

> の部分で「互換性のない型です」とエラーが出て、
> コンパイルできないのですが…。

  type
    TClass1 = class
  public
    Fwork:TWork;                     <--- 注目!
    constructor Create(Work: Integer);
  end;


ふみと  2004-01-13 07:45:29  No: 6676

すみません、さっきのコードは下記の誤りです。
Workから各要素の参照の仕方がわかればなんとかなりそうなのですが…
型キャストとか必要なんでしょうか…

-------------------------------------------

function TClass2.ReadWork(Number: Integer): PInteger;
begin
  Result := @Field[Number].Fwork;
end;

procedure TForm1.FormCreate(Sender: TObject);
var
  Work: PInteger;
  Test: TClass2;
begin
  Test := TClass2.Create(2,3);
  Work := Test.ReadWork(1);
end;

----------------------------------------------


jok  2004-01-13 07:45:39  No: 6677

type
    TWork = array of Integer;

と途中で宣言するとその前の

array of integer

とは「違う型」になるよ


jok  2004-01-13 07:46:52  No: 6678

> 型キャストとか必要なんでしょうか…

必要ない。型を合わせるだけ。


ふみと  2004-01-13 08:02:54  No: 6679

原因がわかりました!!
jokさん、ありがとうございます!
同じ、

type
    TWork = array of Integer;

でも、途中で宣言すると違う型になってしまうんですね…。
ほんとうにありがとうございました!

ところで、そうなるとまた一つ疑問が…。
Class1とClass2は別ユニットに分けていて、
新しいユニットからClass2のユニットのみusesしていたのですが、
これを、TWorkの宣言のために、

---------------------------

type
  TWork = array of Integer;

type
    TClass1 = class
  protected
    Fwork: TWork;
end;

type
    TClass2 = class
  protected
    Field: array of TClass1;
end;

---------------------------

と一つのユニットにまとめた場合、
ほかのユニットからusesしたときに、
そのユニットからもTClass1はクラス型として宣言できてしまいますよね。
これは仕方ないのでしょうか?
TClass1はTClass2のコンポジションにしたいだけなので、
ほかのユニットからは使われたくないのですが…


jok  2004-01-13 08:10:00  No: 6680

TWork の宣言だけのユニットをつくれば?


ふみと  2004-01-13 08:20:06  No: 6681

つまり、Class2とClass1をまとめて、
TWorkを宣言しているユニットをusesして、

新しいユニットから使うときは、
Class2とTWorkの宣言のユニットをusesするということでしょうか?

新しいユニットからClass1を使われないためには、
新しいユニットからは2つのユニットをusesするしかないんですよね?


jok  2004-01-13 08:23:27  No: 6682

TWork の宣言だけのユニットをつくれば

MainUnit からも Class1Unit からも Class2Unit からも TWork 型を参照
できるでしょう。MainUnit からは、Class1Unit を uses しなけりゃいい。


ふみと  2004-01-13 08:31:52  No: 6683

ユニットにまたがって使う型があるときは、
型だけをまとめたユニットを別に作ったほうがいいんですね。
ありがとうございます!

このやりかたなら、

Test.ReadWork(0)[0] := 12;

などの使いかたもできますし、
変数参照(?)で引数として配列を渡すより、便利ですね。

しかしdelphiは型や配列とかポインタがなかなかよくわからないです。
基本の参考書を持ってないもんで…。
クラスについてはここ数週間ではじめて使ったので、
余計、混乱してしまいました。

jokさん、ほんとうにどうもありがとうございました!!


jok  2004-01-13 08:36:13  No: 6684

destructor TClass2.Destroy;

も忘れないように。Create と同じ数だけ Free することは重要。


ふみと  2004-01-13 08:41:34  No: 6685

了解です!
しっかりやっております。

また疑問がでてきたので、
それもこれからやってみたいと思います。
もしわからなかったときは、また質問させてもらうかもしれませんが、
見かけたらよろしくお願いします。


※返信する前に利用規約をご確認ください。

※Google reCAPTCHA認証からCloudflare Turnstile認証へ変更しました。






  このエントリーをはてなブックマークに追加