SHOEISHA iD

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

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

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

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

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

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

メソッドのオーバーライド

問題

 次は、ちょっと難しくなります。6種類の言語を使って「親クラス」と「子クラス」を定義して、メソッドのオーバーライドの処理を書いてみました。同じような動作を期待したのですが、1つだけ出力結果が違うものがありました。それは、どの言語でしょうか?

Delphi
program Project1;
{$APPTYPE CONSOLE}

type
  TParent = class
  public
    constructor Create;
  protected
    procedure foo; virtual;
  end;

  TChild = class(TParent)
  public
    constructor Create;
  protected
    procedure foo; override;
  end;

constructor TParent.Create;
begin
  Self.foo;
end;

procedure TParent.foo;
begin
  Writeln(’TParent#foo’);
end;

constructor TChild.Create;
begin
  inherited;
end;

procedure TChild.foo;
begin
  inherited;
  Writeln(’TChild#foo’);
end;

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

class TParent {
public:
  TParent(){
    this->foo();
  }
protected:
  virtual void foo() {
    cout << "TParent#foo" << endl;
  }
};

class TChild : public TParent {
public:
  TChild() : TParent(){
  }
protected:
  virtual void foo() {
    TParent::foo();
    cout << "TChild#foo" << endl;
  }
};

int main(int argc, char* argv[])
{
  new TChild();
  return 0;
}
Java
package project1;

class TParent {
  public TParent() {
    this.foo();
  }
  protected void foo() {
    System.out.println("TParent#foo");
  }
}

class TChild extends TParent {
  public TChild() {
  }
  protected void foo() {
    super.foo();
    System.out.println("TChild#foo");
  }
}

public class Project1 {
  public static void main(String[] args) {
    new TChild();
  }
}
C#
namespace project1 {
class TParent {
  public TParent() {
    this.foo();
  }
  protected virtual void foo() {
    System.Console.WriteLine("TParent#foo");
  }
}

class TChild : TParent {
  public TChild() : base() {
  }
  protected override void foo() {
    base.foo();
    System.Console.WriteLine("TChild#foo");
  }
}

public class Project1 {
  public static void Main() {
    new TChild();
  }
}
}
PHP5
<?php
class TParent {
  public function __construct() {
    $this->foo();
  }
  protected function foo() {
    echo "TParent#foo\n";
  }
}

class TChild extends TParent {
  public function __construct() {
    parent::__construct();
  }
  protected function foo() {
    parent::foo();
    echo "TChild#foo\n";
  }
}

new TChild();
?>
Ruby
class TParent
  def initialize
    foo
  end

  private
  def foo
    puts "TParent#foo"
  end
end

class TChild < TParent
  def initialize
    super
  end

  private
  def foo
    super
    puts "TChild#foo"
  end
end

TChild.new
解説

 正解は「C++」。

 C++以外の言語では期待した、

TParent#foo
TChild#foo

 という出力が得られますが、C++では単に「TParent#foo」とだけ出力されます。問題のコードはメソッドのオーバーライドの機能を使用して、以下のような順番で処理が進むことを期待しています。

  1. TChildクラスのインスタンスを生成
  2. TChildクラスのコンストラクタが呼び出される
  3. TParentクラスのコンストラクタが呼び出される
  4. TParentクラスのコンストラクタ内でfooメソッドを呼び出す
  5. TChildクラスのfooメソッドが呼び出される
  6. TChildクラスのfooメソッドがTParentクラスのfooメソッドを呼び出す

 もちろん一般的には、コンストラクタの処理中は、派生クラスでオーバーライドされる可能性のあるメソッドを呼び出すべきできはありません。構築途中のインスタンスが外部に漏れる危険性があるからです。Delphi/Java/C#/PHP/Rubyでは、TParentクラスのコンストラクタの処理中にTChildクラスのfooメソッドが呼び出されてしまいます。

 しかしC++では「コンストラクタの中から自身の仮想メソッドを呼び出してたとしても、派生クラスのメソッドではなく、自身のメソッドが呼び出される」という仕様になっています。このため、TChildクラスのfooメソッドは呼び出されることなく「TParent#foo」とだけ出力されたのです。

 なお、Rubyに関しては特徴的な動作があります。問題のコードではTParentクラスのfooメソッドは「private」として修飾され、一見すると派生クラスTChildではオーバーライドされないように思えます。しかし実際にはオーバーライドが行われてしまいます。この点、特に注意が必要でしょう。

次の記事

 

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

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

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

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

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

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

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

この記事をシェア

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

おすすめ

アクセスランキング

アクセスランキング

イベント

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

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

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

メールバックナンバー

アクセスランキング

アクセスランキング