Rubyにおける継承(Java/C++との比較)

JavaC++において継承というと、仕様(インターフェース)の継承がメインだ。

java

public interface Printable {
  public void print();
}

public class Number implements Printable {
  int number = 100;
  public void print() {
    System.out.println(number);
  }
}

public class Text implements Printable {
  String str = "hello";
  public void print() {
    System.out.println(str);
  }
}

とこんな感じにしておくと、Number,TextどちらもPrintableのインスタンスとして扱える。以下の関数はインスタンスがNumberでも、Textでも受け取る事ができる。

void function(Printable printable)
{
  printable.print();
}

これは何のためにやってるのかというと、ポリモーフィズムの実現のためだ。型を気にすることなくprint();とすればその内容を表示することができる。C++の場合はinterfaceがないので純粋仮想関数しか持たないクラスを作る。

なぜこういうことをするかというと、静的型付けを行う言語だから。例えば上の例でfunctionの引数の型がNumberだとコンパイルエラーになってしまう。

Number num = new Number();
Text text = new Text();

function(number);
function(text);     //コンパイルエラー


これをrubyで無理やりおんなじ様に書こうとすると、

class Number
  @@num = 100;
  def printvalue
    print @@num
  end
end


class Text
  @@str = "hello"
  def printvalue
    print @@str
  end
end


def function(param)
  param.printvalue
end

num = Number.new
text = Text.new

function(num)
function(text)

こんなことになるがこれはナンセンス。rubyの様な動的型付け言語ではもっと簡単に書ける。

num = 100
text = "hello"

def function(param)
  print param
end

function(num)
function(text)

function()にパラメータを渡すときに型チェックをしないので、わざわざ同じinterfaceを継承していなくてもパラメータを渡すことができ、同じ名前のメソッドさえあればポリモーフィズムを実現できる。

よって、rubyの様な動的型付け言語では「継承」とはインターフェースの継承ではなく実装の継承に使われる。