UnityC# クラスの継承・抽象メソッドとオーバライドの使い方

クラスの継承についての画像 Unity C#入門講座
クラス継承することで他のクラスのメンバを共有することができる。


Unityの本格ゲーム制作講座はこちら
【30日間の全額返金保証付き】

今回の記事ではクラスの継承についてみていきます。

Unityではコンポーネント自体がUnityEngine.MoneBehaviourを継承したものなので実は既に使用している機能になります。

さらにUnityEngine.MonoBehaviourUnityEngine.Componentを継承していたりとクラスの継承はスマートなアプリ開発に必要不可欠な機能になります。

前回の記事:

UnityC#のフィールド・プロパティ・アクセス修飾子の使い方 スコープの概念を理解する
今回の記事ではクラスのメンバであるフィールドとプロパティをまず解説し、次にアクセス修飾子とスコープについての理解を深めていきます。 ややこしいところですが、頑張っていきましょう! 前回の記事: クラスにフィールドとプロパティを持た...

【Unity入門の森の最新ゲーム開発講座もお届け】

継承とは

継承とはの画像

継承することで派生クラスは基底クラスのメンバを共有し使用することができるが、基底クラス側で指定したアクセス修飾子によっては使用できないものもある。

継承とはあるクラスのメンバを共有する機能のことになります。

クラスの継承元を基底クラス(Base Class)や親クラスと呼び、継承先を派生クラス(Inherited Class)や子クラスと呼びます。継承関係になるクラスの塊をクラス階層と呼びます。

継承の書き方は次の様になります。

class <クラス名> : <継承するクラス名> { ... }

継承したクラスのメンバは継承先のクラスでも使用できます。が、privateのようなアクセス制限が指定されている場合は継承先でも使用できないので注意してください。

一つのクラスに継承できるクラスは一つだけになります。既に他のクラスを継承しているクラスをさらに継承することも可能です。

また、派生クラスは基底クラスとして型変換することができます。この性質を利用することがオブジェクト指向でプログラミングする上のセオリーとなります。

isキーワードとasキーワード

is,asキーワードについての画像

isキーワードで値が指定した型なのかチェックできる。asキーワードは値を指定した型に変換する。

isキーワードとasキーワードを使用すると値が指定した型なのかどうか判定できたり、型変換することができます。

これらのキーワードを使用することで、クラスの型が指定した基底クラスを継承しているのか確認したり、基底クラスを指定した派生クラスへ変換することができます。

使い方は以下の様になります。

isキーワード:<値> is <型名>。真偽判定を行いbool型を返す。

asキーワード:<値> as <型名>。値を型名の型に変換する。変換できない場合はnullを返す。

null(ヌル)について

nullについての画像

nullは参照値が何もデータを参照していないことを表す値のこと。

nullキーワードについての解説を行います。

null参照値が何も実体データを差していないことを表す値になります。

nullになっている参照値を使用するとSystem.NullReferenceExceptionという例外が発生します。そのためメンバにアクセスすることができません。

nullは参照値が何も参照させないようにする時にも使用できます。その時は単にnullを代入してください。

null条件文演算子について(?演算子と??演算子)

null条件文演算子についての画像

?と??演算子を組み合わせることで参照値を安全に使用することができる。

参照値はnullの場合があるため通常はif文を使っ参照値がnullでないか確認する必要があります。

ですが毎回そのように書くのは大変なので、省略した書き方として?演算子を使用すると、参照値がnullでない時のみメンバにアクセスしてくれます。参照値が文字列型の場合はnullを、値型の場合は0を返します。

また、??演算子をその後に書くと参照値がnullの時でも指定した値を返すことができます。

これらの演算子は配列の要素アクセス([])にも使用することができます。

?演算子の書き方:<参照値> ?. <メンバ名>

??演算子の書き方:<参照値> ?. <メンバ名> ?? <nullの時の値>

一つ注意点として、Unityが用意している参照型には?演算子および??演算子を使用できません。間違って使用した時はコンパイルエラーが発生しますので注意してください。

newキーワードと特殊な変数thisとbaseについて

newキーワードについての画像

メンバ定義の時にnewキーワードをつけると基底クラスと同じ名前のメンバを定義できるが、使用は避けるのがオススメ。

クラス継承した時に派生先のクラスでは基底クラスと同じ名前のメンバは定義できません。

どうしても定義したい場合は回避策としてメンバにnewキーワードを指定するとできます。が、混乱をもたらす原因になりますのでnewキーワードの使用は避けましょう

  • newキーワードの使い方:new <メンバ宣言>
thisとbase変数についての画像

どのクラスのメンバなのか明記したい時はthisとbaseという特殊な変数を使用できる。引数など同じ名前のものがある時に使用できる。

またC#にはthisキーワードとbaseキーワードという特殊な変数が存在します。これらは次の様な意味合いになります。

  • this自分自身のインスタンスを表す特殊な変数。
  • base継承元のクラスのインスタンスを表す特殊な変数。

この二つの変数は引数名とメンバ名が被った時やnewキーワードを使ったことにより同じメンバ名がある時など、どのクラスのメンバなのかわからない場合に所属先を明示したいときに使用できます。

【実践】Unityのクラスに他のクラスのメンバーを継承させてみよう!

それでは実際にクラスの継承を試してみましょう!

次のサンプルコードでは次の二つのコンポーネントを定義しています。

  • BaseComponent:UnityEngine.MonoBehaviourを継承したクラス。GetMove()メソッドを定義している。
  • Sample:BaseComponentを継承したクラス。Inspectorからはこちらをアタッチする。

GameObjectにアタッチできるものはSampleコンポーネントの方なのでそちらを適当なGameObjectにアタッチして再生してください。

再生するとBaseComponentで定義されたGetMove()メソッドによってGameObjectが移動します。

今回のサンプルコードの注目点としてはSampleコンポーネントの中で継承したBaseComponentのメソッドを使用している点になります。

サンプルコードはとても簡単な作りですが、実践的にもクラスの継承はGetMove()メソッドの様に処理の共通化と定義を一つのクラスにまとめる役割で使われることが多いです。

サンプル1の実行例の画像

クラスの継承の一例。SampleクラスではBaseComponentのメソッドを利用してGameObjectを移動させている点に注目。

ちなみに今回のサンプルでは一つのスクリプト内に複数個のコンポーネントを定義していますが、実際にUnityエディターからアタッチできるのはファイル名と一致したコンポーネントになります。

なので、ここではSampleコンポーネントだけをアタッチすることができます。一応、BaseComponentもスクリプト上からGameObjectにアタッチすることができるので豆知識として覚えておくといいでしょう。

仮想メンバとオーバーライドとは

仮想メンバとオーバーライドについての画像

仮想メンバとして定義したメンバは派生クラスでその定義を上書き(オーバーライド)することができる。

仮想メンバとはvirtualキーワードを指定したメンバのことで、派生先のクラスでその定義を上書きすることができるものになります。メンバを上書きすることをオーバーライド(Override)と呼んだりします。

書き方の簡単な例は以下のものになります。

  • 仮想メンバ:virtual <メンバ宣言>
  • オーバーライド:override <メンバ宣言>

オーバーライドすることができるメンバは以下のものになります。

  • メソッド
  • プロパティ:get,setの片方だけ仮想化することができます
  • イベント(※):意味合いは異なりますがプロパティと似たような書き方になります

メンバのオーバーライドを使用することで基底クラスの一部分をカスタマイズすることができます。

メンバのオーバーライドはオブジェクト指向の重要な考え方であるポリモーフィズムを実現する際に必須となるものなので、覚えていてください。

(※イベント(Event)はdelegate型と関係するクラスのメンバになります。詳しくは他の記事で解説します。)

抽象クラスとは

抽象クラスについての画像

抽象クラスは継承されることを前提としたクラスのこと。抽象メンバは派生したクラスの中で上書きする様に指定したメンバのこと。

抽象クラスはabstractキーワードを指定したクラスのことで、そのクラスはインスタンスを作成することができません

そのため抽象クラスは継承することを前提としたクラスになります。

抽象メンバについて

クラスのメンバにもabstractを指定することができます。使い方および指定できるメンバは仮想メンバと同じになります。こちらもオーバーライドすることができます。

仮想メンバとの大きな違いとしては、抽象メンバはその宣言の時に定義が不必要な点になります。

sealedキーワードについて

sealedキーワードについての画像

sealedキーワードを指定するとそれ以上派生できなくなったり、上書きすることができなくなる。

sealedキーワードをクラスに指定するとそのクラスを基底クラスとして使用できなくなります

抽象クラスは継承することを前提としたものでしたが、sealedキーワードをつけたものは反対に警鐘を禁止します。

sealedキーワードは仮想メンバにも指定することができます。こちらも同様で指定した仮想メンバはそれ以降の派生先ではオーバーライドすることができなくなります

【実践】Unityで抽象メソッドとオーバライドを実装する

それでは次は抽象メソッドとオーバーライドを試してみましょう!

次のサンプルコードは先に出てきたサンプルコードを次の様に修正したものになります。

  • BaseComponentを抽象クラスとして定義している
  • BaseComponent.GetMove()メソッドの中でGetMoveImpl()メソッドを呼び出しその中でmoveを設定している。
  • BaseComponent.GetMove()メソッドの最後でmoveにTime.deltaTimeを掛けているこれは継承先のGetMoveImpl()メソッドでの掛け忘れを防ぐためのものである。
  • BaseComponentの中でUpdate()メソッドを定義しているので派生クラス先でUpdate()を毎回定義しなくても良くなっている

抽象クラスを使うことでスクリプトの内容が複雑になった感じですが、派生先のクラス(Sampleコンポーネント)ではGetMoveImpl()メソッドをオーバーライドするだけでGameObjectを好きに移動させることができるようになりました。

BaseComponentの中で派生先で似たような処理を毎回書かなくてもいいように処理の共通化を行ったわけですね。

サンプル2の実行例の画像

抽象クラスを使用した一例。Sampleクラス内ではBaseComponentの抽象メソッドをオーバーライドしただけでGameObjectが移動しているのに注目。

まとめ

今回の記事をまとめますと以下の様になります。

  • クラス定義の際に他のクラスを継承することができる。
  • 継承元を基底クラスや親クラスと呼ぶ。
  • 継承したクラスを派生クラスや子クラスと呼ぶ。
  • クラス継承によって構築された型同士の関係をクラス階層と呼ぶ。
  • あるクラスを継承した時はそのクラスのメンバも使用することができる。
  • 基底クラスに同名メンバがあってもnewキーワードを使用するとメンバ宣言できる。
  • thisキーワードはそのクラスのインスタンス自身を表す特殊な変数。
  • baseキーワードはそのクラスの基底クラスを表す特殊な変数。
  • 仮想メソッドは派生先のクラスでメソッドの定義を上書きできると指定したメソッド。
  • 抽象クラスはインスタンス生成できず、継承することを前提としたクラス。
  • 抽象メソッドは派生先のクラスで定義することを強要するメソッド。
  • 抽象メソッドの定義はいらない。
  • 仮想メソッドおよび抽象メソッドはoverrideキーワードを使用することで上書きできる。

以上になります。それでは次の記事に行ってみましょう!

次回の記事:

UnityC#のインターフェースの使い方・ポリモーフィズムの考え方
今回の記事ではオブジェクト指向の重要な機能であるインターフェースとポリモーフィズムについて解説していきます。 インターフェイスを使いこなせるようになるとプログラム全体の管理がしやすくなります。また、Unityなどフレームワークやライブラリ...

初心者向けUnityC#入門講座に戻る>>


【Unity入門の森の最新ゲーム開発講座もお届け】

コメント

タイトルとURLをコピーしました