質問: オブジェクト志向について簡単に教えてください。
回答: オブジェクト指向は色々な面でのメリット・デメリットを持っているので一概には言えませんが、基本的にはデータと関数がセットになっているものと思ってください。 手続き型言語は 「関数にデータを渡して結果のデータを得る」 「関数にデータを渡してデータを書き換える。」 という形が基本ですが、オブジェクト指向は 「データから関数を呼び出して結果のデータを得る」 「データから関数を呼び出して書き換える。」 という形になります。 これによってソースの書き方が異なってきます。 こんな事を考えて見ましょう。 食材A~Eの5つの食材と、フライパンと鍋の2つの調理器具があります。 これを使って ・AとBとCをフライパンに入れていためて料理を作る。 ・DとEを鍋に入れて煮込んで料理を作る。 という事を擬似コードで考えて見ましょう。 手続き型の場合は ------------------ struct 食材{ ___食材のデータ構造 } struct 調理器具{ ___調理器具のデータ構造 } function 料理 炒める(調理器具 _ware,食材[] _foods){ ___炒めるコード ___return 料理; } function 料理 煮込む(調理器具 _ware,食材[] _foods){ ___煮込むコード ___return 料理; } /*ここまで定義*/ /*ここから実装*/ 食材[] forFryPan = {A,B,C}; 食材[] forPot = {E,F}; 調理器具 fryPan = {フライパンのデータ}; 調理器具 pot = {鍋のデータ}; 料理 meal1,meal2; meal1 = 炒める(fryPan , forFryPan); meal2 = 炒める(pot , forPot ); ------------------ となります。 ではこれをオブジェクト指向で書くとどうなるのかというと、こうなります。 (いろんな考え方がありますので、これは一例です) ------------------ class 食材{ ___食材のデータ構造 } class 調理器具{ ___食材[] stock; public: ___void 加える(食材 _food){ ______stock += _food; //stockに_foodを追加 ___} ___virtual 料理 調理(){return 無;} } class フライパン : 調理器具{ public: ___料理 調理(){ ______stock内の食材を炒めるコード ______return 料理; ___} } class 鍋 : 調理器具{ public: ___料理 調理(){ ______stock内の食材を煮込むコード ______return 料理; ___} } /*ここまで定義*/ /*ここから実装*/ フライパン frypan; 鍋 pot; 料理 meal1,meal2; frypan.加える(食材 A); frypan.加える(食材 B); frypan.加える(食材 C); meal1 =frypan.調理(); pot.加える(食材 D); pot.加える(食材 E); meal2 =pot.調理(); ------------------ となります。 実装部分を見てもらえばわかりますが、「食材を加えて調理する」という考えがそのままコードに記述されています。 これがオブジェクト指向の基本です。 オブジェクトというのは物体という意味です。 ただのデータがあたかも物体のように振舞って見えますよね。 これがオブジェクト指向の基本です。 ほかにも二つオブジェクト指向で一般的な考えが入っていて、その一つが継承という考え方です。(名称は言語により異なります) フライパンと鍋は、ともに調理器具というオブジェクトを継承しています。 この調理器具は、調理器具として最低限必要であろう、つまり調理器具であれば「共通して持っている機能」をまとめています。 そしてフライパンと鍋は、この調理器具を継承して(受け継いで)いますので、ともに「食材を加える」という機能を定義していなくても使用できます。 この様に似ている機能であればいちいち記述しなくても継承することで、オブジェクトを再利用できます。 車で考えれば、「走る」「曲がる」「止まる」機能を持つ、タイヤ・変速機・シャーシ・エンジンからできた裸の車の上に外装を乗っけるようなものです。 外装を複数用意して車を継承すれば、外装を作る人は車としての基本機能には目をつぶることができます。 残りは再定義という考え方です。 調理するときはフライパンと鍋とで調理手段が違いますので、継承したオブジェクトの調理という動作を上書きしています。 ほとんど同じ機能を有しているものでも、同じ事をしたら必ず同じ結果が返るとは限りません。 こういうときに、すべてを一度継承してから、違うところだけを上書きする。 これが再定義です。 もしこのコードにフードプロセッサーを追加したいときは class フードプロセッサー : 調理器具{ public: ___料理 調理(){ ______stock内の食材を砕くコード ______return 料理; ___} } とするだけです。 見た目にも頭にもわかりやすいです。 この様に、オブジェクト指向を利用すると、手続き型ではややこしかった事が、比較的簡単に、また人の考え方に近く表現できたりします。 プログラミングというのは、実行時の高速性も大事ですが、 見やすさ、わかりやすさ、無駄のなさ もとても大事です。 同じ事を繰り返さないために継承し、データを物体として考えることで人が理解しやすくする。 上の擬似コードでわかるとおり、もともと短い・簡単なコードをオブジェクト指向にすると逆に長くなったりしますが、これが大規模な・多人数な開発になってくると強力な道具になります。