来源:互联网 发布:皮尔鲨鱼网络授权书 编辑:程序博客网 时间:2024/06/01 23:31

 2.2.5 注意映射机制(shadowing mechanisms)只有当用户通过解释器创建新的TclObject的时候才有效。但如果程序员只是单向创建编译TclObject,这个机制将会失效。因此,程序员不要直接用C++的新方法来创建编译对象。
    TclObject的撤销 delete操作将同时撤销解释对象和相当的shadow对象,
    delete过程来移除默认的链表计划(list scheduler),同时在原处实例化一个替代的计划。
    Simulator instproc use-scheduler type {
    $self instvar scheduler_
    delete scheduler_ # 首先删除已有的list scheduler

    set scheduler_ [new Scheduler/$type]
    }
    同构造函数一样,对象的析构函数必须明确地调用其父类的析构函数,作为该析构函数的声明的最后部分。TclObject的析构数将调用delete-shadow实例过程,从而依次调用对应的编译方法来撤销shadow对象。解释对象将由解释器自身撤销。


    2.3 变量绑定(Variable Bindings)

    大多数情况下,访问编译成员变量只能通过编译代码,同样地,访问解释成员变量只能通过解释代码;但是,在它们之建立一个双向绑定是有可能的,这就使得解释成员变量和编译成员变量都可以访问同样的数据,而且它们中的任何一个变值的变化均可以使另一个相应地变为同样的值。

    这种绑定是对象在实例化的时候,由编译对象的构造函数建立起来的;它也作为一个实例变量被解释对象自动访问。ns持五种不同的数据类型:实型(reals) 带宽变量 ,  (bandwidth valued variables) 时间变量,(time valued variables),整型(integers),布尔型(booleans)。

   如下例:ASRMAgent类(这是个编译类) 的构造函数:

    SRMAgent::ASRMAgent() {
        bind("pdistance_", &pdistance_);
/* 实变量 */
        bind("requestor_", &requestor_);/* 整型变量 */
        bind_time("lastSent_", &lastSessSent_);/* 时间型变量 */
        bind_bw("ctrlLimit_", &ctrlBWLimit_);/* 带宽型变量 */
        bind_bool("running_", &running_);/* 布尔型变量 */
        }

        上述所有的函数都需要两个参数:OTcl变量的名字和绑定的相应的编译成员变量的地址。通常来说,这
些绑定是在由构造函数建立的,但是也可以由其它方式完成。如可以通过InstVar类来完成。

    每个被绑定的变量在对象创建的初始化时候,自动地被赋予默认值。这些默认值被指定为解释类变量。这个初始化过程是在init-instvar{}中被执行的,而这又是被Instvar类中的方法调用的。init-instvar{}检查(check)解释对象的类和该对象所有的父类,从而找到定义变量的第一个类。它利用那个类中的变量值来初始化这个对象。大部分绑定的初始化值定义在~ns/tcl/lib/ns-default.tcl中。

     需要注意的是,实际的绑定过程是在InstVar类的对象实例化过程中完成的。InstVar类中的每个对象绑定一个编译成员变量和一个解释成员变量。一个TclObject存储一个InstVar对象及相应的成员变量的链表。这个链表头被存储在TclObject的成员变量instvar_里。

    2.4 变量跟踪(Variable Tracing)

    除变量绑定以外,TclObject同时也支持对C++和Tcl实例变量的跟踪。一个被跟踪的变量既可以在C++又可以在Tcl中建和配置。如果在Tcl层建立变量跟踪,变量必须在Tcl下是可视的,这也就意味着它必须是一个绑定的C++/Tcl,或者是一个纯Tcl实例变量。

   如果一个TclObject去跟踪变量,它必须扩展C++中的trace方法,那本来是定义在TclObject中的一个虚函数。Trace类只实现一个简单的trace方法,因此,它可以作为一个一般的变量跟踪函数。

   下面是一个在Tcl中设置跟踪变量的简单的例子:

    # /$tcp跟踪它自己的变量cwnd_
    /$tcp trace cwnd_
    # /$tcp中的变量ssthresh_ 被一个一般的/$tracer跟踪
    set tracer [new Trace/Var]
    /$tcp trace ssthresh_ /$tracer

    2.5  command方法: 定义与调用(Invocation)

    对于每个建立的TclObject,ns都将建立cmd{}实例过程,作为一个挂钩(hook)通过编译的shadow对象来执行一些方法。cmd{}过程自动调用shadow对象的command()方法,并将command()方法的参数以矢量的形式传递给cmd{}过程。用户可以通过下面两种方式中的一种来调用cmd{}:通过显式地调用过程,指定所需的操作作为第一个参数,或者隐式地调用,就好象有一个同名的实例过程作为所需的操作。模拟脚本大多都采用后者。

    3 TclClass类

    这个编译类(class TclClass)是一个纯虚类。从这个基类派生的类提供两种功能:构建与编译类层次镜像的解释类层次;提供实例化新TclObjects的方法。每一个这样的派生类与编译类层次中的特定的编译类相互关联,同时可以实例化这个关联类的新对象。

   static class RenoTcpClass: public TclClass {
    public:
    RenoTcpClass() : TclClass("Agent/TCP/Reno") {}
    TclObject* create(int argc, const char*const* argv) {
    return (new RenoTcpAgent());
    }
    } class_reno;

    当ns初次启动时,执行对象的构造函数。
    这个构造函数以解释类名为其参数,调用TclClass的构造函数。
    TclClass的构造函数存储这个类的名字,并把这个对象插入到TclClass对象的链表中。
    在模拟器的初始化过程中,Tcl_AppInit(void)调用TclClass::bind(void)。
    对TclClass对象链表中的每一个对象,bind()调用register{},以解释器名作为其参数。
    register{}建立层次类,建立那些必需,却还创建的类。
    最后,bind()为新类定义create-shadow和delete-shadow两个实例过程。

    4 TclCommand类

    该类(TclCommand类)仅仅为ns提供向解释器输出简单命令的机制,然后由解释器在全局范围内执行。

    5 EmbeddedTcl类

    ns允许对编译代码或者解释代码的功能扩展,这个扩展代码将在初始化的时候被执行。 

    6 InstVar类

    该类定义了将编译的shadow对象中的C++成员变量绑定到与之对应的解释对象中的Tcl实例变量上的方法与机制。这种绑定的建立可以使变量的值在任何时候都能从解释器或编译代码中设置和访问。