1. 問題的由來在使用BlueHoc的過程中,發現它直接修改了ns2的一些核心檔案,那麼是否有一種方式可以不必修改NS2核心檔案而達到同樣的目的呢?2. 思路Ns2使用TCL/CL來將OTCL代碼與C++代碼結合起來,所有的模擬過程都是通過OTCL代碼調用的。那麼是否可以重載OTCL中相同名稱的類,在它們建立時將其指向自己的C++類呢?3. 測試代碼為了測試使用同名的OTCL類是否可以重載的問題,寫了以下的測試代碼:#include <math.h>#include "tclcl.h"extern "C" {#include <otcl.h>} // 定義一個準備讓TCL指令碼調用的類,此類必須從TclObject繼承class CTestObject : public TclObject{private: int m_nCount; public: CTestObject() { m_nCount = 0; // bind之後就可以在TCL指令碼中訪問這個類的成員變數了, // 對於沒有使用bind的變數是無法通過指令碼訪問的。 // 在此只展示一個簡單的整數類型,如果是複雜資料則需要從TracedVar繼承一個子類進行控制 this->bind("Count", &m_nCount); } virtual int init(int argc, const char*const* argv) { // 在指令碼中進行執行個體化時將調用此函數 printf("CTestObject::init called/n"); m_nCount = 100; return (TCL_OK); } virtual int command(int argc, const char*const* argv) { // 當指令碼中進行對象的函數調用時將使用此函數 printf("CTestObject::command called/n"); if(argc >= 2 && strcmp(argv[1], "GetCount") == 0) { char result[20]; sprintf(result, "%d", m_nCount); Tcl::instance().result(result); return TCL_OK; } else return TclObject::command(argc, argv); } }; class CSubTestObject : public CTestObject{private: int m_nSubCount; public: CSubTestObject() { m_nSubCount = 0; this->bind("SubCount", &m_nSubCount); } virtual int init(int argc, const char*const* argv) { // 在指令碼中進行執行個體化時將調用此函數 CTestObject::init(argc, argv); printf("CSubTestObject::init called/n"); m_nSubCount = 200; return (TCL_OK); } virtual int command(int argc, const char*const* argv) { // 當指令碼中進行對象的函數調用時將使用此函數 printf("CSubTestObject::command called/n"); if(argc >= 2 && strcmp(argv[1], "GetSubCount") == 0) { char result[20]; sprintf(result, "%d", m_nSubCount); Tcl::instance().result(result); return TCL_OK; } else return CTestObject::command(argc, argv); }}; // 定義一個TCL指令碼中可以使用的類資訊class CTestClass : public TclClass{public: CTestClass() : TclClass("CTestClass") { } virtual TclObject* create(int argc, const char* const* argv) { // 建立對象時將調用此函數,如果CTestObject的建構函式需要參數也可以從這裡取得 printf("CTestClass::create called/n"); return new CTestObject; }}; // 不可使用這種變數的方式,否則無法重載//static CTestClass _cls; // 定義一個TCL指令碼中可以使用的類資訊class CSubTestClass : public TclClass{public: CSubTestClass() : TclClass("CTestClass") // 使用與CTestClass相同的類名稱,看看發生的結果 { } virtual TclObject* create(int argc, const char* const* argv) { // 建立對象時將調用此函數,如果CTestObject的建構函式需要參數也可以從這裡取得 printf("CSubTestClass::create called/n"); return new CSubTestObject; }}; // 不可使用這種變數的方式,否則無法重載//static CSubTestClass _sub_cls; // 應先初始化Tcl::init之後再註冊類型資訊,否則無法重載void ClassInit(){ new CTestClass; new CSubTestClass;}4. 測試中出現的問題在此測試過程中,剛開始使用的是靜態全域變數進行類的註冊,但是發現此種情況下無法重載。跟蹤代碼時發現,在調用TclClass類建構函式時,如果Tcl::instance()未初始化,則建構函式僅僅是將我們的類放在一個單鏈表中,而不會立即進行OTCL類和C++類的綁定。注意此鏈表中後插入的資料是放在表頭的,而初始化完成後進行C++類和OTCL類綁定的時候則是從表頭向表尾按順序進行的,因此就造成了這個問題。根據分析,解決問題的方式也有兩種。第一種仍然使用靜態全域變數的方式,但是要更改父類和子類初始化的先後順序,先定義子類的靜態全域變數,再定義父類的靜態全域變數。第二種不使用全域靜態變數,而是在Tcl::init()調用完成後再進行類的初始化,如上述代碼中的ClassInit(),此時應先初始化父類,再初始化子類。經過上述調整,即可得到正確的結果。