SHOEISHA iD

※旧SEメンバーシップ会員の方は、同じ登録情報(メールアドレス&パスワード)でログインいただけます

CodeZine編集部では、現場で活躍するデベロッパーをスターにするためのカンファレンス「Developers Summit」や、エンジニアの生きざまをブーストするためのイベント「Developers Boost」など、さまざまなカンファレンスを企画・運営しています。

突然ですがクイズです!(AD)

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

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

  • X ポスト
  • このエントリーをはてなブックマークに追加

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

問題

 最後はちょっと難しくなります。クラス継承時のコンストラクタの連鎖と、メソッドのデフォルト引数について。これも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;
 

この記事は参考になりましたか?

  • X ポスト
  • このエントリーをはてなブックマークに追加
突然ですがクイズです!連載記事一覧
この記事の著者

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

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

※プロフィールは、執筆時点、または直近の記事の寄稿時点での内容です

【AD】本記事の内容は記事掲載開始時点のものです 企画・制作 株式会社翔泳社

この記事は参考になりましたか?

この記事をシェア

  • X ポスト
  • このエントリーをはてなブックマークに追加
CodeZine(コードジン)
https://codezine.jp/article/detail/2297 2008/08/20 13:35

おすすめ

アクセスランキング

アクセスランキング

イベント

CodeZine編集部では、現場で活躍するデベロッパーをスターにするためのカンファレンス「Developers Summit」や、エンジニアの生きざまをブーストするためのイベント「Developers Boost」など、さまざまなカンファレンスを企画・運営しています。

新規会員登録無料のご案内

  • ・全ての過去記事が閲覧できます
  • ・会員限定メルマガを受信できます

メールバックナンバー

アクセスランキング

アクセスランキング