NS2初學筆記(三)之 最詳細講解ns2運行機制

 
rel="File-List" href="file:///C:%5CDOCUME%7E1%5COwner%5CLOCALS%7E1%5CTemp%5Cmsohtml1%5C01%5Cclip_filelist.xml">

至於第三點我解釋如下:

3,至於ns2的兩種語言的交互過程網上有幾篇帖子介紹的已經非常的詳細了,但還是因爲高手們把有一些東西省略了,從而對我這種初學者造成了一定的困難,爲了以後的“Beginner”們能夠更快的捋順關係,早日入門ns2,我還是要按我的方法說一下。ns2是這麼做的,每一個類都有一個Otcl類和一個c++類,每個需要交互的c++類都有一個鏈接類(該類包括一個方法,該方法實例化一個指定的類並且返回一個指向該實例的一個指針),該鏈接類通過其父類的構造方法在編譯階段註冊一個方法到TclLinkage(otcl類可以找到並且可以調用該方法),這樣在Otcl類初始化一個一個類的時候,調用之前註冊過的方法,就可以初始化一個c++類了,並且還會註冊一個使得Otcl類可以調用c++的類的方法——通過順序查找實現的。這樣以後在Otcl類就可以調用c++類中的方法了,說的有點亂,但是如果你看過一個例子,就會覺得我說的有道理了。

還是調用網上某位高手的一個例子吧,在這裏我就補充說明一下tclunknown機制。

static class ChannelClass : public TclClass {

public:

     ChannelClass() : TclClass("Channel") {}

     TclObject* create(int, const char*const*) {

         return (new Channel);

     }

} class_channel

 

ns instantiating the class_channel object,它會invoke ChannelClass:ChannelC

 

lass();

這會首先invoke TclClass:TclClass("Channel");

 

Tcl.cc文件中:

TclClass::TclClass(const char* classname) : class_(0), classname_(classname)

{

         #如果Otcl語言解釋器已存在的話:

         bind();

}

 

void TclClass::bind()

{

          #首先獲取Tcl

     Tcl& tcl = Tcl::instance();

 

          #Otcl環境中註冊該類名:Channel

          #並且該類的父類是SpliteObject

          #Note:SpliteObject存在於otcl環境中,C++中的TclObject相對應

          tcl.evalf("SplitObject register %s", classname_);

 

          #註冊了之後,爲這個類添加兩個命令:create-shadowdelete-shadow

          #Note:the implementation procedures of these two methods就是

          #TclClass::create_shadow()TclClass::delete_shadow().

          class_ = OTclGetClass(tcl.interp(), (char*)classname_);

          OTclAddIMethod(class_, "create-shadow",

                create_shadow, (ClientData)this, 0);

          OTclAddIMethod(class_, "delete-shadow",

                delete_shadow, (ClientData)this, 0);

          otcl_mappings();

}

 

然後當你在ns環境中敲入:new Channel

 

在文件tcl-object.tcl:

proc new { className args } {

     set o [SplitObject getid]

 

          #調用了該類的create函數,Channel:create()函數

          #也就是調用了SpliteObject:create()函數

         if [catch "$className create $o $args" msg] {

            if [string match "__FAILED_SHADOW_OBJECT_" $msg] {

               #

               # The shadow object failed to be allocated.

               #

               delete $o

               return ""

           }

            global errorInfo

            error "class $className: constructor failed: $msg" $errorInfo

     }

     return $o

}

 

但是SpliteObject並沒有implement create() 函數,

但是你別忘了在otcl環境中,SpliteObject類是這樣聲明的:Class SpliteObject

所以這會調用ClassCreate函數

 

Class instproc create() {

...

alloc();

init();

...

}

 

這就會調用SpliteObject instproc init()函數

SplitObject instproc init args {

     $self next

 

          #調用類的create-shadow函數

          #在這個例子中,就是調用了Channel instproc create_shadow函數

          #也就是調用了TclClass::create-shadow()函數,因爲在之前的bind()方法中有將這兩種操作對應起來。

     if [catch "$self create-shadow $args"] {

         error "__FAILED_SHADOW_OBJECT_" ""

     }

}

 

int TclClass::create_shadow(ClientData clientData, Tcl_Interp *interp,

                 int argc, char *argv[])

{

     TclClass* p = (TclClass*)clientData;

 

          #在這裏調用了ChannelClass::create()函數

          #也就是調用了C++環境中的:new Channel

          #到這裏爲止,otcl中的Channelshadow object就生成了

     TclObject* o = p->create(argc, argv);

     Tcl& tcl = Tcl::instance();

     if (o != 0) {

         o->name(argv[0]);

         tcl.enter(o);

         if (o->init(argc - 2, argv + 2) == TCL_ERROR) {

             tcl.remove(o);

             delete o;

             return (TCL_ERROR);

         }

         tcl.result(o->name());

 

                 #在這裏再次爲otcl中的類Channel添加兩個instproc:cmdinstvar

                 #其中cmd命令是meet the Tcl Unknown mechanism

(如果有同名的tcl方法就調用該方法,如果沒有該方法當然是unknown了。

                 #這樣的話,當你在ns腳本中輸入了一個該類未知的命令,

                 #Tclunknown機制就會調用該類的cmd命令

#/tclcl/tcl-object.tcl

SplitObject instproc unknown args {

    if [catch "$self cmd $args" ret] {

        set cls [$self info class]

        global errorInfo

        set savedInfo $errorInfo

        error "error when calling class $cls: $args" $savedInfo

    }

    return $ret

}

                #而這進一步的就會調用該類的shadow objectcommand()過程

                 #所以在實現類的C++部分時,你必須實現該類的Command()過程

                 #command()中實現所有的命令分發

         OTclAddPMethod(OTclGetObject(interp, argv[0]), "cmd",

                    dispatch_cmd, (ClientData)o, 0);

         OTclAddPMethod(OTclGetObject(interp, argv[0]), "instvar",

                    dispatch_instvar, (ClientData)o, 0);

         o->delay_bind_init_all();

         return (TCL_OK);

     } else {

         tcl.resultf("new failed while creating object of class %s",

                 p->classname_);

         return (TCL_ERROR);

     }

}

通過上面的例子可以瞭解到Otcl可以調用c++類中的方法,而c++中的類可不可以調用Otcl類中的方法呢,答案是可以的,是通過得到一個Tcl實例來實現的,具體請參考everything.pdf裏面有詳細的介紹(其實我總解的這些也是通過在總結一下學習該文檔的經驗而已,這個文檔真的可以稱得上是everything了,包括了ns2的一切內容,就是太長了)。
發佈了43 篇原創文章 · 獲贊 10 · 訪問量 15萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章