从一个实例看TCLCL的运行过程

来源:互联网 发布:电子数据交换应用 编辑:程序博客网 时间:2024/06/05 01:08
    Ns2使用了TCL/CL使TCL脚本得以控制C++代码的运行,因此理解它的运行过程就显示非常重要,下面给出的这个简单例子说明了这一过程。
C++部分的代码:
#include <math.h>
#include "tclcl.h"
extern "C" {
#include <otcl.h>
}
 
// 定义一个准备让TCL脚本调用的类,此类必须从TclObject继承
class CTestObject : public TclObject
{
private:
     int m_nCount;
 
public:
     CTestObject()
     {
         m_nCount = 0;
 
         // bind之后就可以在TCL脚本中访问这个类的成员变量了,
         // 对于没有使用bind的变量是无法通过脚本访问的。
         // 在此只展示一个简单的整数类型,如果是复杂数据则需要从TracedVar继承一个子类进行控制
         this->bind("Count", &m_nCount); 
     }
 
     virtual int init(int argc, const char*const* argv)
     {
         // 在脚本中进行实例化时将调用此函数
         printf("CTestObject::init called/n");
         m_nCount = 100;
         return (TCL_OK);
     }
     virtual int command(int argc, const char*const* argv)
     {
         // 当脚本中进行对象的函数调用时将使用此函数
         printf("CTestObject::command called/n");
         if(argc >= 2 && strcmp(argv[1], "GetCount") == 0)
         {
              char result[20];
              sprintf(result, "%d", m_nCount);
              Tcl::instance().result(result);
              return TCL_OK;
         }
         else
              return TclObject::command(argc, argv);
     }
 
};
 
// 定义一个TCL脚本中可以使用的类信息
class CTestClass : public TclClass
{
public:
     CTestClass()
         : TclClass("CTestClass")
     {
     }
 
     virtual TclObject* create(int argc, const char* const* argv)
     {
         // 创建对象时将调用此函数,如果CTestObject的构造函数需要参数也可以从这里取得
         printf("CTestClass::create called/n");
         return new CTestObject;
     }
};
 
// 务必定义这样一个变量,保证向TCL引擎注册类信息
static CTestClass _cls;
在上述代码中,最后一行定义了一个变量,CtestClass从TclClass继承而来,此时它将调用TclClass::TclClass(),将此类信息注册到Tcl的脚本引擎中。
下面再来看TCL脚本对此对象的调用方法:
 
# 在脚本中定义要操作的类的成员变量,如果不定义也可以正常使用这个类,但是在类的实例化时会生成一个警告。请注意在此之前已经不需要使用Class CTestClass这样的语句来定义类,因此本部分功能已经在C++中完成。
%CTestClass set Count {}
%
 
# 对此类进行实例化
%CTestClass cls
CTestClass::create called
CTestObject::init called
cls
%
从以上输出可以看出首先调用CTestClass::create函数,在此函数中创建了一个新对象,然后调用此对象的init方法。其实如果算上TCL脚本的执行过程应该是这样的:
1、 调用C++代码CTestClass::create创建一个新对象。
2、 查找TCL脚本是否为此类写了init函数,如果写了就调用它。
3、 如果在TCL脚本中没有找到init函数则在TCL脚本中查找这个类是否为成员变量定义了初始值,若有则将这些初始值赋给新对象中的成员变量,当然这个过程只会影响C++和TCL共用的变量。
4、 调用C++代码CTestObject::init
从以上过程可以看出如果希望在C++中改变共用变量的初始值,应该在init函数中完成,而不应该在构造函数中完成。
 
# 显示Count的初始值(在C++代码的init函数中赋的值)
%cls set Count
100
 
# 用脚本修改共用变量的值
%cls set Count 500
500
 
# 调用共用的函数显示C++中共用变量的值
%cls GetCount
CTestObject::command called
500
 
本文中的C++代码可以直接放在前述的clsh工程中运行。
原创粉丝点击