- 締切済み
クラスの利点について
手続き志向プログラミングになれてしまって困っています。クラスは関数、構造体とはどう違うのですか。参考書に載っている<クラスを使った例題>を、<関数&構造体>に置き換えたほうが短くなりますし、見やすく感じてしまいます。クラスの良さというものが分かりません。固くなった私の頭を納得させるような説明やその例題(実用的なもの)をお願いします。
- みんなの回答 (2)
- 専門家の回答
みんなの回答
- sssohei
- ベストアンサー率33% (33/98)
はっきり言って、入門書の例題が悪いだけと言わざるを得ません。 たぶん C -> C++ だと思うので、C++ の STL を一例に挙げてみます。 配列の変わりに vector という(テンプレート)クラスがあります。配列の長さが実行時に動的に変化する場合、従来の関数&構造体では、メモリの管理に手間を取られていました。 しかし、vector クラスを使えば、サイズ変更は resize() の一行ですみ、また、解放も vector クラスが自動的に行ってくれるので、利用者は心配する必要がありません。 この様に、設計者と利用者が違う場合でもスムーズに、手間が少なく利用出来ます。 配列の大きさが欲しくなれば size() で得ることが出来ますし、それようの(何処で書き換えられるか分かったもんじゃない)グローバル変数を用意する必要はなくなります。 ソートしたくなれば、vector を使っていようが、list を使っていようが同じ sort 関数を用いればソートが出来てしまいます。 char* ではいちいち、どのくらい確保したから…というのを気にしてプログラムしなければいけませんが、stringを用いればそのような苦労も減ります。 また、シューティングゲームを作ることを考えます。 敵キャラを管理する必要がありますが、このとき、構造体&関数を使って、敵キャラそれぞれに独自の動きをつけようとすると、なかなかすっきりしたプログラムを作ることは出来ません。 しかし、CEnemyBase という基底クラスから敵キャラのクラスを派生させるような設計にすれば、管理は CEnemyBase のポインタ配列を持てば良いことになり、実装もすっきりしたものになります。 基底クラスにある描画する関数などは、派生クラスで独自のものにオーバーライド出来るので、わかりやすさを保ったまま細かく制御することが出来ます。 また、メンバ変数に直接アクセス出来ないようにするカプセル化も大きく力を発揮します。変数に代入する際、値のチェックなどを「確実に」するようにすると物凄い行数が必要となってしまいます。しかし、メンバ関数を通じてアクセスするようにすれば、安全なアクセスにすることができます。 また、ちょっと変更したいなと言うときのつぎはぎ的な作業もクラス化しておいた方が楽です。 そして、クラス単位に設計を分けることで複数人での分散作業もしやすくなります。 後、例えば、fwrite や fread の様にいちいちサイズを指定する必要がある関数よりも、クラスで型毎に動作が分かれている方が見やすいプログラムになりませんか? そういった、面倒な部分を隠してしまうと言うのがとりあえず、わかりやすいメリットでは無いかと思います。 他にもメリットはたくさんあります。 もちろん、小規模のプログラムでも無理に使う必要はありませんが、大抵うまくクラスを使った方が見やすいです^^;
- KaoruNagisa
- ベストアンサー率100% (1/1)
回答ではありません。 短いプログラムだと一般的には<関数&構造体>がわかりやすいでしょう。 自分はクラスは、以下のようなものだと考えています。 1)継承を除けば、クラスと<関数&構造体>は同じもの。 2)doubleやintなどの型の拡張。 クラスの例 :複素数 オブジェクトの例:3i+1 データ例 :実数部(1)、虚数部(3) 操作の例 :2つの複素数の距離の計算 3)ある抽象化されたモノや型のデータや操作をひとまとめにしたもの。 クラスの例 :人間 オブジェクトの例:花子さん、太郎さん、…。 操作の例 :歩く データ例 :位置座標 クラスの利点をわかりやすく言うと 1)データと操作を一体化させる。 2)操作の名前を統一できる。 言語によって以下のような利点があります。 1)継承ができる。(多重継承などがあるものもある) (差分プログラミング) 2)データの隠蔽ができる。 補足事項 1)言われているほど継承は用いられないことが多い。 2)結局、クラスの操作をコーディングするときに手続き指向を使用する。 問題は構造化プログラミングができるかどうかです。 これを理解しているならば、クラスの利点も見えてきます。 継承機能を除けば、クラスとは手続き指向と互換性があります。 例えば、B構造体にある操作は、A構造体の操作と同じ概念なので 同じ名前にしたいとき、手続き指向で考えるなら、 きっと似た名前にしようとしますね。 typedef struct A{ } A; typedef struct B{ } B; void A_operation(A *, arguments, ...); void B_operation(B *, arguments, ...); void main(){ A *a; B *b; A_operation(A, arguments, ...); B_operation(B, arguments, ...); } クラスで実現するならば、以下のようにしませんか? class A{ public: void operation(arguments, ...); } class B{ public: void operation(arguments, ...); } void main(){ A *a = new A; B *b = new B; a->operation(arguments, ...); b->operation(arguments, ...); delete A; delete B; } もし、継承、インプリメント、多重継承、などが分からない点だったら アドバイスの意味が無かったかもしれないですね。 以上
お礼
2)doubleやintなどの型の拡張。 クラスの例 :複素数 オブジェクトの例:3i+1 データ例 :実数部(1)、虚数部(3) 操作の例 :2つの複素数の距離の計算 3)ある抽象化されたモノや型のデータや操作をひとまとめにしたもの。 クラスの例 :人間 オブジェクトの例:花子さん、太郎さん、…。 操作の例 :歩く データ例 :位置座標 ↑ホント分かりやすいです。今からちょっとクラス設計に挑戦しようと思います。 回答していただきありがとうございました。
お礼
なるほどですね。ちょっと分かったような気がします。またクラス設計に挑戦してみようと思います。ありがとうございました。