CodeZine(コードジン)

特集ページ一覧

突然ですがクイズです!-その2

Delphi、C++、Java、C#、PHP、Rubyの6言語の動作の違いをクイズで考察

  • LINEで送る
  • このエントリーをはてなブックマークに追加
2008/03/21 14:00

目次

コンストラクタの連鎖とデフォルト引数

問題

 最後はちょっと難しくなります。クラス継承時のコンストラクタの連鎖と、メソッドのデフォルト引数について。これも6つの言語でテストコードを書いてみました。言語の中には、デフォルト引数の機能を持たないものもありますので、それらもできるだけ似せて書いたつもりです。でも、やはり1つだけ結果の異なるものがありました。それはどの言語でしょうか?

Delphi
program Project1;
{$APPTYPE CONSOLE}
type
  TParent = class
  public
    constructor Create(x: Integer = 1);
  end;

  TChild = class(TParent)
  public
    constructor Create(x: Integer);
  end;

constructor TParent.Create(x: Integer);
begin
  Write(x);
end;

constructor TChild.Create(x: Integer);
begin
  inherited Create;
  Write(x);
end;

begin
  TChild.Create(2);
end.
C++
#include <iostream>
using namespace std;

class TParent {
public:
  TParent(int x = 1) {
    cout << x;
  }
};

class TChild : public TParent {
public:
  TChild(int x) : TParent() {
    cout << x;
  }
};

int main(int argc, char* argv[])
{
  new TChild(2);
  return 0;
}
Java
package project1;
class TParent {
  public TParent() {
    this(1);
  }
  public TParent(int x) {
    System.out.print(x);
  }
}

class TChild extends TParent {
  public TChild(int x) {
    System.out.print(x);
  }
}

public class Project1 {
  public static void main(String[] args) {
    new TChild(2);
  }
}
C#
namespace project1 {
class TParent {
  public TParent() : this(1) {
  }
  public TParent(int x) {
    System.Console.Write(x);
  }
}

class TChild : TParent {
  public TChild(int x) : base() {
    System.Console.Write(x);
  }
}

public class Project1 {
  public static void Main() {
    new TChild(2);
  }
}
}
PHP5
<?php
class TParent {
  public function __construct($x = 1) {
    echo $x;
  }
}

class TChild extends TParent {
  public function __construct($x) {
    parent::__construct();
    echo $x;
  }
}

new TChild(2);
?>
Ruby
class TParent
  def initialize(x = 1)
    print x
  end
end

class TChild < TParent
  def initialize(x)
    super
    print x
  end
end

TChild.new(2)
解説

 正解は「Ruby」。

 Ruby以外の言語では、期待した「12」という出力が得られますが、Rubyでは「22」と出力されます。問題のコードは、「子クラス」のコンストラクタが「直接の親クラス」のコンストラクタを呼び出す処理が、以下のような順番で進むことを期待しています。

  1. TChildクラスのインスタンスを生成
  2. TChildクラスのコンストラクタに「2」が渡される
  3. TChildクラスのコンストラクタがTParentクラスのデフォルトコンストラクタを呼び出す
  4. TParentクラスのデフォルトコンストラクタは「1」を受け取る

 しかし実際には、RubyだけがTParentクラスのデフォルトコンストラクタに「2」を受け取ってしまっています。どこに問題が隠れているのでしょうか? 実はRubyでは、親クラスのメソッド(コンストラクタを含む)を呼び出す際、括弧と引数が省略された「super」と記述すると、子クラス自身が引数として受け取った変数が自動的に親クラスのメソッドに渡されます。つまり、問題のコードは以下のように記述したのと同じになります。

class TChild < TParent
  def initialize(x)
    super(x) # superと同じ
    print x
  end
end

 もちろん、以下のように括弧「()」を明示的に記述することにより、他の言語と同じように動作させることもできます。

class TChild < TParent
  def initialize(x)
    super() # super()はsuper(1)と同じ
    print x
  end
end

 なお、Delphiの「inherited」にはRubyと同じ特徴があります。問題のコードは、実際には以下のコードと同じになります。

constructor TChild.Create(x: Integer);
begin
  inherited Create(1); // inherited Create; と同じ
  Write(x);
end;

 Rubyと同様に「inherited;」とだけ記述すると、子クラス自身が引数として受け取った変数が自動的に親クラスのメソッドに渡されます。

constructor TChild.Create(x: Integer);
begin
  inherited; // inherited Create(x); と同じ
  Write(x);
end;
 


  • LINEで送る
  • このエントリーをはてなブックマークに追加

バックナンバー

連載:突然ですがクイズです!

著者プロフィール

  • EDN編集部(イーディーエヌ編集部)

    エンバカデロ・デベロッパーネットワーク(EDN)は、ソフトウェア開発者とデータベース技術者のための技術情報サイトです。Delphi、C++Builderをはじめとする開発ツールやER/Studioなどのデータベースツールに関連する技術記事、ビデオなどを提供しています。EDN編集部は、EDN記事と連携...

あなたにオススメ

All contents copyright © 2005-2022 Shoeisha Co., Ltd. All rights reserved. ver.1.5