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++類中的方法了,說的有點亂,但是如果你看過一個例子,就會覺得我說的有道理了。
還是調用網上某位高手的一個例子吧,在這裏我就補充說明一下tcl的unknown機制。
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-shadow和delete-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
所以這會調用Class的Create函數
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中的Channel的shadow 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:cmd和instvar
#其中cmd命令是meet the Tcl Unknown mechanism
(如果有同名的tcl方法就調用該方法,如果沒有該方法當然是unknown了。
#這樣的話,當你在ns腳本中輸入了一個該類未知的命令,
#Tcl的unknown機制就會調用該類的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 object的command()過程
#所以在實現類的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的一切內容,就是太長了)。