第十一回レポート総評




継承の例 (1)~車関係

いくつか例をあげます。 まず車関係のものを集めてみましょう。

・自動車の MT と AT

MT の場合:
データメンバ:「エンジンの状態」「ギアの状態」「現在の速度」「クラッチの状態」
メンバ関数:「エンジンのSTART、STOP」「ギアの切り替え」「速度調節」「クラッチの調節」

AT の場合:
データメンバ:「エンジンの状態」「ギアの状態」「現在の速度」「シフトレバーの状態」
メンバ関数:「エンジンのSTART、STOP」「速度調節」「シフトレバーの切り替え」


上の例は、どちらが基底でどちらが派生かわかりません。
また、どちらを基底にするにしても、「汎化と特化」という考え方から行くと、まだ「汎化」が 不十分であるように思われます。

[車クラス (基底クラス)]
データメンバ:アクセル踏み具合 方向指示器の点灯状況 ハンドルの状態 ブレーキ踏み具合
メンバ関数:アクセル調節 方向指示器のON/OFF ハンドルの調節 ブレーキ調節

[MT車クラス (派生クラス)]
データメンバ:ギアの状況 クラッチの状況
メンバ関数:ギアの調節 クラッチの調節
[AT車クラス (派生クラス)]
データメンバ:ギアの状況
メンバ関数:ギアの調節


上の例ならば問題なさそうです。

基本クラス:自動車
派生クラス:トラック


上の例ですが、自動車はトラックを一般化したものかというと、そうとも言い切れない気がします。 ですから、継承の例として適当かどうかは微妙なところです。
また、データメンバやメンバ関数なども記述し、根拠を示して欲しかったと思います。

[ガソリン式自動車 (基底クラス)]
メンバ:ガソリン式エンジン、外観、タイヤ、内装

[ハイブリッド式自動車 (派生クラス)]
メンバ:電気式エンジン、発電機、エンジンの切り替えシステム(電気orガソリン)


これも、ガソリン式車がハイブリッド車を一般化したものかというと、 微妙なところです。
(車については詳しくないので、自信はありませんが…)

さて、以上に出て来た例を全て取り込み、妥当と思われる派生関係を 図示してみると、以下のようになるでしょうか。(メンバは省いた)






さて、ハイブリッド車はどこに入るか考えてみます。
ハイブリッド車は (多分) 「AT 車 (自家用)」と「電気式四輪車両」の 両方の性質を兼ね備えたものであるので、
「AT 車 (自家用)」クラスと「電気式四輪車両」クラスの両方から派生させたくなります。

C++ はこのように 2 つ以上のクラスから派生させる機能を持っており、 多重継承と呼ばれます。
ただし、多重継承を用いるにはいろいろと注意すべきことが多いので、 多重継承を敬遠する人もいます。
興味のある人は C++ の教本を調べてみると良いでしょう。

ところで、上の図の継承関係は唯一の正解というわけではありません。
どの程度まで継承関係を一般化するかは、プログラマや扱う問題に依存します。
もっとシンプルな図で済む場合も、さらに細かく分けなければならない場合もあるでしょう。

クラスを用いたプログラミングをする際、「何をクラスにすべきか」「継承関係はどのようにすべきか」
などをプログラミングする前に良く考えなければいけません。
これらの工程は「オブジェクト指向分析」、「オブジェクト指向設計」 などと呼ばれます。
この分析と設計が適切に行われないと、再利用性の低いクラスが出来てしまうでしょう。

もちろん、始めから大規模なプログラミングを行うわけではありませんから、
小さなクラスで練習して、徐々に考え方に慣れていけば良いと思います。



継承の例 (2)~オーディオ関係

オーディオ関係も多かったので、いくつか紹介してみます。

[ラジオクラス (基底クラス)]
データメンバ:「電源の状態」「バンド(AM・FM)」「現在のチューニング」「現在音量」「ディスプレー表示」
メンバ関数:「電源入・切」「バンド変更」「チューニング変更」「音量変更」「表示切替」

[CD コンポクラス (派生クラス)]
データメンバ:「CDの再生状態」「CD/ラジオの状態」
メンバ関数:「CDの再生・トラック変更・停止」「CD/ラジオ切り替え」

[MD コンポクラス (派生クラス)]
データメンバ:「MDの録音・再生状態」「MD/ラジオの状態」
メンバ関数:「MDの再生・録音・トラック変更・停止」「MD/ラジオ切り替え」


オーディオコンポというのはいくつかの部品 (CD、MD、ラジオチューナ、等) を組み合わせて作らているので、非常にオブジェクト指向的だと思います。
しかし、コンポの継承関係がどうなっているかを考えてみると、意外と難しそうです。
例えば、上の例のようにラジオからいきなり CD コンポを派生するのはちょっと飛躍があるような気がします。

次の例はどうでしょうか。

[音を鳴らすシステム (基底クラス)]
データメンバ:電源の状態、現在の音量
メンバ関数:電源ON/OFF、音量調整

[CD プレイヤー (派生クラス)]
データメンバ:再生状況
メンバ関数:再生、早送り、巻き戻し、曲の頭だし

[MD プレイヤー (派生クラス)]
データメンバ:再生状況
メンバ関数:再生、早送り、巻き戻し、曲の頭だし


この例では「音を鳴らすシステム」という抽象的な物をまずクラス化し、 それを派生させて CD や MD クラスを実現しています。
これはなかなかうまいやり方だと思います。

このように、「抽象的なもの」をまずクラス化し、それを派生させて「具体的なもの」をあらわすクラスを作ることはしばしばあります。
資料ではそれを「カスタマイズ」という言葉で表現しました。
論理回路シミュレータの例でも、「抽象的な Node クラス」を派生させて、「And クラス」、「Not クラス」などを作っていました。

このアイディアを利用してオーディオコンポをクラス化すると、 例えば下図のようになるでしょうか (メンバは一部省略しています)。







ポイントは「コンポのモジュール」というクラスと「コンポ」 というクラスが抽象的なクラスになっていることです。
それらを派生させて、「ラジオチューナ」や「CD プレイヤー」、 および「CD コンポ」、「MD つき CD コンポ」などを作成しています。


C から入る C++ に戻る