第10章 継承とオーバーライド

10.3 オーバーライドについて

 これまでの学習では派生クラスを作成する際に、新規機能(メソッド)を追加するように拡張してきました。そこで派生クラスに新しくメソッドを追加する時には、基本クラスと全く同じ定義(メソッド名、引数の数、型、並び)のメソッドを追加することができます。その機能をオーバーライド(override)と言います。

オーバーライドとは
 基本クラス(親クラス)で定義されたインスタンスメソッドを、そのクラスを継承した派生クラス(子クラス)で独自に定義し直して上書きすることをいいます。派生クラスで機能を追加する必要がある場合などにオーバーライドを利用します。なお、オーバーライドを利用するには、メソッド名、戻り値の型、引数の型と数及び並びが完全に同じでなければなりません。

オーバーライドのメリット
 ・基本クラスから継承したメソッドの代わりに、派生クラスのメソッドを動作させることができる。
 ・1つのメソッド名でそのオブジェクトのクラスに応じて、適切な処理(メソッド)を行わせることができる。
 ・複数のメソッド名を定義したり覚えたりする必要がなくなる。

 上記で示したメリットではあまり便利な機能に感じないかもしれませんが、オーバーライドを行うのは「継承したスーパークラスのメソッドでは実現したい機能が満たせない、でも利用するメソッド名を変更することができない」といった場合になります。別の名前でメソッドを作成すればいいではないかと思うかもしれませんが、別の名前で似たような処理のメソッドを乱立させると管理が大変になる理由があり、このオーバーライド機能が提供されている理由にもなっています。

よく似た名前の別機能
・オーバーロード(Overload)
 同じクラス内で、メソッド名が同じで引数の形式が異なるメソッドを定義すること。
・オーバーライド(Override)
 基本クラスのメソッドとメソッド名・戻り値の型・引数の形式が完全に同じであるメソッドを派生クラス内で再定義すること。

 この機能の呼び名が似ていて、非常に間違え易いので気をつけて下さい。

 では基本クラスと派生クラスに同じ定義のメソッドがある場合、どちらのメソッドが呼び出されるのかをソースコードから確認していきます。

10.3.1 基本クラスと同じ定義のメソッドを派生クラスに用意するプログラム

 基本クラスと同じ定義のメソッドを派生クラスに用意することで、どちらのメソッドが動作するのか確認します。メソッドのオーバーライドについて学習しましょう。

ソースコード

ソース・フォルダー  :myproj_framework_basic/ch10
ファイル名      :computer2.php
アクセスURL    :このファイルは直接実行しない

➢ computer2.php ※基本クラス

    <?php
    // 基本クラスの定義作成
    class Computer2{
        protected $os;
        protected $memory;
    
        // コンストラクタ
        public function __construct($os, $memory){
            $this->os = $os;
            $this->memory = $memory;
            echo "OS「" . $os . "」、メモリサイズ「" . $memory . "MByte」のパソコンを作成しました。<br>";
        }
        public function show(){
            echo "パソコンのOSは「" . $this->os . "」です。<br>";
            echo "メモリサイズは「" . $this->memory . "MByte」です。<br>";
        }
    }
    ?>
	

解説
 Computer1クラスの内容からフィールド変数のアクセス修飾子を、privateからprotectedに変更しています。アクセス修飾子がprivateの場合は継承した派生クラスだとしてもクラスの外部ということになるので直接アクセスすることはできませんが、protectedで定義した場合は派生クラスから直接アクセスするできます。

 また、コンストラクタを引数ありに変更し、受け取った引数でフィールド変数を初期化しています。

ソースコード

ソース・フォルダー  :myproj_framework_basic/ch10
ファイル名      :notePc3.php
アクセスURL    :このファイルは直接実行しない

➢ notePc3.php ※派生クラス

    <?php
    // 派生クラスの定義作成
    class NotePc3 extends Computer2{
        private $useType; //用途タイプ
    
        // コンストラクタ
        public function __construct($os, $memory, $useType){
            parent::__construct($os, $memory);
            $this->useType = $useType;
            echo "タイプは「" . $useType . "」用のノートパソコンを作成しました。<br>";
        }
        public function show(){
            echo "このノートパソコンのOSは「" . $this->os . "」です。<br>";
            echo "メモリサイズは「" . $this->memory . "MByte」です。<br>";
            echo "タイプは「" . $this->useType . "」用です。<br>";
        }
    }
    ?>
	

解説
Computer2クラスを継承しており、引数ありのコンストラクタでフィールド変数の初期化を行っています。

 また、基本クラスと同じ名前・引数のshow()メソッドを定義することで、オーバーライドしています。

ソースコード

ソース・フォルダー  :myproj_framework_basic/ch10
ファイル名      :overrideMethod.php
アクセスURL    :http://localhost/myproj_framework_basic/ch10/overrideMethod.php

➢ overrideMethod.php ※オブジェクトを生成して実行するファイル

    <?php
        //基本クラスと派生クラスの読み込み
        require_once 'computer2.php';
        require_once 'notePc3.php';
    ?>
    <html>
        <head>
     		<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
     		<title>メソッドのオーバーライド</title>
      	</head>
        <body>
     	    <?php
                // 派生クラスのオブジェクトを生成
                $npc = new NotePc3("Windows7",3072,"ビジネス");
      
                // 派生クラスのオブジェクトからshow()メソッドを呼び出し
                $npc->show();
            ?>
        </body>
    </html>
	

実行結果

解説
 14行目でNotePc3クラスのオブジェクト生成を引数ありのコンストラクタで行っています。引数にはOS名、メモリ数、用途の3つの情報を渡しています。

 17行目でshow()メソッドを呼び出しています。このshow()メソッドは基本クラスにも派生クラスにも定義されているメソッドになっています。

 実行結果を見ると直ぐに分かりますが、派生クラスのshow()メソッド処理内容のメッセージ出力が行われているのが確認できます。

 先程のプログラムの基本クラスと派生クラスのメソッド内容を比較してみましょう。

図 10.3.1: メソッドのオーバーライド

 処理内容を見比べると基本クラスは2行メッセージを出力、派生クラスは3行メッセージを出力するようになっています。実行結果は3行のメッセージが出力されていたので、間違いなく派生クラスのshow()メソッドが呼び出されているのが分かります。

図 10.3.2: メソッドのオーバーライドで呼び出されるメソッドについて

ポイント

・基本クラスと同じ定義のメソッドを持つ派生クラスからそのメソッドを呼び出すと、派生クラスのメソッドが呼び出される。

オーバーライドを防ぐ定義方法
 もし基本クラスで定義したメソッドを派生クラスでオーバーライドされたくない場合は、メソッドの定義部分にfinal修飾子を付けてあげましょう。
 アクセス修飾子 final function メソッド名 ( 引数 ) {}
 と定義すると、そのメソッドを派生クラスでオーバーライドして実行するとエラーが返ってきます。


NEXT>> 10.4 本章のまとめ