オブジェクト指向プログラミング
クラス
クラスの構造を簡単に紹介します。
もし、すでにオブジェクト指向プログラミングを行ってきたのなら、馴染みのある構造でしょう。
package my.pack; /* this will define the class my.pack.MyClass */ class MyClass { // .... }
クラスは、いくつかの変数とメソッドを持つことができます。
package my.pack; class MyClass { var id : Int; static var name : String = "MyString"; function foo() : Void { } static function bar( s : String, v : Bool ) : Void { } }
変数とメソッドは、次のフラグを持つことができます。
- static : フィールドは、このクラスのインスタンスではなく、クラス自体に属しています。つまり、クラス自体内で直接使用することができます。クラスの外では、クラス名(my.pack.MyClass.nameなど)を使用する必要があります。
- dynamic: フィールドは、動的に書き換えることができます。
- override: フィールドには、サブクラスでオーバーライドされています。
- public : フィールドは、クラスの外からアクセスすることができます。
- private : フィールドへのアクセスは、クラス自体もしくは継承したクラスに制限されています。これはクラスの内部状態にアクセスできないことが保証されます。
デフォルトでは、すべてのフィールドはプライベートです。これは、Java、PHPなど他のほとんどの言語の proceted キーワードに対応しています。class Foo { private var a:Int;//aはFooクラス内の"全て"のコードからアクセスできる function b(f:Foo) { trace(f.a); } }
- 共通の親クラスのプライベート変数へアクセスする (haxe 2.10から)
class Foo { private var nr = 0; public function new() { } } class Bar extends Foo { public function new() { super(); } } class Baz extends Foo { public function new() { super(); var bar = new Bar(); bar.nr = 1; //変数はBarだが、BazはFooの子クラスなのでFooのprivate変数であるnrにアクセスできる。 } }
コンストラクタ
クラスは、new と呼ばれる static でないコンストラクタを1つだけ持つことができます。newはキーワードで、コンストラクタの関数名としても使用します。
class Point { public var x : Int; public var y : Int; public function new() { this.x = 0; this.y = 0; } }
コンストラクタのパラメータ化&オーバーロード:
public function new( x : Int, ?y : Int ) { this.x = x; this.y = (y == null) ? 0 : y; // "y" is optional }
クラス継承
クラスを宣言するとき、一つのクラスに対してextends、複数のクラスまたはインターフェースに対してimplementsを指定することができます。
これらの指定は、このクラスがそれぞれの型から継承しているという事を意味します。
class D extends A, implements B, implements C { }
全てのDのインスタンスはD型ですが、A,BまたはC型を要求している場所でも使うことができます。
つまり、A,B,Cとしても扱うことができるということです。
拡張(Extends)
クラスを拡張するとき、そのクラスはpublicまたはprivateな全ての非スタティックフィールドを継承します。スタティックなフィールドは継承しません。
また、親クラスと同じ数と型の引数を持ったメソッドをオーバーライドとして再定義することができます。
メソッドをオーバーライドしたときは、親クラスのメソッドへのアクセスに"super"を使用してください。
class B extends A { override function foo() : Int { return super.foo() + 1; } }
コンストラクタ内で親クラスのコンストラクタを呼び出すのにも"super"を使うことができます。
class B extends A { function new() { super(36,""); } }
実装(Implements)
インターフェースの実装(implements)が行える他に、JavaScript, PHP, Nekoターゲットではクラスを実装することができます。
クラスまたはインターフェースを実装する場合、実装元のクラスまたはインターフェースのフィールドすべてを同じ型と名前で宣言しなければなりません。ただし、フィールドは親クラスで定義されているものを適用することができます。
インターフェイス
インターフェースは抽象型の一つです。interfaceキーワードを使用して宣言します。デフォルトではインターフェースのすべてのフィールドはpublicです。インターフェースはインスタンス化できません。
interface PointProto { var x : Int; var y : Int; function length() : Int; }
インターフェースは1つまたは複数を実装(implement)することができます。
interface PointMore implements PointProto { function distanceTo( p : PointProto ) : Float; }
ヘルパークラス
Haxeでは、一つのファイルに複数のクラスを記述することができます。
// Foo.hxに両方の定義を記述 class Foo { ... } class FooHelper { ... }
Haxeでは、Javaとは異なり、これらのヘルパークラスに対しても他ファイルからのアクセスが可能です。メインのクラスをインポートすることで、メインのクラスとヘルパークラスの両方が利用可能になります。
// Bar.hxに記述 import Foo; class Bar{ var b:FooHelper; }
パッケージを記述することでもヘルパークラスにアクセスすることができます。
// Bar.hxに記述 class Bar{ var b:Foo.FooHelper; }
ヘルパークラスはファイルに名前が表れてこないためクラスを探すのが難しくなるので、publicなヘルパークラスは多くの言語では推奨されていません。
Haxeでは、ヘルパークラスをprivateにすることが可能です。
// Foo.hxに両方を記述 class Foo { ... } private class FooHelper { ... }
privateにより他ファイルからのヘルパークラスへのアクセスが禁止されます。
理由が無い限り、publicなクラスは各hxファイル当たりに1つを置くことが推奨されます。