« Layer クラスの分割 | メイン | 8月バイナリ »

2013年08月01日

吉里吉里Z 開発:: ネイティブでの TJS2 クラスの継承

    

ネイティブで TJS2 クラスの継承可能な処理を入れた。
ただ、C++ では継承関係はないので、実装は面倒な形に。
TJS2 Class 側にスーパークラスのポインタ保持、TJS2 インスタンス側にスーパークラスのインスタンス保持と言う形。
仮想コードで書くのならこんな感じ。
NativeClass.SuperClass = SuperClass::NativeClass;
CustomObject.SuperClass = SuperClass::CustomObject;

iTJSDispatch2 は ClassInstanceInfo の TJS_CII_GET_SUPRECLASS/TJS_CII_SET_SUPRECLASS で設定取得する。
現在のところ多重継承はサポートしていない。
C++的な継承関係はないので、実装は少し面倒。
同一バイナリであれば、TJS2 で親クラスに当たる NativeInstance を包含することで少しは記述が楽だけど、バイナリが異なると FuncCall 経由で呼び出すことになるので面倒。
TJS2 のコンストラクタの呼び出し順は基底クラスが先。
コンストラクタ呼び出し時には、スーパークラスが登録されているので、そこで親の NativeInstance を取得して、保持しておくことが出来る。
NativeClass へのスーパークラス登録は、global から目的のクラスを取得して設定する。

同一バイナリ内に限定するのであれば、C++ で NativeInstance を継承してしまうのが良いように思うが、そのままだと基底クラスと派生クラスが NativeInstance をそれぞれ持ち、基底クラスのメソッドでアクセスした時は、基底クラスの NativeInstance が使われ別々のインスタンスにアクセスすることになって意図しない動作を引き起こす。
派生クラス側の NativeInstance を両方に登録するば、この問題は解決するが、NativeInstance 解放時に二重解放の問題を引き起こす。
NativeInstance はリファレンスカウンタ等で管理されていないので、二重解放の問題を回避するべく NativeInstance にもリファレンスカウンタを導入するとなると、全プラグインに波及する。

CustomObject 側ではスーパークラスを持たず、スーパークラスのメンバを登録した後、派生クラスのメンバを登録して上書きすれば、NativeInstance の二重登録問題は解決する。
NativeInstance 取得時に基底クラスの ID でも取得でき、IsInstanceOf で基底クラスの名前でも true を返せば、オーバーライド時に直接的に基底クラスのメンバへアクセスできないことを除いて、問題は解決する。
直接的にというのは、global 経由であれば、アクセスできるので不可ではない。
問題はバイナリが異なると継承できなくなること。

他にも方法を考えたが、結局一番上に書いた方法で実装した。
実装の面倒臭さはProxyクラスを作って継承するなどすればある程度緩和されるが、Proxyクラスを作るのが面倒なことには変わりない。



投稿者 Takenori : 2013年08月01日 14:49




comments powered by Disqus
Total : Today : Yesterday : なかのひと