http://hi.baidu.com/jacktar11/blog/item/4b0f25ece4cbcf20adafd51b.html
所添加的新协议的C++文件中都会有一段代码 eg:
static class Mac802_16Class : public TclClass
{
public:
//构造函数Mac802_16Class()将Otcl中的类名Mac/802_16作为参数传给其父类TclClass的构造函数;
//要注意,这里实际上是创建了两个类:Mac和802_16,并且802_16是Mac的子类;
Mac802_16Class() : TclClass("Mac/802_16") {}
//而create方法则创建一个要与Otcl类对应的C++类的对象实例,然后返回;
TclObject* create(int, const char*const*)
{
return (new Mac802_16());
}
} class_mac802_16;
一个声明为static的类,在NS2初始化的时候会调用该类的构造函数,在此NS2调用了Mac802_16Class:Mac802_16Class(),这首先调用了TclClass("Mac/802_16")。我们接着翻看tclcl-1.17/Tcl.cc看TclClass()是如何工作的。
在Tcl.cc文件中:
TclClass::TclClass(const char* classname) : class_(0), classname_(classname)
{
if (Tcl::instance().interp()!=NULL) {
//如果Otcl语言解释器已存在的话,调用bind():
// this can happen only (?) if the class is created as part of a dynamic library
bind();
} else {
// the interpreter doesn't yet exist
// add this class to a linked list that is traversed when
// the interpreter is created
next_ = all_;
all_ = this;
}
}
往下找到bind():
void TclClass::bind()
{
//获取Tcl
Tcl& tcl = Tcl::instance();
//在Otcl环境中注册该类名:Mac802_16,其父类是SpliteObject
//需要注意的是:SpliteObject存在于otcl环境中,与C++中的TclObject相对应
tcl.evalf("SplitObject register %s", classname_);
//注册了之后,为这个类添加两个命令:create-shadow和delete-shadow,注意:这两个命令的执行程序实际上就是TclClass类的create_shadow()和TclClass::delete_shadow().
class_ = OTclGetClass(tcl.interp(), (char*)classname_);
OTclAddIMethod(class_, "create-shadow",
(Tcl_CmdProc *) create_shadow, (ClientData)this, 0);
OTclAddIMethod(class_, "delete-shadow",
(Tcl_CmdProc *) delete_shadow, (ClientData)this, 0);
otcl_mappings();
}
然后当我们在ns脚本中:new Mac802_16时,在tclcl-1.17/tcl-object.tcl中:
proc new { className args } {
set o [SplitObject getid]
//调用了该类的create函数,即Mac802_16: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并没有实现create()函数!如何解决呢?我们往上找找看SpliteObject类是如何声明的:Class SpliteObject,原来这实际上是调用了Class的Create函数:
Class instproc create() {
...
alloc();
init();
...
}
这就会调用SpliteObject instproc init()函数
SplitObject instproc init args {
$self next
//调用类的create-shadow函数,在这个例子中,就是调用了Mac802_16 instproc create_shadow函数
//如前面所讲,也就是调用了TclClass::create-shadow()函数
if [catch "$self create-shadow $args"] {
error "__FAILED_SHADOW_OBJECT_" ""
}
}
我们继续翻看TclClass的create_shadow()函数,看它做了些什么:
int TclClass::create_shadow(ClientData clientData, Tcl_Interp *interp, int argc, char *argv[])
{
TclClass* p = (TclClass*)clientData;
//在这里调用了Mac802_16Class::create()函数,也就是调用了C++环境中的:new Mac802_16,到这里为止,otcl中的Mac802_16类对应的shadow object(影象对象)就生成了
TclObject* o = p->create(argc, argv);
Tcl& tcl = Tcl::instance();
if (o != 0) {
o->name(argv[0]);
tcl.enter(o);
//在这里再次为otcl中的类Mac802_16添加两个命令:cmd和instvar,其中cmd命令是meet the Tcl Unknown mechanism——Tcl的unknown机制,这样一来,当你在ns脚本中输入了一个该类未知的命令,Tcl的unknown机制就会调用该类的cmd命令,具体的过程可以翻看NS手册的相应部分,有比较详细的说明;
//而cmd()命令激活影像对象的command()方法,并将cmd()的参数以向量的形式传递给command()方法,因此在实现某类的C++部分时,你必须实现该类的Command()过程,仔细看看NS2中的大部分类,是不是都有一个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);
}
}
command()