クラスは、そのままでも使えますし、それを元に継承して新しいクラスを作って利用することもできます。が、クラスの中には、「そのままでは使えず、必ず継承してクラスを作って利用しないといけない」というものもあります。それが「
抽象クラス」です。
抽象クラスは、以下のような形でクラスを定義します。
abstract class クラス名 {……}
クラス定義の冒頭に「
abstract」というものをつけると、そのクラスは抽象クラスとなります。抽象クラスにも、インスタンス変数とメソッドを置くことができます。が、メソッドは、具体的な処理({}の部分)は書きません。ただ、メソッドの宣言文だけを用意するのです。
抽象クラスは、インスタンスを作成することのできないクラスです。これを利用するためには、継承するクラスを作成して利用します。継承したクラスでは、抽象クラスに用意されているメソッドをすべて実装しなければいけません。
すべて実装しないといけないわけですから、元の抽象クラスにあるメソッドは、常に実行されないことになります。だから、抽象クラスのメソッドには実装がないのですね。
では、実際の例を下のリスト欄に掲載しておきましょう。ここでは
MyObjを抽象クラスにし、それを継承した
MyDataを利用する処理を用意してあります。両者の使い方をよく見ておきましょう。
■抽象クラスの役割
「必ず継承しないと使えないクラスなんて、何の役に立つんだ?」と思った人。役に立つんです。それは、「作成するいくつかのクラスで、必ず同じメソッドが用意されていることを保証する」という場合です。
例えば、図形を描くプログラムを作成していて、「円」「四角形」「直線」といったクラスを作ったとしましょう。そこには
drawというメソッドがあり、これを呼び出すとそれぞれ異なる図形が描かれる、というものですね。
このとき、円クラス、四角形クラス、直線クラスすべてに必ず
drawメソッドが用意されている、ということをどうやって保証すればいいでしょうか? また、更に「多角形」だの「曲線」だのといった図形のクラスを作って追加するとき、それらに
drawメソッドがある保証は? もしなかったら、プログラムはエラーになって動かなくなってしまいますね。
こういうとき、「図形クラス」といった抽象クラスを作成し、そこに
drawメソッドを用意しておくのです。そして、「すべての図形のためのクラスは、図形クラスを継承して作る」とします。こうすれば、図形クラスを継承したすべてのクラスには、必ず
drawメソッドが用意されます。
void main() {
MyData hanako = new MyData.make('Hanako', 'hanako@flower', 28);
hanako.printData();
}
abstract class MyObj {
String name;
String mail;
num age;
void printData();
}
class MyData extends MyObj {
MyData() : this.make('noname', 'no@mail', 0);
MyData.make(String name, String mail, num age){
this.name = name;
this.mail = mail;
this.age = age;
}
@override
void printData(){
String re = '<MyObj "' + this.name + ' [' + this.mail + '"](' +
this.age.toString() + ')>';
print(re);
}
}