第22回 class – 5 override


前回メンバメソッドを学びました。
今回はclassの継承についてです。

継承?

継承というのは、とあるclassが別のclassの特性(つまりメンバ)を受け継いで、別のクラスを作ることを言います。
継承される元のclassの事を親クラス、もしくはスーパークラス、継承するclassの事を子クラスまたはサブクラスといいます。
継承の話をする時に、よく引き合い出されるのが動物です。

Cat classとDog classを作る場合に、犬と猫が共通して持っている特性を持つAnimal classを先に作ってあげると、Cat classもDog classも定義しなければならないメソッドの数が減ってお得!というような話です。
Processingの場合には、犬とか猫とか言っていても仕方ないので、Circle classとSquare classで考えてみましょう。
円と四角形に必要な共通する特性を書き出して、Shape classを先に定義します。

円と四角形を描くクラスにあると便利なもの

・移動する(上下左右)
・色を指定できる
・場所を指定できる
・大きさを指定できる

とりあえずこの辺でいいでしょうか。
まず親クラスのShapeに、上記の機能のためのメンバ変数とメンバメソッドを定義します。
そして次に、CircleクラスとSquareクラスを作るときに、Shapeクラスを継承します。

継承するためには、 extendsというキーワードを使って、

class Circle extends Shape {
}
という風にします。
つまり、いつも通りクラス名を書いた後に、extendsキーワード、スペースを開けて継承する元の親クラスの名前、という風に記述します。

そして、継承元クラスのコンストラクタをsuper()というメソッドで呼び出すことが出来ます。
もしメンバ変数があるクラスを継承するのであれば、基本的にsuper()メソッドで親クラスのコンストラクタを呼び出してあげる必要があります。
そうしないと、メンバ変数に何も代入されず空のままになってしまいエラーを起こすからです。

こんな感じになります。


Circle circle; //Circle型のcircleとう名前の変数を宣言
Square square; //同じく
void setup(){
  size(800,800);
  circle = new Circle(400,400,50,color(255,0,0)); //インスタンス化
  square = new Square(200,400,50,color(0,255,0)); //インスタンス化
}

void draw(){
background(0);//背景を黒で塗りつぶす

circle.disp();//円を表示させる
square.disp();//四角形を表示させる
circle.moveLeft();//円を左に移動させる
square.moveRight();//四角形を右に移動させる

  
}

//円と四角の親クラス、シェープクラスを定義
class Shape {

  float x, y, size;//メンバ変数たち
  color col;

  Shape(float _x, float _y, float _size, color _col) {//コンストラクタ
    x = _x;
    y = _y;
    size = _size;
    col = _col;
  }

  void moveRight() {//移動させる系のメソッドたち

    x++;
  }

  void moveLeft() {
    x--;
  }

  void moveDown() {

    y++;
  }

  void moveUp() {

    y--;
  }
}

class Circle extends Shape{//円を描くためのクラスを作る。Shapeクラスをextendsキーワードで継承する。
  
  Circle(float _x, float _y, float _size, color _col){//コンストラクタ
   super(_x,_y,_size,_col);// superで親クラスの今スタクラを呼び出している。
    
  }
  
  void disp(){
    
    fill(col);
    ellipse(x,y,size,size);
  }
}

class Square extends Shape{
  
  Square(float _x, float _y, float _size, color _col){
   super(_x,_y,_size,_col); 
  }
  void disp(){
    
    fill(col);
    rect(x,y,size,size);
  }
}

かなり長くなってしまっていますが、この move4種類とメンバ変数を両方のクラスに実装するよりは多分短く書けました。
コピペするのではなく一度自分のprocessingに書き写して、理解を深めてください。
コンストラクタの値を変えたり、Shapeクラスの持っているメソッドを追加してみたり、draw()の中で呼び出すメソッドを変更してみたりしてください。

次回はこの継承を用いた便利なパターンを紹介します。
では。