Class ClassName [Inherits BaseClass] [Private] [statement] 'プライベート メンバ ステートメント Public [statement] 'パブリック メンバ ステートメント Protected [statement] 'プロテクティット メンバ ステートメント End Class
Class CTest ... VarName [As VarType] VarName2 [As VarType2] ... End Class
Class CTest ... '通常のメンバ関数の定義 Sub/Function FuncName ([arglist]) [As RetType] [statement] End Sub/Function '仮想関数の定義 Virtual Sub/Function FuncName ([arglist]) [As RetType] ... End Class
コンストラクタ、デストラクタはそれぞれオブジェクトの生成、消滅の際に呼び出される戻り値がない関数(Sub定義)です。関数名は "クラス名" 及び "~クラス名" が利用され、これらの名前を持つ関数は自動的にコンストラクタ、デストラクタと認識されます。
オブジェクトの生成時に呼び出されるコンストラクタではオブジェクトの初期化を行います。コンストラクタについてはパラメータを指定することができます。オブジェクトの消滅時に呼び出されるデストラクタではオブジェクトが利用したデータの破棄処理などを行います。デストラクタについてはパラメータを指定することはできません。
コンストラクタ及びデストラクタはクラス外から呼び出されるケースがほとんどのため、アクセシビリティをパブリックにセットしておく必要があります。
呼び出されるタイミング
コンストラクタ及びデストラクタは下記のように実態オブジェクトの定義を行うと、コンストラクタが自動的に呼び出されます。
Dim obj As CClass(param)
デストラクタは下記のようなオブジェクトが破棄されるタイミングで呼び出されます。
・グローバル領域で定義されたオブジェクトについてはプログラム終了時
・ローカル領域で定義されたオブジェクトについてはプロシージャ抜け出し時
・New演算子で生成されたオブジェクトについては、Delete演算子を使用した時
コンストラクタ、デストラクタの省略
コンストラクタまたはデストラクタの定義を省略すると、下のような引数を持たない空のコンストラクタ、デストラクタが暗黙的に定義されます。
Sub ClassName() '空のコンストラクタ End Sub Sub ~ClassName() '空のデストラクタ End Sub
クラスを継承したときのコンストラクタ、デストラクタの動き
クラスの継承が行ったとき、サブクラスのコンストラクタ、デストラクタ呼び出し時にはスーパークラス(継承元クラス)のコンストラクタの呼び出しを行います。
サブクラスのコンストラクタの定義を省略したとき、またはサブクラスのコンストラクタの先頭部分でスーパークラスのコンストラクタの呼び出しを行わなかったときは、スーパークラスのコンストラクタ呼び出しが引数無しで暗黙的に呼び出されます。呼び出し順序は下のようになります。
サブクラスのデストラクタが呼び出された後に、スーパークラスのデストラクタが暗黙的に呼び出されます。
メンバとして含まれる実体クラスのコンストラクタ、デストラクタの動き(コンポジション)
親クラスに属すメンバとして実体クラス(以後、メンバクラス)が定義されるとき、メンバクラスのコンストラクタ(引数が存在するものを除く)及びデストラクタは下記のような順序で自動的に呼び出されます。メンバクラスのコンストラクタが引数を持つとき、自動呼び出しは行われません。このような場合は任意に呼び出さなければならないので、注意が必要です。
親クラスのデストラクタが呼び出された後に、メンバクラスのデストラクタが暗黙的に呼び出されます。
仮想関数は主にCOMインターフェイスを定義する際に活用します。具体的には下記のようにメンバ変数の先頭部分に関数ポインタの配列を示すポインタを保持します。
VTblPtr->Table[0]->Proc0 Table[1]->Proc1 Table[2]->Proc2 Table[3]->Proc3 Table[4]->Proc4
仮想関数の呼び出しは通常のメンバ関数と同様の手順で行うことができるため、特別が利用がない限りこれらの構造を意識する必要はありません。また、仮想関数を定義しただけでは関数ポインタには何のデータも格納されないため、インターフェイスの取得または任意の関数ポインタを格納する必要があります。
CHumanというクラスをベースに名前と誕生年、年齢を表示するプログラムです。
はじめにClass 〜 End ClassステートメントでCHumanクラスの定義を行います。名前、誕生年のデータはそれぞれpName、BirthYearというメンバ変数に格納することにします。pName、BirthYearの値設定及び参照はクラス内のメンバ関数を通して行うので、外部からアクセス不可能なプライベートで宣言します。続いて、メンバ関数を定義していきます。GetAge関数はBirthYearの値をもとに現在の年齢を計算する関数です。後に定義するメンバ関数ShowHumanDataから呼び出される以外は使われることがないので、プライベートで宣言しています。オブジェクトの生成、消滅時に呼び出されるコンストラクタ(CHuman関数)、デストラクタ(~CHuman関数)は共にパブリックなメンバ関数として定義します。コンストラクタでは初期データ(名前と誕生年)のセットを行います。デストラクタでは名前バッファで確保したメモリの解放を行います。ShowHumanData関数は名前、誕生年、年齢をメッセージボックスで表示する関数です。
クラスの定義が完了すれば、Dimステートメントを利用して実際にオブジェクトを生成できるようになります。ここではobj_dai、obj_yasuという2つのオブジェクトを生成しています。コンストラクタ、デストラクタがオブジェクトの生成時、関数抜け出し時に呼び出されるところに注目しておきましょう。オブジェクトが生成できたらそれぞれShowHumanData関数を呼び出してデータを表示して一連の流れは終了します。
Class CHuman pName As BytePtr '名前バッファへのポインタ BirthYear As Long '誕生年 '年齢を取得するための関数 Function GetAge() As Long Dim st As SYSTEMTIME GetLocalTime(st) GetAge=st.wYear-BirthYear End Function Public 'コンストラクタ Sub CHuman(buf As BytePtr, n As Long) 'メモリを確保し、名前をセット pName=malloc(lstrlen(buf)+1) lstrcpy(pName,buf) '誕生歳をセット BirthYear=n End Sub 'デストラクタ Sub ~CHuman() '名前で使用したメモリを解放 free(pName) End Sub 'データを表示するための関数 Sub ShowHumanData(hWnd As DWord) Dim buf[255] As Byte wsprintf(buf,Ex"名前:%s\r\n%d年生まれ\r\n今年で%d歳",pName,BirthYear,GetAge()) MessageBox(hWnd,buf,"Class Test",MB_OK) End Sub End Class Sub Main() 'オブジェクトを生成 Dim obj_dai As CHuman("Daisuke",1983) Dim obj_yasu As CHuman("Yasuharu",1984) Dim hDeskWnd As DWord hDeskWnd=GetDesktopWindow() 'オブジェクトのデータを表示する obj_dai.ShowHumanData(hDeskWnd) obj_yasu.ShowHumanData(hDeskWnd) 'デストラクタは関数終了時に自動的に呼び出される End Sub 'メイン関数の呼び出し Main()