はじめまして、最近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;
----------------------------------------------------------
C言語ではどのように書きますか?
ほぼ同じように書けます。
C言語の場合、int*を戻り値にすると思いますが、同じようにする場合、array of integerではなく、PIntegerにします。
使いにくい場合は、やはりC言語と同じように引数から取得します。
まずは、C言語でどのように書くか考えてみてください。
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;
レスありがとうございます。
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;
の部分で「互換性のない型です」とエラーが出て、
コンパイルできないのですが…。
> の部分で「互換性のない型です」とエラーが出て、
> コンパイルできないのですが…。
type
TClass1 = class
public
Fwork:TWork; <--- 注目!
constructor Create(Work: Integer);
end;
すみません、さっきのコードは下記の誤りです。
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;
----------------------------------------------
type
TWork = array of Integer;
と途中で宣言するとその前の
array of integer
とは「違う型」になるよ
> 型キャストとか必要なんでしょうか…
必要ない。型を合わせるだけ。
原因がわかりました!!
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のコンポジションにしたいだけなので、
ほかのユニットからは使われたくないのですが…
TWork の宣言だけのユニットをつくれば?
つまり、Class2とClass1をまとめて、
TWorkを宣言しているユニットをusesして、
新しいユニットから使うときは、
Class2とTWorkの宣言のユニットをusesするということでしょうか?
新しいユニットからClass1を使われないためには、
新しいユニットからは2つのユニットをusesするしかないんですよね?
TWork の宣言だけのユニットをつくれば
MainUnit からも Class1Unit からも Class2Unit からも TWork 型を参照
できるでしょう。MainUnit からは、Class1Unit を uses しなけりゃいい。
ユニットにまたがって使う型があるときは、
型だけをまとめたユニットを別に作ったほうがいいんですね。
ありがとうございます!
このやりかたなら、
Test.ReadWork(0)[0] := 12;
などの使いかたもできますし、
変数参照(?)で引数として配列を渡すより、便利ですね。
しかしdelphiは型や配列とかポインタがなかなかよくわからないです。
基本の参考書を持ってないもんで…。
クラスについてはここ数週間ではじめて使ったので、
余計、混乱してしまいました。
jokさん、ほんとうにどうもありがとうございました!!
destructor TClass2.Destroy;
も忘れないように。Create と同じ数だけ Free することは重要。
了解です!
しっかりやっております。
また疑問がでてきたので、
それもこれからやってみたいと思います。
もしわからなかったときは、また質問させてもらうかもしれませんが、
見かけたらよろしくお願いします。
ツイート | ![]() |