OTCL用户手册

来源:互联网 发布:信息技术程序编程 编辑:程序博客网 时间:2024/06/06 15:35

OTCL用户手册

本手册主要目标为帮助你快速上手OTCL,我们假设你已经熟悉面向对象编程的概念.

 

C++的比较

对于C++的程序员来说,他们可能对OTCL里面的面向对象编程概念不太习惯.其中的差别如下:

1,C++中只能存在单个类定义来比较,OTCL可以有多个定义.每个成员函数的定义(用关键词instproc)都给类增加一个方法.每个变量的定义(用关键词set或函数体内使用instvar)都给对象增加一个变量.

2,C++中的构造函数不同,OTCL使用一个叫做initinstproc.相对于C++中的析构函数,otcl使用一个名字为destroyinstproc.而且OTCL里的构造函数和析构函数并不自动和基类结合,需要用next显式调用.

3,C++不同的是OTCL方法往往通过对象进行调用(???).函数体内的关键词self相当于C++中的this指针.而且,OTCL方法常常是虚拟函数(virtual)

4,C++中调用被继承的方法不同,OTCL通过施用next来调用.next将通过查找继承关系来找到被继承的方法和变量.

5,避免在OTCL中施用static方法和变量,因为OTCL中没有对应的关键词.请通过在类对象内部共享变量,并且通过使用关键词class来访问.这种行为会被继承.如果一个不需要被继承的话,使用proc而非instproc关键词.

 

OTCL编程

假设我们在程序中需要使用大量的面包,我们可以构造一个面包类

% Class Bagel

Bagel

第一行定义一个面包的类,%为提示符,第二行为第一行语句的输出,即类名

我们还可以通过info方法来跟踪类,比如:

% Bagel abagel

abagel

% abagel info class

Bagel      //显示该变量的类名

% Bagel info instances

abagel    //显示该类的继承关系

当然,现在的面包类不能做太多的事情,首先,它应该记录自己是否已经被烤过.所以我们通过关键词set来创建一个变量记录这个状态.在类里面所由的变量,都有着C++中的public属性,同样,info方法可以帮助我们跟踪类.

% abagel set toasted 0

0

% abagel info vars//跟踪类中的变量

toasted

% abagel set toasted

0

然而,对于面包来说,刚开始做出的面包都是未曾烤熟的,所以我们需要加入一个init的构造函数来实现它.一般来说,如果你需要新创建的变量能被初始化,你需要实现这个init函数

% Bagel instproc init {args} {

 $self set  toasted 0 

 eval $self next $args

}

% Bagel bagel2

bagel2

% bagel2 info vars

toasted

% bagel2 set toasted

0

这里有许多细节值得探讨.作为创建对象的一部分,系统在对象被分配后将立刻调用init.在上面的代码中,initproc方法给类Bagel增加了一个叫做init的方法,所以系统将在新的Bagel对象创建时找到它并调用它.

init函数内部,同样有一些细节问题.调用next方法是init函数的常有动作,我们将在后面讨论它.其中self变量包含程序运行时对象的名字,在上一段代码中就将代表bage2,它相当于C++中的this指针.这里还有两个关键词你可能会感兴趣,procclass,其中proc关键词用来定义成员函数,但该函数不能被子类继承.

 

现在我们的面包类能够表示它是否已经进过烘烤房,除了在最前面尚未定义init方法的时候定义的那个面包abagel,所以我们首先将它销毁,然后重新开始:

% Bagel info instances

bagel2 abagel

% abagel destroy

% Bagel info instances

bagel2

% Bagel abagel

abagel

现在我们可以给面包定义一个方法以便我们能将其送入烘烤房.在这里我们施用关键词instproc,以便该方法能被子类继承(所由面包都需要烘烤操作).定义的格式和TCL差不多,都有参数列表和函数体.

% Bagel instproc toast {} {

 $self instvar  toasted

 incr toasted

 if {$toasted>1} then {

   error "something's burning!"

 }

 return {}

}

% Bagel info instprocs//查看能被继承的方法

init toast

toast方法中除了设置toasted变量外,该方法还展示了instvar方法的调用.该方法用来声明变量,并将其带入当前的作用域.因此在前面通过set初始化的变量toasted,能够在当前的作用域中通过局部变量toasted来操作.

我们可以和使用infodestory相类似的方法来烘烤面包,这也说明在系统函数和用户自定义的函数之间,并煤油什么区别.

% abagel toast

% abagel toast

something's burning!

现在面包已经实现了,但为了外观的好看,我们还研制出了一种陀螺面包,对此,我们将其作为一个独立的类来实现:

% Class SpreadableBagel -superclass Bagel

SpreadableBagel

% SpreadableBagel info superclass

Bagel

% SpreadableBagel info heritage

Bagel Object

在该代码中,首先定义一个继承自Bagel类的陀螺面包 SpreadableBagel ,这通过关键词superclass来定义,而且通过使用info查看它的继承关系可以得知,该类继承自两个类,BagelObject,奇怪吗?哪里来的Object?原来在OTCL,所由的对象都默认继承自Obejct,所以Bagel直接从Object继承,然后 SpreadableBagel 再继承自Bagel.

-superclass还需要更多的解释.First,you might be wondering why all methods except create are called byusing their name after the object name, as the second argument. Theanswer is that create is called as part of the system's unknownmechanism if no other method can be found. This is done to provide thefamiliar widget-like creation syntax, but you may call createexplicitly if you prefer.

 

Second,as part of object initialization, each pair of arguments is interpretedas a (dash-preceded) procedure name to invoke on the object with acorresponding argument. This initialization functionality is providedby the init instproc on the Object class, and is why the Bagel initinstproc calls next. The following two code snippets are equivalent(except in terms of return value). The shorthand it what you use mostof the time, the longhand explains the operation of the shorthand.

 

   % Class SpreadableBagel

   SpreadableBagel

   % SpreadableBagel superclass Bagel

 

   % Class create SpreadableBagel

   SpreadableBagel

   % SpreadableBagel superclass Bagel

 

   % Class SpreadableBagel -superclass Bagel

   SpreadableBagel

一旦你明白了这个关系(我没明白),那么你就能意识到对象的创建没什么特别的.例如你可以增加其它的选项比如:

   % Bagel instproc size {n} {

     $self set bites $n

   }

   % SpreadableBagel abagel -size 12

   abagel

   % abagel set bites

   12

对于SpreadableBagel我们需要增加一些特有的方法和属性,这样我们就需要init方法,比如:

% SpreadableBagel instproc init {args} {

 $self set  toppings {}

 eval $self next $args

}

% SpreadableBagel instproc spread {args} {

 $self instvar toppings

 set toppings [concat $toppings $args]

 return $toppings

}

现在init函数里的next可以解释清楚了,由于SpreadableBagel同样也是面包(Bagel ),所以我们也需要设置SpreadableBagel在刚做出的时候尚未被烘烤,所以我们调用next来回溯继承树使得父类的构造函数也被调用.

在这个例子里,Bagel类的init函数将会被调用,eval是用来整理参数序列中的参数.同样,Bagel类中的init被调用的时候,还将调用Object类的init函数.

 

现在让我们给面包类增加一个品尝动作:

% Bagel instproc taste {} {

 $self instvar toasted

 if {$toasted == 0} then {

   return raw!

 } elseif {$toasted == 1} then {

   return toasty

 } else {

   return burnt!

 }

}

 

% SpreadableBagel instproc taste {} {

 $self instvar toppings

 set t [$self next]

 foreach i $toppings {

   lappend t $i

 }

 return $t

}

 

% SpreadableBagel abagel

abagel

% abagel toast

% abagel spread jam

jam

% abagel taste

toasty jam

当然,我们还需要给面包加上其它许多的东西,比如洋葱,罂粟,芝麻等,我们可以通过使用内部变量来代表这一切,但这并不是最佳的解决方案.我们可以通过构造继承类来实现:

% Class Sesame

Sesame

% Sesame instproc taste {} {

 concat [$self next] "sesame"

}

% Class Onion

Onion

% Onion instproc taste {} {

 concat [$self next] "onion"

}

% Class Poppy

Poppy

% Poppy instproc taste {} {

 concat [$self next] "poppy"

}

这看样子没起什么作用,:

% Class SesameOnionBagel -superclass {Sesame Onion SpreadableBagel}

SesameOnionBagel

% SesameOnionBagel abagel -spread butter

% abagel taste

raw! butter onion sesame

对于多继承,由系统来决定一个线性的继承序列,可以通过info方法来显示,比如:

% SesameOnionBagel info heritage

Sesame Onion SpreadableBagel Bagel Object

next将根据这个序列来依次调用.

 

我们还可以把我们的混和类和其它类结合,比如:

% Class Chips

Chips

% Chips instproc taste {} {

 return "crunchy"

}

% Class OnionChips -superclass {Onion Chips}

OnionChips

% OnionChips abag

abag

% abag taste

crunchy onion

其它参考文献:

   * There is support for autoloading libraries of classes and methods. See OTcl Autoloading for details.

   *There is a C level interface (as defined by otcl.h) that allows newobjects and classes to be created, and methods implemented in C to beadded to objects. See OTcl C API for details.

   *Classes are special kinds of objects, and have all of the properties ofregular objects. Thus classes are a convenient repository forprocedures and data that are shared by their instances. And thebehavior of classes may be controlled by the standard inheritancemechanisms and the class Class.

   *Methods called procs can be added to individual object, for sole use bythat object. This allows particular objects to be hand-crafted, perhapsstoring their associated procedures and data.

   *User defined methods are treated in the same way as system providedmethods (such as set and info). You can use the standard inheritancemechanisms to provide your own implementation in place of a systemmethod.

·                     Thereare several other system methods that haven't been described. arraygives information on array instance variables, unset removes instancevariables, there are further info options, and so forth.

 

 

·                     Objects in Otcl:http://bmrc.berkeley.edu/research/cmt/cmtdoc/otcl/object.html

·                     Classes in Otcl:http://bmrc.berkeley.edu/research/cmt/cmtdoc/otcl/class.html

·                     C API:http://bmrc.berkeley.edu/research/cmt/cmtdoc/otcl/capi.html

·                     OTcl Autoloading :http://bmrc.berkeley.edu/research/cmt/cmtdoc/otcl/autoload.html

0 0