C++/CLI ラッピング入門4
今回はラップしたアンマネージドクラスの
クラス、構造体などの複合型メンバ変数をマネージ側に公開します。
—————————————————————–
・クラス・構造体型メンバ変数の公開
アンマネージドクラスclassAの、classB型(アンマネージ)のメンバ変数BをC++/CLIでマネージド側に公開する場合
内部では、classAと、そのメンバ変数B(classB)のつながりを保ったまま、
外からは、classAのラッパークラス A_Wrapperが
classBのラッバークラスB_Wrapper型のメンバ変数Bを持っているようにみえるのが望ましいです。
図1 内部ではclassAとclassBはつながっていて、その結合を保ったまま、ラップする
図2 外からは、A_WrapperがB_Wrapperをメンバに持っているように見えるようにする
そこで、B_WrapperにはclassBのポインタを受け取るのコンストラクタを作成し、
A_Wrapperでは、B_Wrapper型のプロパティBを公開し、
その内部では、
classAのメンバ変数B(classB型)を先ほど作成したポインタを受け取るコンストラクタにわたして、B_Wrapperオブジェクトを作成するようにします。
//---------------------
// アンマネージドクラス定義 (C++)
namespace CPP
{
class classB
{
public:
//classBコンストラクタ
classB():i(0){}
//メンバ変数
int i;
};
class classA
{
public:
// コンストラクタ
classA(){}
// メンバ変数B
classB B;
};
}
//---------------------
// マネージドラッパー (C++/CLI)
namespace CLI
{
// classBのラッパー
public ref class B_Wrapper
{
public:
// B_Wrapperを単体で作る時用のコンストラクタ
B_Wrapper(){pB = new CPP::classB();}
~B_Wrapper(){this->!B_Wrapper();} //デストラクタ
!B_Wrapper(){delete pB;} //ファイナライザ
// classBのメンバ変数を公開
property int i
{
int get()
{ return pB->i; }
void set(int value)
{ pB->i = value; }
}
internal:
CPP::classB* pB;
//メンバ変数としての公開用のコンストラクタ
// アセンブリの外からは呼び出さないのでinternal
B_Wrapper(CPP::classB* ptr)
{
pB = ptr;
}
};
// classAのラッパー
public ref class A_Wrapper
{
public:
A_Wrapper(){pA = new CPP::classA();}
~A_Wrapper(){this->!A_Wrapper();}
!A_Wrapper(){delete pA; }
//classAのメンバ変数bをプロパティでラップして公開
property B_Wrapper^ B
{
//classBをB_Wrapperとして公開
B_Wrapper^ get()
{ return gcnew B_Wrapper(&(pA->B)); }
//B_Wrapper内のclassBオブジェクトをコピー
void set(B_Wrapper^ value )
{ pA->B = *value->pB; }
}
internal:
CPP::classA* pA;
};
}
//----------------------------
しかし、このままでは、newで直接確保したわけではない
B_Wrapperに格納されているclassBへのポインタ(classAオブジェクトのメンバ変数B)に対してもdeleteが実行されてしまいます。
コレを防ぐために
ポインタを受け取るコンストラクタでフラグを建てて、
このフラグが立っている場合はdeleteされないようにします。
//---------------------
// B_Wrapper delete防止
public ref class B_Wrapper
{
public:
// B_Wrapperを単体で作る時用のコンストラクタ
B_Wrapper():no_alloc_flag_(false)
{pB = new CPP::classB();}
~B_Wrapper(){this->!B_Wrapper();} //デストラクタ
!B_Wrapper()
{
// ポインタを受け取るコンストラクタで立てられるフラグが立っていれば、
//deleteしない
if(!no_alloc_flag_)
{delete pB;}
} //ファイナライザ
// classBのメンバ変数を公開
property int i
{
int get(){return pB->i;}
void set(int value){pB->i = value;}
}
internal:
CPP::classB* pB;
//delete防止ようフラグ
bool no_alloc_flag_;
//メンバ変数としての公開用のコンストラクタ
// アセンブリの外からは呼び出さないのでinternal
B_Wrapper(CPP::classB* ptr):
no_alloc_flag_(true) // deleteしないようにフラグを立てる
{
pB = ptr;
}
};