下面开始来看看是怎么通过OTcl来操纵C++对象的:
一、C++对象的创建
NS2采用的分裂对象模型,即每个C++的类都有一个Otcl类与之相对应。NS2中所有类的基类是TclObject,而Otcl中的基类则为 SplitObject。下面首先看一下SplitObject这个类的定义(~/tclcl.*/Tcl-object.tcl):
Class SplitObject
SplitObject set id 0
SplitObject instproc init args {
$self next
if [catch "$self create-shadow $args"] { //(1)调用create_shadow()
error "__FAILED_SHADOW_OBJECT_" ""
}
}
SplitObject instproc destroy {} {
$self delete-shadow
$self next
}
由于每一个Otcl对象的创建都要调用其init过程,因此所有继承于SplitObject的Otcl类的初始化最终都会调用到SplitObject的init()这个instproc。
从上面代码中可以看到,init()实际上是调用了一个叫create-shadow的函数,这个函数就是用来创建C++对象的,这在后面会分析到。
同时,SplitObject也重载了destroy()函数,调用了一个叫delete-shadow的方法,顾名思义,也就是销毁相应的C++对象。
注意:Otcl并不会像C++那样会自动调用父类的构造函数,而必须显示的进行调用,也就是上面的: $self next
在Otcl脚本中是通过new命令来创建一个Otcl对象,通过delete来销毁一个对象的。这两个命令在~/tclcl.*/Tcl-object.tcl中有定义:
#创建一个object
#调用该类的create函数
proc new { className args } {
set o [SplitObject getid]
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
}
#销毁一个object
proc delete o {
$o delete_tkvar
$o destroy
}
可以看到,new方法实际上是调用了类中的一个create函数来进行初始化,那么这个create函数究竟是怎么一回事呢?再回过头来仔细看看Otcl的语法:
"The create instproc provides a mechanism for classes to create other classes and objects"
原来create就是用来创建一个Otcl解释对象的,在对象创建时会调用其init()方法,最终就调用create-shadow来创建一个与之相对应的C++shadow对象。
那么问题又来了,create-shadow又是怎么创建C++对象?还有它又怎么知道要创建哪个C++类对应的对象的呢?接下来就来看看Otcl类和C++类是怎么关联起来的。在Otcl基类SplitObject中提供了一个名为register的方法:
// This routine invoked by TclClass::bind.
//注册类名
SplitObject proc register className {
set classes [split $className /]
set parent SplitObject
set path ""
set sep ""
foreach cl $classes {
set path $path$sep$cl
if ![$self is-class $path] {
Class $path -superclass $parent
}
set sep /
set parent $path
}
}
通过上面的代码可以看出,register的功能其实就是定义一个指定classname的Otcl类。
在这还得简单介绍一下NS2中的类命名规则。NS2是使用字符’/’来作为分割符以表示类之间的继承关系的。具体据个例子,如名为”Agent /TCP/Reno”的Otcl类,它就是继承于“Agent/TCP”类的;同理“Agent/TCP”则是继承于“Agent”类,而Agent类则 最后继承于基类SplitObject。知道了类的命名规则,上面的代码就很好理解了,它也就是根据提供的classname利用分隔符进行分割后创建相 应的派生类。其中-superclass就表明了类之间的继承关系。
那么又是谁来调用这个register方法进行Otcl类注册的呢?这时候就得把TclClass给介绍出来了,终于可以从Otcl脚本转向熟悉的 C++了~~。TclClass是个纯虚类,它封装了Otcl类的注册机制。废话少说,先看看这个类的定义(~/tclcl.*/tclcl.h)
class TclClass {
public:
static void init();
virtual ~TclClass();
protected:
TclClass(const char* classname);
virtual TclObject* create(int argc, const char*const*argv) = 0;
private:
static int create_shadow(ClientData clientData, Tcl_Interp *interp,
int argc, CONST84 char *argv[]);
static int delete_shadow(ClientData clientData, Tcl_Interp *interp,
int argc, CONST84 char *argv[]);
static int dispatch_cmd(ClientData clientData, Tcl_Interp *interp,
int argc, CONST84 char *argv[]);
static int dispatch_init(ClientData clientData, Tcl_Interp *interp,
int argc, char *argv[]);
static int dispatch_instvar(ClientData clientData, Tcl_Interp *interp,
int argc, CONST84 char *argv[]);
static TclClass* all_;
TclClass* next_;
protected:
virtual void otcl_mappings() { }
virtual void bind();
virtual int method(int argc, const char*const* argv);
void add_method(const char* name);
static int dispatch_method(ClientData, Tcl_Interp*, int ac, CONST84 char** av);
OTclClass* class_;
const char* classname_;
};
首先来分析一下它的构造函数TclClass::TclClass(const char* classname);
TclClass::TclClass(const char* classname) : class_(0), classname_(classname)
{
if (Tcl::instance().interp()!=NULL) {
// the interpreter already exists!
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;
}
}
嗯,看起来是非常的简单。。。在判断Otcl解释器存在之后就调用了一个名为bind的成员函数,现在再来看看这个bind函数的具体实现
void TclClass::bind()
{
Tcl& tcl = Tcl::instance();
//Register classname in OTCL
tcl.evalf("SplitObject register %s", classname_);
class_ = OTclGetClass(tcl.interp(), (char*)classname_);
//Add 2 method for this class
//create-shadow & delete-shadow
OTclAddIMethod(class_, "create-shadow",
create_shadow, (ClientData)this, 0);
OTclAddIMethod(class_, "delete-shadow",
delete_shadow, (ClientData)this, 0);
otcl_mappings();
}
这下就豁然开朗了,原来是bind函数调用SplitObject的register方法注册了一个名为classname_Otcl类,然后再在 该类中添加了两个方法:create-shadow和delete-shadow,这就是我们上面讲到的在创建和销毁Otcl对象是调用的两个方法,它们 分别和TclClass中的两个成员函数:create_shadow和delete_shadow绑定了起来。那么现在就来看看 create_shadow的部分实现(~/tclcl.*/)
int TclClass::create_shadow(ClientData clientData, Tcl_Interp *interp,
int argc, CONST84 char *argv[])
{
TclClass* p = (TclClass*)clientData;
TclObject* o = p->create(argc, argv);
/*以下代码省略…*/
}
从开头的代码可以看出,它其实是调用了纯虚函数virtual TclObject* create(int argc, const char*const*argv) = 0; 那么这个create函数究竟又是干什么的呢?接下来以TclClass的一个派生类AgentClass为例来说明,其定义如下(~/ns2.*/common/Agent.cc)
static class AgentClass : public TclClass {
public:
AgentClass() : TclClass("Agent") {}
TclObject* create(int, const char*const*) {
return (new Agent(PT_NTYPE));
}
} class_agent;
首先我们注意到了关键字static,说明AgentClass是一个静态类,也就是说当NS2刚开始初始化的时候,便会调用该类的构造函数,而构 造函数又做了什么工作呢?上面我们已经分析了,其实就是在Otcl中注册了一个名为Agent的Otcl解释类。当Otcl脚本调用new方法实例化这个 Agent类的时候,最终会调用到AgentClass的create函数,该create函数的实现很简单,就是实例化了一个C++的Agent对象, 并返回该对象的指针。至此Otcl对象终于和C++对象关联起来了。
相关推荐
对ns2中分裂模型的一点认识,总结自己学习ns2的经验。
里面包含九种常用的移动模型代码分析,可以直接使用。是c++编写生成场景文件在ns2中运行。
这是我在网上找的关于添加能量模型的过程,经过我实验,很有效。
利率曲线模型最简单的NS模型,是官方文件
与传统的NS2链路模型相比,该模型在不影响网络模拟真实性的前提下,不再在链路模型中维护分组缓存队列,并将部分离散事件采用直接计算来处理,以减少离散事件个数,降低模拟运行时间。实验表明,该模型在保证真实性...
用C++写的元胞自动机NS模型,可以在程序中对规则修改,得到新的模型。方面初学者的学习运用。
用于制作交通流NS模型的简单模型,对初学者有一定的借鉴意义
matlab实现利率期限结构静态估计的NS模型,内有具体说明
在圆形区域上,使用C-N方法求解NS-Voigt模型,NS-Voigt模型是在经典的NS模型上加了一个Voigt正则化项得到的
元胞自动机交通流模型,单车道及多车道的应用
交通流元胞自动机NS模型,可为新手所用。
元胞自动机的NS模型的C++代码实现 可用 结构清晰
该模型中包含了高速公路模型highway,车流模型model,车辆换道模型lane-change,车类vehicle等, 一个安装过程见: http://blog.csdn.net/barcodegun/article/details/6898193 请注意:由于版本不一样,环境不一样,...
NS 一二三道模型代码 MATLAB 代码
在ns2中实现nice丢包信道,ns2无线错误模型包括常用的GE信道,该软件包增加了nice丢包信道
NS模型拟合债券利率期限结构
一篇不错的论文,使用NS3仿真车联网。“highway mobility and vehicular ad-hoc networks in NS-3”。
交通流模型,改进ve模型等
该模型将Mesh模式的物理层和媒质接入控制层的必要功能分成相对独立的几个功能模块,每个模块都可以在NS2仿真中用面向对象的C 类实现其功能,具有很好的可扩展性。基于该模型,扩展了NS2,实现了Mesh模式的协调分布式...
元胞自动机 NaSch模型及其MATLAB代码