C#:アセった時に読む【基底クラスと派生クラス】

C#

新人研修からずいぶん経ち、仕事にも慣れてきたころ、
基底クラスで継承に関する実装をしている時にふと、
『そういえば、何で基底クラスに派生クラスを代入できるんだっけ?』と疑問に思いました。
研修時代はよく分からなかったところは丸暗記して『そういうものだ』と割り切ってしまっていたので。

という訳で今回は『基底クラスと派生クラス』についてです。
基底クラスはベースクラス、派生クラスはスーパークラスとも呼ばれます。

正解からいうと、

〇 基底クラス = 派生クラス

× 派生クラス = 基底クラス

   
です。ここで、

『基底クラス = 派生クラス』
という関係を思い出せばなんら問題ありません
(これ以外でどんな風に習ったのか覚えていない)。

問題はないのですが、今回テーマにしたいのは
『なぜ、基底クラスに派生クラスを代入するのはOKで、逆の時はダメなのか』という事についてです。

今は、『基底クラス = 派生クラス』の公式は知らないとして、
基底クラスや派生クラスの特徴から、正解を導き出していきたいと思います。

スポンサードサーチ

それぞれの特徴

  • 基底クラス:派生クラスのベースとなるクラス。
  • 派生クラス:基底クラスをもとに継承している。
    基底クラスより機能(プロパティ・メソッド)が多い。

となります。
派生クラスの方が、基底クラスより多くのプロパティや、メソッドを持っているはずです。そのうちの一部が基底クラスのプロパティになっている感じですね。

ここで、
『より多くのプロパティやメソッドを持っている』という事は、
それはつまり、派生クラスはより多くのメモリ空間を持っている事になるはずです。

この辺りをもう少し詳しく説明してみましょう。

—基底クラス—
・クラスY
  < string up >
  < string down >

—派生クラス—
・クラスXY : Y
  < string up >
  < string dowin >

  string right
  string left

分かりやすいようにカッコでくくっていますが、
見てわかる通り、YクラスよりもXYクラスの方が、見れる情報が多いです。

多いということは、その分メモリ空間で多く取って覚えているということになります。

そして、もう一つ大事なことは、
プロパティを通してメモリ空間をのぞけるということです
のぞけるという事はすなわち、『値が取れるという意味と同義』です。

では、先ほどの問題に戻ってみましょう。
基底クラス=派生クラスがOKなのか、
派生クラス=基底クラスがOKなのか、分かってくるはずです。

基底クラス = 派生クラス

左辺の基底クラスを基準に考えてみます。

なぜ、左辺なのでしょうか?
それは、左辺に値が代入されるからです。左辺を主に考えます。

ここでは、先ほど例に出したYクラスをもとに考えてみましょう。
基底クラスYがのぞくことができるのは、もともと持っているupとdownのプロパティのみです。
派生クラスXYに、それらのプロパティは、当然ながらあります。
ということはOKです。

そして基底クラスに、left, rightのプロパティは入りません。そうですよね、なぜなら保持しておくプロパティは持っていませんから。
プロパティを持っていないということは、メモリ空間に存在するプロパティの値をのぞけないということです。

東京ドームは東京にある

メモリ空間でなく、エリアを表す身近な例で考えてみましょう

  • 基底クラスとして東京ドームを考えます。式では、$Y_{東京ドーム}$とします
  • 派生クラスとして東京を考えますとします。式では、$Y_{東京}$とします

当然、東京ドームエリア < 東京エリアです。
ここで、$Y_{東京ドーム} = Y_{東京}$ を考えます。つまり、右辺の東京を、左辺の東京ドームに代入することをします。

このとき、左辺の東京ドームには、右辺の東京から東京ドームだけ抜き出されたものが代入されます。

ここで、基底クラスと派生クラスに戻してみましょう。
$$ Y_{基底クラス} = Y_{派生クラス}$$

  • 東京ドームのエリアが小さい=メモリ空間が小さい→基底クラス
  • 東京は東京ドームを含む=メモリ空間が東京ドームより大きい→派生クラス

ということは、基底クラスYに派生クラスが代入される時、
『左辺の派生クラスにある基底クラス分のメモリ空間』が『右辺の基底クラス』に代入されることになります。
それをメモリの世界に置き換えたら、
そのエリア分(メモリ空間もしくはプロパティ)を取得できる形になる、というだけです。

スポンサードサーチ

東京には東京ドーム+αがある

次に左辺が派生クラスの場合を考えてみましょう。
式で書くと、$$ Y_{派生クラス} = Y_{基底クラス}$$となり、

また東京と東京ドームを例にとると、
$$ Y_{東京} = Y_{東京ドーム}$$
となります。さて、左辺に注目すると、東京ドームの他に+αになっています。なぜなら左辺は東京だから。
東京には東京ドーム以外のエリアがありますよね。東京ドーム以外のエリアを+αとして、さて、これらの値はいったいどこを見ているのでしょうか?
これがいわゆる、整地していないメモリ空間を覗ける状態になっているという事です
怖いですね。

これを考えることができれば、派生クラス = 基底クラスは危険ということが分かります。

まとめ

基底クラスと派生クラスの特徴から、覗けるメモリ空間の違いによって、どちらへの代入がOKで、どちらへの代入がアウトなのかを説明しました。

結論:のぞけるメモリ空間で考えてみれば、間違えない。

でもまぁ、そもそも初心者向けの基底・派生クラス辺りの説明は分かりにくい気がしますけど。
いずれにせよ、直感的に分かる方が理解が早いと思いますので、今回のような覚え方の方がいいのではないかと思います。

また、派生クラス = 基底クラスは、ダウンキャストでいけるのですが、それでも危ない事には変わりません。気を付けましょう。
(参考文献)
なぜアップキャストは安全で、ダウンキャストは危険なのか