最近學了C++/CLI,也寫了一些小玩意兒體驗了它的強大,昨天開始籌劃將以前的彎管機的類比程式用C++/CLI重寫。
基本思路是將底層3D部分和上層GUI圖形介面部分大體分離。最原始的做法是寫一個C++的類,然後定義一些介面,然後用C++/CLI寫一個
Wrapper,然後用C#進行調用。這種做法其實不是很好,增加了很大的工作量,而且在寫Wrapper的時候難免有很多重複性的賦值代碼。
第二種思路就是直接用C++/CLI開始寫,將Native部分和Managed部分合并在一塊兒寫。當然C++/CLI有一些限制,不能在託管類裡面直
接嵌套非託管類,只能有非託管類的指標等等。這個限制帶來的最大的不好是osg::ref_ptr,也就是OpenSceneGraph裡面的智能指標無
法使用了,因為他是一個類型,不能直接嵌入到託管類裡面,所以類似下面的文法是錯誤的:
ref class ManagedClass
{
osg::ref_ptr<osg::Node> node;
}
當然這樣寫是正確的:
ref class ManagedClass
{
osg::Node* node;
}
但這樣就失去了智能指標的保護,很容易造成記憶體泄露,所以當務之急是需要寫一個智能指標來代替osg::ref_ptr,但基本上要保持功能的不變。
OpenSceneGraph的引用類都是繼承與osg::Object,而osg::Object又是繼承於osg::Reference。所以這些引
用類都有ref()和unref()方法,用於增加和減少ReferenceCount,當ReferenceCount=0時,就自動delete了。
參考osg::ref_ptr並去掉這個類中不常用的部分,寫了一個smart_ptr類,完成了智能指標的任務://! OpenSceneGraph managed smart_ptr.
template<typename T>
public ref class smart_ptr
{
public:
typedef T element_type;
smart_ptr() : _ptr(0) {}
smart_ptr(T* ptr) : _ptr(ptr) { if (_ptr) _ptr->ref(); }
smart_ptr(const smart_ptr% rp) : _ptr(rp._ptr) { if (_ptr) _ptr->ref(); }
~smart_ptr() { if (_ptr) _ptr->unref(); _ptr = 0; }
smart_ptr% operator = (const smart_ptr% rp)
{
if (_ptr==rp._ptr) return *this;
T* tmp_ptr = _ptr;
_ptr = rp._ptr;
if (_ptr) _ptr->ref();
// unref second to prevent any deletion of any object which might
// be referenced by the other object. i.e rp is child of the
// original _ptr.
if (tmp_ptr) tmp_ptr->unref();
return *this;
}
inline smart_ptr% operator = (T* ptr)
{
if (_ptr==ptr) return *this;
T* tmp_ptr = _ptr;
_ptr = ptr;
if (_ptr) _ptr->ref();
// unref second to prevent any deletion of any object which might
// be referenced by the other object. i.e rp is child of the
// original _ptr.
if (tmp_ptr) tmp_ptr->unref();
return *this;
}
//T% operator*() { return *_ptr; }
T* operator->() { return _ptr; }
T* get() { return _ptr; }
bool operator!() { return _ptr==0; } // not required
bool valid() { return _ptr!=0; }
T* release() { T* tmp=_ptr; if (_ptr) _ptr->unref_nodelete(); _ptr=0; return tmp; }
private:
T* _ptr;
};
如此這般折騰以後,終於可以在託管類中間使用智能指標了: public ref class Scene
{
protected:
smart_ptr<osg::GraphicsContext> gc;
smart_ptr<osg::Group> root;
smart_ptr<osgViewer::Viewer> viewer;
smart_ptr<osg::Camera> camera;
.
}
跨越了智能指標的障礙以後,還有很多問題有待於解決。像osg::Vec3這些常用類只能重寫以便於調用。像尋找節點FindNode這種函數: ref class NodeFound
{
public:
String^ name;
smart_ptr<osg::Node> osgNode;
};
NodeFound^ FindNode(String^ name)
{
FindNodeVisitor findNodeVisitor;
findNodeVisitor.name=MarshalString(name);
root->accept(findNodeVisitor);
if(findNodeVisitor.node==NULL) throw gcnew Exceptions::NodeNotFoundExpection();
NodeFound^ nodeFound=gcnew NodeFound();
nodeFound->name=name;
nodeFound->osgNode=findNodeVisitor.node;
return nodeFound;
return nullptr;
}
只能定義一個新的結構作為傳回值,否則C#語言無法使用,因為它不能解析一個智能指標。~~~或許,還有別的方法可以用吧,比如用IntPtr這種,但可能又會脫離了智能指標的保護,變的危險起來。
繼續學習中~