アヒルのある日

株式会社AHIRUの社員ブログです。毎週更新!社員が自由に思いついたことを書きます。

クラス継承の基礎

 

こんにちは
みにくい社長です。

オブジェクト指向言語の特徴の1つにクラス継承があります。
C++, C#, Javaで概念は同じですが、多少ルールが異なる部分があり、間違った解釈をしてしまっているケースを目にすることがあるので、解説したいと思います。

クラス継承(extends)は継承関係を指定することで、子クラスが親クラスの機能を引き継ぐことができます。
このクラス継承を利用することで、同じ機能を複数の子クラスに引き継ぎ、実装を集約することができます。
 

f:id:minikui_ahiru:20210907135949p:plain

クラス継承

 

継承関係はis-a関係と解説されているように、Car is a vehicle.という文が成立するかどうかで、正しい継承関係になっているかを確認することができます。

全てが継承関係で説明できれば良いですが、そうでない概念を共有化したい場合に多重継承が必要だと感じるケースがあります。

c++では下図のように複数のクラスを継承する多重継承が許可されています。

f:id:minikui_ahiru:20210907140013p:plain

多重継承

 しかし、多重継承は危険なバグを引き起こす可能性があり、開発者の間では非推奨となりました。主な原因は、親が2つある場合に仮想関数がどちらの親を呼び出すか特定できなかったり、同名の変数が2つ存在してしまうことが起こることにあります。

そして多重継承を避けるために、インターフェースという機能が追加されました。インターフェースは継承と似ていますが、実装(implement)という別の概念として扱われ、複数の実装を追加することができます。インターフェースにはメンバ変数を含めることができない為、変数名の衝突などが起こりません。C#やJavaでは多重継承が禁止されており、is-a関係になければインターフェースを活用することが推奨されています。

f:id:minikui_ahiru:20210907140021p:plain

 
 
また、親クラスがあくまで概念であり実態化したくない、というケースのために抽象クラス(abstruct)にすることで、不要な実体化を防ぐことができます。
ちなみに、
一般のクラス>抽象クラス>インターフェース
という順に制限が多くなります。
抽象クラスは
・実体化できない
インターフェースは抽象クラスの制限に加え、
・メソッドを実装できない(宣言のみ可能)
・メンバ変数を定義できない
となります。
(言語によって多少異なります)
 
プログラミングする際には、カプセル化など、できるだけ制限をかける方が設計意図が明確になります。
しかし、抽象クラスではなくインターフェースに置き換えられるから、という理由でインターフェースにすべきではありません。
あくまで目的に合った方を選択しないと、余計に意図が不明瞭になってしまいます。
例えば、

f:id:minikui_ahiru:20210907140028p:plain

とした場合に、IVechicleを抽象クラスのように利用することはできますが、CarクラスとBicycleクラスの共通処理が増えた場合に、Ivehicleに記載するのが適切かどうかはわかりません。
IVehicleはインターフェースなので、CarやBicycleと継承関係のないクラスにも使われている可能性があります。(インターフェースの目的を考えると、他で使われているべきです)
他で使われていないということを伝える為にも、Ivehicleは抽象クラスにしておくべきです。
インターフェースは多重利用が許可されているだけに、影響範囲も広範囲に渡る可能性があるということですね。
可読性を良くする為にも、クラス名、インターフェース名や用途を明確にすることを心がけましょう。
 
では、またねー