継承という機構は、主に既存のコードを再利用するためにあります。
誰かが立派なクラスを作っていれば、それにちょちょいと追加してやればいいんです。
ただ、そんなに立派なものでなければコピペという手もあるわけで。
あんまり使いすぎるのもどうかと思います。
そんなことはおいといて、JScript.NETでは、
ベースとなるクラスを基本クラス、
そこから作られるクラスを派生クラスと呼びます。
ここでは、本クラスとそこから派生するコミッククラスを例に考えましょう。
コミックには背表紙に各出版社独自のコードが書かれています。
このコードをプロパティとして追加し、
ToStringメソッドもこのコードを追加するように書き替えましょう。
comic1.js
-------------------------------------------------------------------
var book1 : CBook = new CBook("離散系の数学");
var comic1 : CComic = new CComic("お月様のことばかり", "KCN862");
print(book1.ToString());
print(comic1.ToString());
class CBook {
var title : String;
function CBook(str : String) {
title = str;
}
function ToString() : String {
return title;
}
}
class CComic extends CBook {
var code : String;
function CComic(str1 : String, str2 : String) {
super(str1);
code = str2;
}
function ToString() : String {
return code + " " + title;
}
}
これを実行すると次のようになります。
>comic1
離散系の数学
KCN862 お月様のことばかり
クラスを継承するには、
次のように
extendsをつけてクラスを定義します。
//基本クラス
class CBook {
...
}
//派生クラス
class CComic extends CBook {
...
}
次のようにクラスを
finalで修飾すると
継承できなくなります。
//継承できないクラス
final class CBook {
...
}
//型 : 'CBook' を拡張できません。
class CComic extends CBook {
...
}
継承で一つうれしいのは、
派生クラスのインスタンスも基本クラスのと一括で扱えることです。
今のクラスを利用して、
comic2.js
-------------------------------------------------------------------
//同じ配列に入れて
var books : CBook[] = new CBook[2];
books[0] = new CBook("離散系の数学");
books[1] = new CComic("お月様のことばかり", "KCN862");
//まとめて処理
for(var i = 0; i < 2; i++)
print(books[i].ToString());
...
とすると上と同じ結果が得られます。
派生クラスの中でコンストラクタは次のようにしています。
class CComic extends CBook {
...
function CComic(str1 : String, str2 : String) {
super(str1);
code = str2;
}
...
}
この
superは
基本クラスのコンストラクタを呼び出しています。
ここでは、
title = str1;
としても同じなのですが、もっと複雑なときは有効になるでしょう。
上の例ではToStringというメソッドが派生クラスでは再定義されていました。
class CBook {
...
function ToString() : String {
return title;
}
}
class CComic extends CBook {
...
function ToString() : String {
return code + " " + title;
}
}
こういうのは再定義ではなくオーバーライドといいます。
これを実行すると、
>comic2
離散系の数学
KCN862 お月様のことばかり
となったので、CBookのToStringのメソッドではなく、
CComicのToStringメソッドを使っています。
すなわち、ToStringメソッドを置き替えていることになります。
オーバーライドを次のように修飾子を用いて明示することもできます。
class CComic extends CBook {
...
override function ToString() : String {
return code + " " + title;
}
}
逆に置き替えないようにするには
hide修飾子を用います。
class CComic extends CBook {
...
hide function ToString() : String {
return code + " " + title;
}
}
こうすると、
離散系の数学
お月様のことばかり
となります。
逆に基本クラスで
final修飾子を指定すると
オーバーライドできなくなります。
class CBook {
...
final function ToString() : String {
return title;
}
}
class CComic extends CBook {
...
function ToString() : String {
return code + " " + title;
}
}
これでも同じことになります。
このとき
overrideを使うとコンパイルエラーになります。
メンバに
protected修飾子をつけると、
継承したクラスからのみアクセスできるようになります。
var d : CDerived = new CDerived();
print(d.method2()); //OK
var b : CBase = new CBase();
print(b.method1()); //エラー
//基本クラス
class CBase {
function CBase() { }
protected function method1() : String {
return "Base";
}
}
//派生クラス
class CDerived {
function CDerived() { }
function method2() : String {
return super.method1(); //superで基本クラスにアクセス
}
}