[1] コンストラクタ
クラスオブジェクトの変数を、定数ではなくてパラメーターによって初期化したいときは、コンストラクタというメンバ関数を定義します。コンストラクタは、戻り値型なしで、this という名前で関数を定義します。
class Car{
private int fuel = 0; //燃料の量
public this(int fuel){ //これがコンストラクタ
this.fuel = fuel;
}
public void supplyFuel(int amount){
fuel += amount;
}
public void drive(int distance,int speed){
fuel -= distance * speed / 2;
}
public int getFuelAmount(){
return fuel;
}
}
コンストラクタは、必要に応じて別のコンストラクタに処理を委譲することが出来ます。この場合、内部でthisという関数を呼び出すコードを書くことになりますが、複数のコンストラクタが互いに呼び出している場合、コンパイルエラーになります。
class Airplane{
int fuel;
Person[] passengers;
public this(int fuel,Person[] passengers){
this.fuel = fuel;
this.passengers = passengers;
}
public this(int fuel){
this(fuel,null) //処理を、上のコンストラクタに丸投げしている。
}
/*…以下略…*/
}
コンストラクタはオブジェクトの生成時に呼ばれるメンバ関数です。逆に、オブジェクトが破棄されるときに呼ばれる関数が、デストラクタです。デストラクタは、~this という名前の、引数と戻り値が共にない関数です。つまり…
D言語では、基本的にはオブジェクトはGCが必要に応じて破棄します。ですから、デストラクタは、決まったタイミングで呼び出されるという類のものではありません。もし決まったタイミングでデストラクタを呼び出したいということであれば、scope属性を使うことになります。scopeについては別の記事で解説します。
[3] プロパティ
クラスのメンバ変数は、必ずprivateであるべきです。これは、意図しないアクセスによってオブジェクトの整合性が失われることを防止する為ですが、外部からのアクセスを、クラス側でチェックできるならば、正当なアクセスを許可することは、全く問題がないでしょう。そこで、オブジェクト指向プログラミングでは、クラスにアクセッサという関数を用意することがあります。
アクセッサは、大抵は"get~" "set~" といった名前を付けられます。当然、前者が値の読み取り、後者が値の書き込みに対応しているわけです。D言語でも、アクセッサを使う方法は全く間違いではありませんが、このような用途のために用意されている言語機能が、プロパティです。
プロパティとは、あたかもメンバ変数にアクセスするかのようにアクセスできる、メンバ関数のことです。つまり、こういうことが出来るわけです。D言語でプロパティを定義するには、@property属性をつけて、get~に対応するほうは引数なしで、set~に対応するほうは引数一つで関数を定義するだけです。呼び出しは、戦術の通りメンバ変数にアクセスするのと同じやり方でアクセスします。以下サンプル。
import std.stdio;
class Sample{
private int value = 100;
public @property{
int Value(){ //"get~"に相当する
writeln("Called int Value()!!");
return value;
}
int Value(int newValue){ //"set~"に相当する
writeln("Called int Value(int newValue)!!");
return this.value = newValue;
}
}
}
void main(){
Sample sample = new Sample;
writefln("%d",sample.Value); //読み取り
sample.Value = 1000; //書き取り
writefln("%d",sample.Value); //読み取り
}
Called int Value()!!
100
Called int Value(int newValue)!!
Called int Value()!!
1000
前の記事「属性(1)とクラス(2)」 ←→ 次の記事「コンテキスト参照とthis (2)」