Haxe入門 / Class Instance
2.3 Class Instance
2.3.1 Class constructor コンストラクタ
クラスのインスタンスは、コンストラクタを呼び出すことで作れる(インスタンス化)。インスタンスのことをオブジェクトと呼ぶこともあるけどHaxeでは、enum instanceとの対応も考えてインスタンスと呼びたいらしい。まあどうでもいい。
実際のインスタンス化の例
var p = new Point(-1, 65);
これはPointクラスのインスタンスを作っている。Pointクラスのコンストラクタは2つの引数(-1と65)をとる。Pointクラスの場合はこれらの変数はそれぞれ、x
とy
というインスタンス変数に割り当てられる。
簡単にまとめると、 newを使えばコンストラクタを呼び出せて、インスタンスが作れる。
newは5.11 newで詳しく説明する。
2.3.2 Inheritance 継承
クラスは他のクラスからextendsキーワードを使って継承できる。
class Point3 extends Point { var z : Int; public function new(x,y,z) { super(x,y); this.z = z; } }
この場合、Point3の親クラスはPoint、言い換えればPointクラスの子クラスはPoint3。
継承とは、親クラスの機能を拡張するための方法である。基本的な機能は親クラスと同じであるため、拡張部分だけを記述する。親となるクラスを指定するためにextendsキーワードを使う。それだけである。上の例で言えば、Point3はx,y,z
の情報を持つクラスである。x,y
の情報を持つクラスはPointがあるので、これにz
を拡張したということ。
さて、上のクラスではコンストラクタを定義している。
public function new(x,y,z) { ... }
これはコンストラクタで呼び出しで実行される。例) var p = new Point3(1,2,3)
コンストラクタ中のsuper(x,y)
は親クラスのコンストラクタを呼び出している。
クラスを継承しているからといって、必ずしも子クラスで新しくコンストラクタを定義する必要はない。ただし定義する場合は必ず親クラスのコンストラクタを呼びださなければならない。呼び出すのはコンストラクタの最初でも途中でも最後でも構わない。
子クラスは親クラスの関数をオーバーライドできる。明示的にoverrideキーワードを使って指定する。
class Child extends Parent { public override function someMethod() { ... } }
オーバーライドすると、親クラスの関数を別の挙動をするように上書きできる。
詳しくは4.3.1 Overriding Methodsで説明する。
2.3.3 Interfaces インターフェイス
インターフェイスの役割はクラスが持つ変数や関数の名前を示すこと。名前を出すのが目的なので実装(implements)は書かない。実装ってのはつまり関数の中身 { ... }
のこと。
interface Printable { public function toString(): String; // 関数の中身は書かない。 }
クラスと似てるけど、以下の点でクラスとは違う。
インターフェイスは構造的部分型と違って、クラス間の静的関係を示す。構造的部分型はまだ読んでないので知らない。ちなみに性的関係ではない。
静的関係(static relation)はOfficialサイトには強調して書いてあるんですが、そんな単語書かれたってわけわからん。これ書いたやつ頭悪いんちゃうか。あなたの書いた静的関係と私の考える性的関係は違うかもしれんのですよ。まあ親切に推測すると、インターフェイスに書かれた名前とクラスに書かれた名前は型とかも含めて見たまんま一致しなければならないっちゅーことですかね?
気を取り直して、インターフェイスの使い方。
class Point implements Printable { }
implements
ってキーワードを使って、PointクラスはPrintableインターフェイスの関数や変数を実装することを示します。継承と似ていて、PointクラスのインスタンスはPrintableインターフェイスのインスタンスにもなります。継承と違うのは、クラスは複数のインターフェイスを親にとれるという点です。
class Point implements Printable implements Serializable { }
implements
キーワードがあると、Haxeコンパイラはインターフェイスに書かれた関数名や変数名が、実際にクラスで実装されているかチェックします。この時チェックするクラスは、その親クラスも含まれます。
つまり、
class Point extends Base implements Printable { }
とした場合は、Point
クラスがPrintable
の関数名を実装していなくともBase
クラスで実装してあればOKです。
上でもちらっと書きましたがインターフェイスで書けるフィールドは関数だけではなく、変数やプロパティも含まれます。
interface Placeable { public var x:Float; public var y:Float; } class Main implements Placeable { public var x:Float; public var y:Float; static public function main() { ... } }
もちろん、インターフェイスで変数名を書いたら実装先のクラスでも同一名の変数を書かなければなりません。 ちなみに、Haxe2までは複数のインターフェイスをimplementsする際、カンマで区切って並べる必要がありましたけど、Haxe3では必要無くなりました。数少ないHaxe2とHaxe3の非互換性だそうです。