オブジェクト指向 Part2

このエントリーをはてなブックマークに追加
さて、>>611の寒いギャグが一ヶ月放置された訳だが…
さて、>>612が書込まなければ、
その状態が2ヶ月でも3ヶ月でも続いていた訳だが…
>>612 >>613
そんなことより、オブジェクト恥垢とは何かを語りませんか?
615逝って良しの1:02/06/02 11:24
隠蔽された恥垢
616逝って良しの1:02/06/02 11:25
親から子に継承される恥垢
617 :02/06/02 11:25
of Xect si chuo
まだあったのかこのスレ。ウザ。

いまどき「継承」かよ。(プ
VB 使いを小寒しますた
>>618 は、ウォーターフォールな分割詳細化設計で、
 内容の9割9分が重複してるシステム作って、
 「大規模SIは難しい」とか言っているんだろうなぁ
>>616
面白い!(笑

Delphiでオブジェクト恥垢を1から学習しようと思い、基本から作ってみたのですが、
実行後に例外が出ました。
どこがおかしいのでしょうか?

unit frmClass;

interface

uses
 Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
 Dialogs, StdCtrls;

type
 TForm1 = class(TForm)
  Button1: TButton;
  procedure Button1Click(Sender: TObject);
 private
  { Private 宣言 }
 public
  { Public 宣言 }
 end;
 TNum = class
  num1, num2, num3: Integer;
  function numChange(add: Integer): TNum;
 end;

var
 Form1: TForm1;

implementation

{$R *.dfm}

function TNum.numChange(add: Integer): TNum;
var
 n2: TNum;
begin
 n2 := TNum.Create;
 n2.num1 := Self.num1 + add;
 n2.num2 := Self.num2 + add;
 n2.num3 := Self.num3 + add;
 Result := n2;
 n2.Free;
end;
procedure TForm1.Button1Click(Sender: TObject);
var
 n1: TNum;
begin
 n1 := TNum.Create;
 n1.num1 := 1;
 n1.num2 := 2;
 n1.num3 := 3;
 n1 := n1.numChange(3);
 ShowMessage('3足すと、num1=' + IntToStr(n1.num1) + ',num2=' + IntToStr(n1.num2)
          + ',num3=' + IntToStr(n1.num3));
 n1.Free;
end;

end.

//例外メッセージです。
---------------------------
デバッガ例外が発生
---------------------------
プロジェクト GUIClass.exe が EAccessViolation クラスの例外を生成しました。
'モジュール 'GUIClass.exe' のアドレス 004034D0 でアドレス FFFFFFFF に対する読み込み違反がおきました。'
プロセスは停止しています。再開するにはステップ実行または実行を選択してください。
---------------------------
OK ヘルプ(H)
---------------------------
>>620
618 には理解不能とおもわれ
n2.Free; が変。
Resultに代入しても、オブジェクトそのものはひとつなので、
計算結果を捨ててしまっています。
>>624
レスありがとうございます。

n2のフィールドの値をn1のフィールドに代入した後だから、Freeでインスタンスを捨てても良いのでは?
>>621で実行後に例外が出ましたと書きましたが、ShowMessageは正常に実行されて、その後に例外が出るという事です。
それとほぼ同様な感じでnumChangeメソッドの戻り値をIntegerにしてみたら、例外は無く実行されるので、
それ以外の部分に誤りがあると推測していたのですが…。

もう少し詳しく教えて頂けたら幸いです。
クラス型変数の代入はコピーでは無く参照先を変えるだけです。
まず、n1 := n1.numChange(3) で、元々のn1の参照先オブジェクトを見失ってメモリーリーク。
Result := n2 で、Resultとn2が同じオブジェクトを指しているのに、n2.Freeして、
その後同じオブジェクトをn1.Freeしているので2重解放。(恐らくここで例外)

n2.Freeで解放後の領域をアクセスして動いているのは、
直後なので同じメモリーが他の用途に使われておらず、内容が残っているためと思われます。

Delphiは歴史的に値型と参照型が混在していてしかもBoxingもGCも無いので
参照型(クラス、インターフェース)と他の型は区別して扱う必要があります。
>>625 = 俺
>それとほぼ同様な感じでnumChangeメソッドの戻り値をIntegerにしてみたら、例外は無く実行されるので、
>それ以外の部分に誤りがあると推測していたのですが…。
戻り値をIntegerにした時にn2 := TNum.Create; 、n2.Free; を消してるので、この部分はおかしかったです。
何かを勘違いしてました、すみません。

>>626さん
ありがとうございます。

n2にn1が代入されるため、numChangeメソッド内でも n2.Free; = n1.Free; されてしまい、2重開放になるということは理解できました。
そこでもう一つ疑問なのですが、numChangeメソッドの n2 := TNum.Create; の一行を削除したら、再び例外が出ました。
破棄の時と同様に、これもインスタンスを2度生成しているような気がするのですが、こっちは必要の様ですね。
(オブジェクトはひとつなのに、2回生成するのはおかしいような…。)
その一行がどうして必要なのかが理解できないのですが、どうしてなのでしょうか?
こちらも教えて頂けたら嬉しいです。
仮に行列クラスがあったとして

x, y: TMatrix;
...
x := TMatrix.Create( ... );
y := x.Add( ... ); {*}

で、{*}の一行でxの内容が変わったら変でしょう?
使う側は

var
 n1, n2: TNum;
begin
 n1 := TNum.Create;
 n1.num1 := 1;
 n1.num2 := 2;
 n1.num3 := 3;
 n2 := n1.numChange(3);
 ShowMessage(...); {n2を表示}
 n1.Free;
 n2.Free;
end;

で、どうです?
629A:02/06/03 15:03
>>621

なんとなく、普通はこうしそうな気がする

procedure TNum.numChange(add: Integer);
begin
 Self.num1 := Self.num1 + add;
 Self.num2 := Self.num2 + add;
 Self.num3 := Self.num3 + add;
end;

procedure TForm1.Button1Click(Sender: TObject);
var
 n1: TNum;
begin
 n1 := TNum.Create;
 n1.num1 := 1;
 n1.num2 := 2;
 n1.num3 := 3;
 n1.numChange(3);
 ShowMessage('3足すと、num1=' + IntToStr(n1.num1) + ',num2=' + IntToStr(n1.num2)
          + ',num3=' + IntToStr(n1.num3));
 n1.Free;
end;

end.
630デフォルトの名無しさん:02/06/03 15:13
計算結果を別オブジェクトで返すか、自身を書き換えるか…と問題を一般化してみる。

例えば、イテレータを進める時、Ite.Next; とするか、Ite := Ite.Next; とするか…皆さんどちら派?
もしイテレータではなく行列オブジェクトだったら?
631A:02/06/03 15:17
>>627
> そこでもう一つ疑問なのですが、numChangeメソッドの n2 := TNum.Create; の一行を削除したら、再び例外が出ました。

そのままのソースで、単純に、n2 := TNum.Create; を削除したら、
次の行の、

n2.num1 := Self.num1 + add;

で、存在しない(Createされていない)インスタンス n2 にアクセスしようとしているのだから、
例外が出て当然。

n2をどうしても使いたいなら、n2 := TNum.Create; n2.Free; を消して、
n2 := TNum.Create; の代わりに、n2 := Self; って入れるとか(笑
意味はほとんど、>>629 と同じになるけど。
632630:02/06/03 15:23
>>631 割り込みすいません......
633A:02/06/03 16:06
>>630
イテレータは、Ite.Next のほうが、自然な気がする。
というか、Ite := Ite.Next; これだと、結局自分を書き換えてない?

代入させる場合だと、自分以外の変数に入れてやることができるけど
ただの代入だと結局、インスタンスは同じだから、別々に扱いたい場合は
自分の中でインスタンスのコピー作って返してやればいいのか・・・
ただ、それだと、コピーされたインスタンスの破棄には責任もてないし、
上みたいに、自分自身に代入してしまうと、元のインスタンスを見失って
メモリリーク起すから、扱いに気を使いそう・・・。
必要な時以外は、あまり使いたくない気がしてきた(笑

>>632 あ。気にしないでください。間に時間空いてるんで
>>633
interfaceを使えば破棄は自動化できますし。
Delphiに限った話でも無くGCのある言語なら尚更問題は無いし。

Ite := Ite.Next; 方式ですと、同一のイテレータを複数箇所が参照していても
勝手に書き換えられる心配が無いので
C#のstringがimmutableなのと同じ理屈で共有できますね。
みなさんありがとうございます、>>621でございます。
みなさんの書き込み見ると、まだ理解できてなかったっぽい…(汗

>>628さん
使う側の例でn2 := TNum.Create; してないのは、numChangeメソッド内で生成してるからですよね?
それに対して n2.Free; は使う側にありますが、このようなメソッドはpublicで他のユニットで使う時など、
メソッドのコードが見えないので、開放するのを忘れちゃいそうですよね?
これは(;;゜Д゜)マズー

>>629さん
それの方がシンプルだし、自然っぽいですよね。
今は戻り値がクラス型なメソッドの勉強中なので、不自然ですが勘弁してください。

>>631
>n2をどうしても使いたいなら、n2 := TNum.Create; n2.Free; を消して、
>n2 := TNum.Create; の代わりに、n2 := Self; って入れるとか(笑
この方法は結局オブジェクトを二つ作るのではなく、
newChangeメソッド内でn1をあたかもn2の様に扱うということですね。
その方法だと、使う側でFree; しなくて良いので大変助かります。(笑)
636A:02/06/03 21:15
>>635
>>628 のコードで生成と解放を同じ場所に書くようにするとすると、こんな感じかなぁ?
こうなると、n1のメソッドである意味がほとんどないけど(笑

function TNum.numChange(n2: TNum; add: Integer): TNum;
begin
 n2.num1 := Self.num1 + add;
 n2.num2 := Self.num2 + add;
 n2.num3 := Self.num3 + add;
 Result := n2;
end;

procedure TForm1.Button1Click(Sender: TObject);
var
 n1, n2: TNum;
begin
 n1 := TNum.Create;
 n1.num1 := 1;
 n1.num2 := 2;
 n1.num3 := 3;
 n2 := TNnu.Create;
 n2 := n1.numChange(n2,3);
 ShowMessage(...); {n2を表示}
 n1.Free;
 n2.Free;
end;

要は、戻り値でインスタンスを返す以上、そのインスタンスの解放はメソッド抜けるまで
やっちゃダメなので、Freeを置くとしたら、外に置くしかない。
で、CreateとFreeはセットに、ってことで、Createも外置いて、呼ぶときに渡してやる、と。

ちなみに上のコードだと、最後の代入はあってもなくても同じだったり(笑

あとは、考え方を変えると、同じく >>628 のコードで、コードはそのまま

function TNum.numChange(add: Integer): TNum;
          ↓
function TNum.Create_And_numAdd(add: Integer): TNum;

とかね(笑
新しいインスタンス作ってるよ!と判るようにしてやる(笑
>>636
ありがとうございます。

>あとは、考え方を変えると、同じく >>628 のコードで、コードはそのまま

>function TNum.numChange(add: Integer): TNum;
          ↓
>function TNum.Create_And_numAdd(add: Integer): TNum;

>とかね(笑
>新しいインスタンス作ってるよ!と判るようにしてやる(笑
それもいいアイディアですね。
でもよく考えると、VCLのクラスでも、使用する際に生成・破棄しなくてはいけないので、
自作のクラスでもクラスないに生成・破棄コードを書くのは不自然なのかもしれませんね。

JBuilderも無料なのでJavaもやったことがあるのですが、
本を一冊読みましたが、インスタンスを破棄するという内容は出てきませんでした。
Javaではインスタンスの破棄はしなくてもいいんですかね?
>637
> Javaではインスタンスの破棄はしなくてもいいんですかね?
ガーベジコレクションって聞いたことない?
>>638
初耳でした。
本には書いてなかったですね。
JBuilderのヘルプ見たら項目はありましたけど、中身が見れませんでした。(泣)
でも、ガーベジコレクションが本に出てなかったってことは、破棄しなくてもいいのかな?
Google検索してみます!
>>638
なるほど、Java VMが勝手に使用しなくなったメモリ領域を使える様にしてくれるっちゅーことですね。
これは便利だ…。
ありがとうございます!
641デフォルトの名無しさん:02/06/09 05:34
>>621以降、色々とOOについて教えて戴いた者ですが、また知りたいことがあるので質問させてください。
クラスは何のために作るのですか?
作り方はわかってきたのですが、実際に何かソフトを作るケースにおいて、どういう時に作って良いのかわからないのです。
ユニットを作ることにより、プログラムの再利用が容易にできるというのは聞いたことがありますが、
1回しか使わない物をクラス可する利点というのはあるのでしょうか?
>>641
> クラスは何のために作るのですか?
そこにクラスがあるから。

> プログラムの再利用が容易にできるというのは聞いたことがありますが、
まやかしです。

> 1回しか使わない物をクラス可する利点というのはあるのでしょうか?
データ部は野ざらしにするより、アクセス関数とセットで管理した方が安全です。
>>639
ガベコレのってなかったの?
その本捨てちまえ

>>641
> クラスは何のために作るのですか?
オブジェクト指向をやろうとする場合に、一番クラスが利用しやすいから

> プログラムの再利用が容易にできるというのは聞いたことがありますが、
んなこたあない。必ずしもそうはならない。

> 1回しか使わない物をクラス可する利点というのはあるのでしょうか?
642に同意
644デフォルトの名無しさん:02/06/09 19:08
>>642-643
どうもありがとうございます。

>んなこたあない。必ずしもそうはならない。
一度作ったものをusesやimportに加えるだけで再利用できるのに、容易じゃなくなる場合もあるんですか?

>データ部は野ざらしにするより、アクセス関数とセットで管理した方が安全です。
野ざらし=クラスに属さないという事ですよね?
それが理由なら、TForm1にフィールド変数やメソッドを追加すれば良いのでは?と思うのですが。

>ガベコレのってなかったの?
>その本捨てちまえ
ガベコレは載ってなかったけど、他の説明はわかりやすくて、とても良い本だと感じましたが。
ちなみに「Java本格入門(技術評論社)」っていう本です。
645A:02/06/09 19:42
>>644
TForm1自体が、TFormから継承して作られたクラスだが・・・

例え再利用しなくても、プログラムの規模が大きくなってくると、人間の管理能力を
越えるようになってくる。その際にオブジェクト指向的な作り方をしてあると、
比較的管理がしやすくなる。
>>645
よくわかりました。
ありがとうございます。m(_ _)m
647デフォルトの名無しさん:02/06/11 23:04
コンポーネントとクラスって違うのですか?
イメージがわかないです。
648いいけどね:02/06/12 01:12
きっとわかってない
>>647
コンポーネントはクラスに含まれています。
Delphiだったら、クラスの中でTComponentを継承しているクラスをコンポーネントと呼びます。
俺は>>646なんで全然くわしくないけど、これは多分合ってます。(笑)
650デフォルトの名無しさん:02/06/12 21:05
>>649

いや、あってないです。
それは単にDelphiでの話では?
コンポーネントって意味広いような。
652デフォルトの名無しさん:02/06/15 02:08
なんか、難しいっすね。
インポの仲間です。
俺は>>646なんで全然くわしくないけど、これは多分合ってます。(笑)
654デフォルトの名無しさん:02/06/17 00:33
皆さんの知識と技術を、こちらの板でも披露してください
http://pc.2ch.net/test/read.cgi/tech/1023986216/
オーバーロードってのは言うなれば、拡張子を変えるようなもんで、
オーバーライドってのは言うなれば、上書きってことでいいの?
656ゆでたまご:02/06/17 01:16
>>655

オーバーロード:アシュラマン
オーバーライド:モンゴルマン
657デフォルトの名無しさん:02/06/22 09:42
mage
658デフォルトの名無しさん:02/06/22 16:09
オブジェクト指向なんぞ簡単だろ?
言語によって実装が違うから、各言語を行き来してるとストレスがたまる。
そうストレスが溜まる
661デフォルトの名無しさん
ギコやモナー達はオブジェクト指向!
「公式設定」が存在しないので、だいたいの役割から
具体的なキャラクタを作り出している。