[1] コンテキスト参照
クラスメンバは、基本的に、何かのインスタンスに所属します。static属性が付与されていれば、その変数や関数はクラスの全てのインスタンスで共有されます。static属性が付与されているメンバを、静的メンバと言います。staticメンバではない場合、インスタンスによってアクセスしなければならないのですが、メンバ関数の中から、どのインスタンスによってアクセスされているかというのを識別する参照が、コンテクスト参照です。
コンテキスト参照は、thisという予約語によってアクセスできます。静的でないメンバ関数の内部では、あたかもそのクラス型の参照変数のようにアクセスできます。ただし、書き換えることは出来ません。
import std.stdio;
class Sample{
private int value;
public void func(){
writefln("インスタンス %p の変数valueの値は、%d",cast(void*)this,this.value);
}
}
void main(){
Sample sample = new Sample;
writefln("sampleのアドレスは、%p",cast(void*)sample);
sample.func();
}
sampleのアドレスは、B7580E50
インスタンス B7580E50 の変数valueの値は、0
D言語においては、クラス型の参照変数はvoid*にキャストすることができ、その結果はオブジェクトへのアドレスになるわけですので、上のコードを実行すれば、「B7580E50」のところは必ず一致するわけです。
[2] thisに対して属性を付与する
thisの型は、クラス型の参照になりますが、これはミュータブル型なので、上の場合、immutable型のオブジェクトや、const型のオブジェクトによってfunc関数を呼ぶことは出来ません。そこで、メンバ関数に対して、正確に言えば、thisに対して、属性を付与しなければならない場面が出てきます。
メンバ関数に属性を付与する場合、引数リストの後ろに付与する属性を記述することが出来ます。ちょうどこんな感じです。この場合、属性の違いによって、オーバーロードすることが出来ます。メンバ関数に付与できる属性は、通常の関数に付与できるそれに加えて、「const,immutable,shared,inout」の4つです。
import std.stdio;
class Sample{
private int value;
public this(int value){
this.value = value;
}
public void func(){
writeln("通常バージョン");
writefln("value = %d",value);
}
public void func() immutable {
writeln("immutableバージョン");
writefln("value = %d",value);
}
}
void main(){
Sample obj1 = new Sample(100);
immutable Sample obj2 = new immutable(Sample)(200);
obj1.func();
obj2.func();
}
通常バージョン
value = 100
immutableバージョン
value = 200
実験してみると分かりますが、2つ目のfuncメンバ関数の内部で、メンバ変数valueを書き換えようとすると、コンパイルエラーになります。メンバ変数を書き換えない関数は、全てconstに指定しておけば、mutable及びimmutableな参照は、常にconst参照に暗黙に変換することが出来ますから、大抵の呼び出しには対応することが出来ます。
前の記事「クラス(3)」 ←→ 次の記事「………To Be Determined.(未定)」