サイトトップ

Director Flash 書籍 業務内容 プロフィール

Macromedia Flash非公式テクニカルノート

4. インスタンスとクラスのメンバ

ID: FN0309006 Product: Flash

Platform: All
Version: Flash MX 2004

4.1 インスタンスとクラスメンバについて
オブジェクト指向プログラミングでは、クラスのメンバ(プロパティまたはメソッド)は「インスタンスメンバ」(instance member)か「クラスメンバ」(class member)かのどちらかになります。インスタンスメンバは、クラスのインスタンスごとに作成されます。インスタンスメンバをコンストラクタ関数の外で宣言すると、そのメンバはクラスの'prototypeに定義されます[*1]。それに対して、クラスメンバは、クラスに対して一度だけ作成されます(クラスメンバは、「静的メンバ」(static member)とも呼ばれます)。

[訳者註*1] 原文は、"Instance members are created for, and copied into, each instance of the class"(日本語版: インスタンスメンバー はクラスの各インスタンス用に作成され、各インスタンスにコピーされます)とされています。この表現は、インスタンスメンバが、クラスのオブジェクトインスタンスごとに個別に設定されるように解釈できます。実際、Javaなどの他言語では値がインスタンスごとに設定されるため、思わぬ誤解を生みやすい点です。

コンストラクタの外で'var'宣言されたプロパティは、クラスの'prototype'に定義されます。その値はいわばデフォルト値として、インスタンスの'__proto__'プロパティを通じて参照されます。インスタンス自身にプロパティを設定するには、コンストラクタ中で処理を行う必要があります(「3.3 プロパティのインライン初期化」[訳者註*1]参照)。以下のサンプルスクリプトで、その動作を確認することができます。

// ActionScript 2.0クラス定義ファイル: Test.as
class Test {
  var protoProp:String = "property defined to prototype";
  var instanceProp:String;
  function Test(myVar:String) {
    // protoProp = myVar;  // コメントを外すとインスタンスに設定される
    instanceProp = myVar;
  }
}

// SWF
// フレームアクション
var obj:Test = new Test("property assigned to an instance");
trace(obj.hasOwnProperty("protoProp"));  // 出力: false
trace(obj.hasOwnProperty("instanceProp"));  // 出力: true

この点をMacromediaに指摘したところ、Web上のヘルプ「Flash MX 2004 LiveDocs」に、本稿と同内容の修正がコメントとして加えられました。

インスタンスメソッドを呼出したり、インスタンスプロパティにアクセスするには、クラスのインスタンスを参照します。たとえば、以下のコードは、MovieClipクラスのclip_mcというインスタンスに対して、showInfo()メソッドを呼出しています。

clip_mc.showInfo();

しかし、クラス('static')メンバはクラス自身に定義され、クラスのインスタンスには設定されません。クラスメソッドを呼出したり、クラスプロパティにアクセスするには、クラス名自身を参照し、クラスの特定のインスタンスは指定しません[*2]。

ClassName.classMember;

[訳者註*2] クラスのインスタンスからクラスメンバにアクセスすると、コンパイルエラーになります。しかし、クラスのインスタンスメソッドからクラスメンバには、ターゲットの参照なしにアクセスすることが可能です(後述「4.3 クラスメンバの使用: シンプルな例」参照)。

たとえば、ActionScriptのMathクラスは、静的なメソッドとプロパティのみから構成されています。Mathクラスのメソッドを実行するには、クラスのインスタンスは作成しません。単に、Mathクラスそれ自身に対してメソッドを呼出します。以下のコードは、Mathクラスの'sqrt()'メソッドを実行します。

var square_root:Number = Math.sqrt(4);

インスタンスメンバは、静的メンバを読取ることができます。しかし、書替えることはできません。インスタンスメンバは、'for'や'for..in'ループで列挙する(enumerable)ことはできません。

4.2 クラスメンバの作成
クラスのプロパティを静的に設定するには、つぎのように'static'修飾子を使います。

static var variableName;

また、クラスのメソッドを'static'宣言することもできます。

static function functionName() {
  // 関数本体
}

クラス(静的)メソッドがアクセスできるのは、クラス(静的)プロパティのみで、インスタンスプロパティは参照できません。たとえば、つぎのコードはコンパイルエラーになります。クラスメソッドgetName()が、インスタンス変数nameを参照しているからです[*3]。

class StaticTest {
  var name = "Ted";

  static function getName() {
  var local_name = name;
  // エラー! インスタンス変数は静的関数からアクセスできません
  }
}

この問題を解決するには、メソッドをインスタンスメソッドにするか、変数をクラス変数にします。

[訳者註*3] クラスメソッド内でthis参照を用いた場合も、コンパイルエラーになります。クラスメソッドはクラスそのものに関連づけられているため、特定のインスタンスを参照するthisをもたないからです。

4.3 クラスメンバの使用: シンプルな例
クラス(静的)メンバの使い方のひとつは、クラスとそのインスタンスの状態に関する情報を管理することです。たとえば、特定のクラスから作成されたインスタンスの数を監視したいとします。簡単な方法は、クラスプロパティを使って、新たなインスタンスを作成するたびに数を加算することです。

以下のサンプルでは、Widgetというクラスを作成します。そして、ひとつの静的なインスタンスカウンタを、widgetCountという名前で定義します。クラスの新たなインスタンスを作成するたびに、widgetCountの値は1加算します。そして、widgetCountの現在値は、[出力]パネルに表示されます。

クラス変数を使ってインスタンスカウンタを作成する
(1) 新規ActionScript(AS)ファイルを作成します。

(2) 以下のコードをファイルに加えます[*4]。

class Widget {
  static var widgetCount:Number = 0; // クラス変数の初期化
  function Widget() {
    trace("Creating widget #"+widgetCount);
    widgetCount++;
  }
}

[訳者註*4] 上記スクリプトでは変数値の加算にポストインクリメントを用いているので、ステートメントを1行で書くことも可能です。

 trace("Creating widget #"+(widgetCount++));

変数widgetCountは、'static'として宣言されています。したがって、値0で1度だけ初期化されます。Widgetクラスのコンストラクタ関数が実行されるたびに、widgetCountは1加算されて、作成されたインスタンスの現在の数が表示されます[*5]。

(3) ファイルをWidget.asとして保存します。

(4) 新規のFlash(FLA)ムービーを作成して、createWidget.flaという名前で、Widget.asと同じディレクトリに保存します。
このファイルの中で、Widgetクラスの新規インスタンスを作成します。

(5) createWidget.flaのタイムラインでレイヤー 1を選択して、[アクション]パネルを開きます([ウィンドウ] > [開発者パネル] > [アクション])。

(6) [アクション]パネルに、以下のコードを加えます。

// クラスのインスタンスを作成する前は
// widgetCountが0
// trace("Widget count at start: "+Widget.widgetCount);
var widget_1 = new Widget();
var widget_2 = new Widget();
var widget_3 = new Widget();

(7) ファイルを保存して、ムービープレビューを実行する([制御] > [ムービープレビュー])
[出力]パネルには、つぎのように表示されます。

Widget count at start: 0
Creating widget #0
Creating widget #1
Creating widget #2

[訳者註*5] Widget.asは、つぎのように定義することも可能です。'static'宣言したメソッドgetCount()が、加わっています。コンストラクタ関数からは、このメソッドをターゲットの参照なしに呼出すことができます。

// ファイル: Widget.as
class Widget {
   static var widgetCount:Number = 0;
   var test:String;
   function Widget() {
     getCount();  // クラスメソッドをターゲット参照なしに呼出し
     ++widgetCount;
   }
   static function getCount() {  // クラスメソッド
     trace("Creating widget #"+(widgetCount));
   }
}

クラス内からは、クラスメソッドをターゲット参照なしに呼出せます。しかし、インスタンスをターゲットとして、クラスメソッドを呼出そうとすると、コンパイルエラーになります。ターゲットには、クラスを直接指定する必要があります。

var widget_1:Widget = new Widget(); // 出力: Creating widget #0
widget_1.getCount(); // コンパイルエラー
Widget.getCount(); // 出力: Creating widget #1

4.4 クラスメンバとサブクラス
クラスメンバは、そのメンバを定義したスーパークラスからサブクラスに継承されます。前のサンプル(「4.3 クラスメンバの使用: シンプルな例」参照)では、クラスプロパティを使って、作成したクラスインスタンスの数を監視しました。Widgetクラスのサブクラスは、つぎのようにして作成することができます。

class SubWidget extends Widget {
  function SubWidget() {
    trace("Creating subwidget #"+Widget.widgetCount);
  }
}

出典
ActionScript Reference Guideより邦訳。

_____

作成者: 野中文雄
更新日: 2005年7月14日 訳者註*3を追加
更新日: 2004年1月24日 Macromediaのドキュメンテーション修正に合わせて該当する本文と訳者註*1を変更 更新日: 2003年11月30日 文章の若干の修正および訳者註の追加
作成日: 2003年9月22日


Copyright © 2001-2003 Fumio Nonaka.  All rights reserved.