NS2初学笔记(三)之 最详细讲解ns2运行机制

 

至于第三点我解释如下:

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 的一切内容,就是太长了)。

你可能感兴趣的:(NS2初学笔记(三)之 最详细讲解ns2运行机制)