プロパティ


フィールドのようなメンバ関数

振る舞いは通常のメンバ関数であるが、アクセス方法がフィールドのような特殊なメンバが存在します。 これを D 言語ではプロパティと呼びます。 プロパティは、代入演算などの式から直接呼び出すことができるメンバ関数です。

プロパティを使うことによって、従来の言語に多く見られていた Set***() や Get***() または Is***() というような、いわゆるアクセッサメソッドを省略することができます。 クラスのフィールドに外部から直接アクセスされる場合、フィールドの変更と同期しなければならないような処理も外部に委ねなければなりませんでした。 これを解決し、スマートに連帯させる方法がアクセッサメソッドの存在ですが、プロパティはさらにアクセッサメソッドの存在を省略し、外部からは直接フィールドを呼び出しているかのような記述方法でメソッドを呼び出すことができます。

D 言語では、メンバ関数が ( ) 無しで参照された場合は引数の無いメンバ関数であると解釈し、代入演算の代入先にメンバ関数が指定された場合は、引数が 1 つのメンバ関数であると解釈します。 例えば obj . Value = 10 という式で Value という名前のフィールドが存在しない場合、コンパイラは obj . Value (10) と解釈します。 同様に int x = obj . Value という使われ方をした場合、コンパイラは int x = obj . Value() と解釈するのです。

この性質を利用することで SetValue() と GetValue() という形で個別にアクセッサメソッドを宣言しなくても、概念的に Value という名前のプロパティとして統一することができるのです。

import std.stream;

class Point {
	int x , y;

	int X() { 
		stdout.printf("Point . GetX %d\n" , x);
		return x;
	}
	void X(int x) {
		stdout.printf("Point . SetX %d\n", x);
		this.x = x;
	}
	int Y() { 
		stdout.printf("Point . GetY %d\n" , y);
		return y;
	}
	void Y(int y) {
		stdout.printf("Point . SetY %d\n" , y);
		this.y = y;
	}
}

int main() {
	Point pt = new Point();
	
	pt.X = 10;
	pt.Y = 100;
	stdout.printf("X=%d,Y=%d\n" , pt.X , pt.Y);
	return 0;
}

このプログラムは、X プロパティと Y プロパティを提供する Point クラスを宣言しています。 プロパティの実体はメンバ関数なので、プロパティを提供するクラスは従来のアクセッサメソッドのように値を設定するメンバ関数と値を返すメンバ関数をそれぞれ用意します。 一方で、これらのメンバ関数を呼び出す方法はフィールドにアクセスするかのように、メンバ関数の名前だけで呼び出すことができます。 例えば pt.X = 10 は pt.X(10) と同じであると解釈することができるのです。

もし、読み取り専用プロパティを実現したければ、値を設定するメンバ関数は用意せずに、値を返すメンバ関数だけを用意すればよいでしょう。


型と式のプロパティ

D 言語では、デフォルトですべての型と式にプロパティが存在します。 単純型のプロパティでは、その単純型が表すことのできる最大値、最小値、および型が占有するメモリ領域のバイトサイズなどを得ることができます。 C 言語の sizeof() 演算子のような処理を実現するには、sizeof プロパティを使えばよいということになります。

このような型と式のプロパティはオブジェクトのプロパティと異なり実体のメンバ関数が存在するわけではありません。

整数型には、次のようなプロパティが定められています。

プロパティ解説
init初期値 (0)
sizeofbyte単位でのサイズ
sizebyte単位でのサイズ(sizeof と同じ)
alignofアラインメントのサイズ
max最大値
min最小値

これらのプロパティは int . init という形で型に指定することもできれば int 型の式 ( x ) . init という形で指定することも可能です。

import std.stream;

int main() {
	int x = 0;

	stdout.printf("init = %d\n" , x.init);
	stdout.printf("sizeof = %d\n" , x.sizeof);
	stdout.printf("alignof = %d\n" , x.alignof);
	stdout.printf("max = %d\n" , x.max);
	stdout.printf("min = %d\n" , x.min);
	return 0;
}

このプログラムは int 型の変数 x の初期値やバイトサイズなどを表示します。 変数 x に対して .init という形でプロパティを要求していることがわかります。 型と式のプロパティはメンバ関数を呼び出すものではないため、x . init() と記述してもコンパイルエラーとなります。 オブジェクトのプロパティとは異なる性質であることを理解する必要があるでしょう。

同様に、浮動小数点数型のプロパティには次のようなものがあります。

プロパティ解説
init初期値 (NaN)
sizeofbyte単位でのサイズ
sizebyte単位でのサイズ(sizeof と同じ)
alignofアラインメントのサイズ
max∞を除いた最大値
min0を除いた最小値
infinity無限大
nanNaN
sign負なら1, 正なら0
isnanNaNなら1, でなければ0
isinfinite±∞なら1, でなければ0
isnormalNaNか∞なら1, でなければ0
degits精度の10進桁数
epsilon最小の増分値
mantissa仮数部のビット数
maxExp指数の最大値

整数型と同様に型や式からこれらのプロパティを通して値を得ることができます。



前のページへ戻る次のページへ